1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-15 09:34:18 +02:00

update stb_vorbis to the latest version

This commit is contained in:
XProger
2018-05-09 20:39:11 +03:00
parent 6aa55dcd13
commit 42eab0cea2

View File

@@ -1,20 +1,15 @@
// Ogg Vorbis audio decoder - v1.09 - public domain // Ogg Vorbis audio decoder - v1.14 - public domain
// http://nothings.org/stb_vorbis/ // http://nothings.org/stb_vorbis/
// //
// Original version written by Sean Barrett in 2007. // Original version written by Sean Barrett in 2007.
// //
// Originally sponsored by RAD Game Tools. Seeking sponsored // Originally sponsored by RAD Game Tools. Seeking implementation
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software, // sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker,
// Aras Pranckevicius, and Sean Barrett. // Elias Software, Aras Pranckevicius, and Sean Barrett.
// //
// LICENSE // LICENSE
// //
// This software is dual-licensed to the public domain and under the following // See end of file for license information.
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// No warranty for any purpose is expressed or implied by the author (nor
// by RAD Game Tools). Report bugs and send enhancements to the author.
// //
// Limitations: // Limitations:
// //
@@ -34,21 +29,27 @@
// Bernhard Wodo Evan Balster alxprd@github // Bernhard Wodo Evan Balster alxprd@github
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot // Tom Beaumont Ingo Leitgeb Nicolas Guillemot
// Phillip Bennefall Rohit Thiago Goulart // Phillip Bennefall Rohit Thiago Goulart
// manxorist@github saga musix // manxorist@github saga musix github:infatum
// Timur Gagiev
// //
// Partial history: // Partial history:
// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version // 1.14 - 2018-02-11 - delete bogus dealloca usage
// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame // 1.13 - 2018-01-29 - fix truncation of last frame (hopefully)
// 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const // 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
// 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) // 1.11 - 2017-07-23 - fix MinGW compilation
// 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory
// 1.09 - 2016-04-04 - back out 'truncation of last frame' fix from previous version
// 1.08 - 2016-04-02 - warnings; setup memory leaks; truncation of last frame
// 1.07 - 2015-01-16 - fixes for crashes on invalid files; warning fixes; const
// 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson)
// some crash fixes when out of memory or with corrupt files // some crash fixes when out of memory or with corrupt files
// fix some inappropriately signed shifts // fix some inappropriately signed shifts
// 1.05 - 2015/04/19 - don't define __forceinline if it's redundant // 1.05 - 2015-04-19 - don't define __forceinline if it's redundant
// 1.04 - 2014/08/27 - fix missing const-correct case in API // 1.04 - 2014-08-27 - fix missing const-correct case in API
// 1.03 - 2014/08/07 - warning fixes // 1.03 - 2014-08-07 - warning fixes
// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows // 1.02 - 2014-07-09 - declare qsort comparison as explicitly _cdecl in Windows
// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct) // 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float (interleaved was correct)
// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel; // 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
// (API change) report sample rate for decode-full-file funcs // (API change) report sample rate for decode-full-file funcs
// //
// See end of file for full version history. // See end of file for full version history.
@@ -275,7 +276,7 @@ extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
// do not need to seek to EXACTLY the target sample when using get_samples_*, // do not need to seek to EXACTLY the target sample when using get_samples_*,
// you can also use seek_frame(). // you can also use seek_frame().
extern void stb_vorbis_seek_start(stb_vorbis *f); extern int stb_vorbis_seek_start(stb_vorbis *f);
// this function is equivalent to stb_vorbis_seek(f,0) // this function is equivalent to stb_vorbis_seek(f,0)
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f); extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
@@ -555,7 +556,7 @@ enum STBVorbisError
#include <math.h> #include <math.h>
// find definition of alloca if it's not in stdlib.h: // find definition of alloca if it's not in stdlib.h:
#ifdef _MSC_VER #if defined(_MSC_VER) || defined(__MINGW32__)
#include <malloc.h> #include <malloc.h>
#endif #endif
#if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__)
@@ -580,6 +581,7 @@ enum STBVorbisError
#undef __forceinline #undef __forceinline
#endif #endif
#define __forceinline #define __forceinline
#define alloca __builtin_alloca
#elif !defined(_MSC_VER) #elif !defined(_MSC_VER)
#if __GNUC__ #if __GNUC__
#define __forceinline inline #define __forceinline inline
@@ -882,11 +884,7 @@ static int error(vorb *f, enum STBVorbisError e)
#define array_size_required(count,size) (count*(sizeof(void *)+(size))) #define array_size_required(count,size) (count*(sizeof(void *)+(size)))
#define temp_alloc(f,size) setup_temp_malloc(f,size)//(f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size)) #define temp_alloc(f,size) setup_temp_malloc(f,size)//(f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size))
#ifdef dealloca
#define temp_free(f,p) (f->alloc.alloc_buffer ? 0 : dealloca(size))
#else
#define temp_free(f,p) 0 #define temp_free(f,p) 0
#endif
#define temp_alloc_save(f) ((f)->temp_offset) #define temp_alloc_save(f) ((f)->temp_offset)
#define temp_alloc_restore(f,p) ((f)->temp_offset = (p)) #define temp_alloc_restore(f,p) ((f)->temp_offset = (p))
@@ -981,17 +979,18 @@ static int ilog(int32 n)
{ {
static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 }; static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 };
if (n < 0) return 0; // signed n returns 0
// 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29) // 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29)
if (n < (1 << 14)) if (n < (1 << 14))
if (n < (1 << 4)) return 0 + log2_4[n ]; if (n < (1 << 4)) return 0 + log2_4[n ];
else if (n < (1 << 9)) return 5 + log2_4[n >> 5]; else if (n < (1 << 9)) return 5 + log2_4[n >> 5];
else return 10 + log2_4[n >> 10]; else return 10 + log2_4[n >> 10];
else if (n < (1 << 24)) else if (n < (1 << 24))
if (n < (1 << 19)) return 15 + log2_4[n >> 15]; if (n < (1 << 19)) return 15 + log2_4[n >> 15];
else return 20 + log2_4[n >> 20]; else return 20 + log2_4[n >> 20];
else if (n < (1 << 29)) return 25 + log2_4[n >> 25]; else if (n < (1 << 29)) return 25 + log2_4[n >> 25];
else if (n < (1 << 31)) return 30 + log2_4[n >> 30]; else return 30 + log2_4[n >> 30];
else return 0; // signed n returns 0
} }
#ifndef M_PI #ifndef M_PI
@@ -1200,7 +1199,6 @@ static int vorbis_validate(uint8 *data)
// called from setup only, once per code book // called from setup only, once per code book
// (formula implied by specification) // (formula implied by specification)
/*
static int lookup1_values(int entries, int dim) static int lookup1_values(int entries, int dim)
{ {
int r = (int) floor(exp((float) log((float) entries) / dim)); int r = (int) floor(exp((float) log((float) entries) / dim));
@@ -1210,16 +1208,6 @@ static int lookup1_values(int entries, int dim)
assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above
return r; return r;
} }
*/
static int lookup1_values(int a, int b)
{
int r = 0, p = 0;
do {
r++;
p = (int)pow(r, b);
} while (p <= a);
return r - 1;
}
#ifdef _PSP #ifdef _PSP
// pspmath.h // pspmath.h
@@ -1340,13 +1328,13 @@ static void neighbors(uint16 *x, int n, int *plow, int *phigh)
// this has been repurposed so y is now the original index instead of y // this has been repurposed so y is now the original index instead of y
typedef struct typedef struct
{ {
uint16 x,y; uint16 x,id;
} Point; } stbv__floor_ordering;
static int STBV_CDECL point_compare(const void *p, const void *q) static int STBV_CDECL point_compare(const void *p, const void *q)
{ {
Point *a = (Point *) p; stbv__floor_ordering *a = (stbv__floor_ordering *) p;
Point *b = (Point *) q; stbv__floor_ordering *b = (stbv__floor_ordering *) q;
return a->x < b->x ? -1 : a->x > b->x; return a->x < b->x ? -1 : a->x > b->x;
} }
@@ -2114,6 +2102,8 @@ static int residue_decode(vorb *f, Codebook *book, float *target, int offset, in
return TRUE; return TRUE;
} }
// n is 1/2 of the blocksize --
// specification: "Correct per-vector decode length is [n]/2"
static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode)
{ {
int i,j,pass; int i,j,pass;
@@ -2121,7 +2111,10 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int rtype = f->residue_types[rn]; int rtype = f->residue_types[rn];
int c = r->classbook; int c = r->classbook;
int classwords = f->codebooks[c].dimensions; int classwords = f->codebooks[c].dimensions;
int n_read = r->end - r->begin; unsigned int actual_size = rtype == 2 ? n*2 : n;
unsigned int limit_r_begin = (r->begin < actual_size ? r->begin : actual_size);
unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size);
int n_read = limit_r_end - limit_r_begin;
int part_read = n_read / r->part_size; int part_read = n_read / r->part_size;
int temp_alloc_point = temp_alloc_save(f); int temp_alloc_point = temp_alloc_save(f);
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
@@ -3463,7 +3456,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->last_seg_which == f->end_seg_with_known_loc) { if (f->last_seg_which == f->end_seg_with_known_loc) {
// if we have a valid current loc, and this is final: // if we have a valid current loc, and this is final:
if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) {
uint32 current_end = f->known_loc_for_packet - (n-right_end); uint32 current_end = f->known_loc_for_packet;
// then let's infer the size of the (probably) short final frame // then let's infer the size of the (probably) short final frame
if (current_end < f->current_loc + (right_end-left_start)) { if (current_end < f->current_loc + (right_end-left_start)) {
if (current_end < f->current_loc) { if (current_end < f->current_loc) {
@@ -3472,7 +3465,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
} else { } else {
*len = current_end - f->current_loc; *len = current_end - f->current_loc;
} }
*len += left_start; *len += left_start; // this doesn't seem right, but has no ill effect on my test files
if (*len > right_end) *len = right_end; // this should never happen if (*len > right_end) *len = right_end; // this should never happen
f->current_loc += *len; f->current_loc += *len;
return TRUE; return TRUE;
@@ -3555,11 +3548,13 @@ static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right)
return right - left; return right - left;
} }
static void vorbis_pump_first_frame(stb_vorbis *f) static int vorbis_pump_first_frame(stb_vorbis *f)
{ {
int len, right, left; int len, right, left, res;
if (vorbis_decode_packet(f, &len, &left, &right)) res = vorbis_decode_packet(f, &len, &left, &right);
if (res)
vorbis_finish_frame(f, len, left, right); vorbis_finish_frame(f, len, left, right);
return res;
} }
#ifndef STB_VORBIS_NO_PUSHDATA_API #ifndef STB_VORBIS_NO_PUSHDATA_API
@@ -3942,7 +3937,7 @@ static int start_decoder(vorb *f)
g->book_list[j] = get_bits(f,8); g->book_list[j] = get_bits(f,8);
return error(f, VORBIS_feature_not_supported); return error(f, VORBIS_feature_not_supported);
} else { } else {
Point p[31*8+2]; stbv__floor_ordering p[31*8+2];
Floor1 *g = &f->floor_config[i].floor1; Floor1 *g = &f->floor_config[i].floor1;
int max_class = -1; int max_class = -1;
g->partitions = get_bits(f, 5); g->partitions = get_bits(f, 5);
@@ -3978,11 +3973,11 @@ static int start_decoder(vorb *f)
// precompute the sorting // precompute the sorting
for (j=0; j < g->values; ++j) { for (j=0; j < g->values; ++j) {
p[j].x = g->Xlist[j]; p[j].x = g->Xlist[j];
p[j].y = j; p[j].id = j;
} }
qsort(p, g->values, sizeof(p[0]), point_compare); qsort(p, g->values, sizeof(p[0]), point_compare);
for (j=0; j < g->values; ++j) for (j=0; j < g->values; ++j)
g->sorted_order[j] = (uint8) p[j].y; g->sorted_order[j] = (uint8) p[j].id;
// precompute the neighbors // precompute the neighbors
for (j=2; j < g->values; ++j) { for (j=2; j < g->values; ++j) {
int low,hi; int low,hi;
@@ -4148,7 +4143,10 @@ static int start_decoder(vorb *f)
int i,max_part_read=0; int i,max_part_read=0;
for (i=0; i < f->residue_count; ++i) { for (i=0; i < f->residue_count; ++i) {
Residue *r = f->residue_config + i; Residue *r = f->residue_config + i;
int n_read = r->end - r->begin; unsigned int actual_size = f->blocksize_1 / 2;
unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size;
unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size;
int n_read = limit_r_end - limit_r_begin;
int part_read = n_read / r->part_size; int part_read = n_read / r->part_size;
if (part_read > max_part_read) if (part_read > max_part_read)
max_part_read = part_read; max_part_read = part_read;
@@ -4159,6 +4157,8 @@ static int start_decoder(vorb *f)
classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *));
#endif #endif
// maximum reasonable partition size is f->blocksize_1
f->temp_memory_required = classify_mem; f->temp_memory_required = classify_mem;
if (imdct_mem > f->temp_memory_required) if (imdct_mem > f->temp_memory_required)
f->temp_memory_required = imdct_mem; f->temp_memory_required = imdct_mem;
@@ -4687,8 +4687,9 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
// starting from the start is handled differently // starting from the start is handled differently
if (sample_number <= left.last_decoded_sample) { if (sample_number <= left.last_decoded_sample) {
stb_vorbis_seek_start(f); if (stb_vorbis_seek_start(f))
return 1; return 1;
return 0;
} }
while (left.page_end != right.page_start) { while (left.page_end != right.page_start) {
@@ -4789,7 +4790,10 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
skip(f, f->segments[i]); skip(f, f->segments[i]);
// start decoding (optimizable - this frame is generally discarded) // start decoding (optimizable - this frame is generally discarded)
vorbis_pump_first_frame(f); if (!vorbis_pump_first_frame(f))
return 0;
if (f->current_loc > sample_number)
return error(f, VORBIS_seek_failed);
return 1; return 1;
error: error:
@@ -4880,14 +4884,14 @@ int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number)
return 1; return 1;
} }
void stb_vorbis_seek_start(stb_vorbis *f) int stb_vorbis_seek_start(stb_vorbis *f)
{ {
if (IS_PUSH_MODE(f)) { error(f, VORBIS_invalid_api_mixing); return; } if (IS_PUSH_MODE(f)) { return error(f, VORBIS_invalid_api_mixing); }
set_file_offset(f, f->first_audio_page_offset); set_file_offset(f, f->first_audio_page_offset);
f->previous_length = 0; f->previous_length = 0;
f->first_decode = TRUE; f->first_decode = TRUE;
f->next_seg = -1; f->next_seg = -1;
vorbis_pump_first_frame(f); return vorbis_pump_first_frame(f);
} }
unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f)
@@ -5052,6 +5056,7 @@ stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *err
if (f) { if (f) {
*f = p; *f = p;
vorbis_pump_first_frame(f); vorbis_pump_first_frame(f);
if (error) *error = VORBIS__no_error;
return f; return f;
} }
} }
@@ -5417,19 +5422,22 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
#endif // STB_VORBIS_NO_PULLDATA_API #endif // STB_VORBIS_NO_PULLDATA_API
/* Version history /* Version history
1.09 - 2016/04/04 - back out 'avoid discarding last frame' fix from previous version 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks; 1.11 - 2017-07-23 - fix MinGW compilation
1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory
1.09 - 2016-04-04 - back out 'avoid discarding last frame' fix from previous version
1.08 - 2016-04-02 - fixed multiple warnings; fix setup memory leaks;
avoid discarding last frame of audio data avoid discarding last frame of audio data
1.07 - 2015/01/16 - fixed some warnings, fix mingw, const-correct API 1.07 - 2015-01-16 - fixed some warnings, fix mingw, const-correct API
some more crash fixes when out of memory or with corrupt files some more crash fixes when out of memory or with corrupt files
1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson)
some crash fixes when out of memory or with corrupt files some crash fixes when out of memory or with corrupt files
1.05 - 2015/04/19 - don't define __forceinline if it's redundant 1.05 - 2015-04-19 - don't define __forceinline if it's redundant
1.04 - 2014/08/27 - fix missing const-correct case in API 1.04 - 2014-08-27 - fix missing const-correct case in API
1.03 - 2014/08/07 - Warning fixes 1.03 - 2014-08-07 - Warning fixes
1.02 - 2014/07/09 - Declare qsort compare function _cdecl on windows 1.02 - 2014-07-09 - Declare qsort compare function _cdecl on windows
1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float
1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in multichannel 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in multichannel
(API change) report sample rate for decode-full-file funcs (API change) report sample rate for decode-full-file funcs
0.99996 - bracket #include <malloc.h> for macintosh compilation by Laurent Gomila 0.99996 - bracket #include <malloc.h> for macintosh compilation by Laurent Gomila
0.99995 - use union instead of pointer-cast for fast-float-to-int to avoid alias-optimization problem 0.99995 - use union instead of pointer-cast for fast-float-to-int to avoid alias-optimization problem
@@ -5469,3 +5477,46 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
*/ */
#endif // STB_VORBIS_HEADER_ONLY #endif // STB_VORBIS_HEADER_ONLY
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/