Commit 6edd3cfd authored by David Reid's avatar David Reid

Update stb_vorbis.

parent 259d8aa2
// Ogg Vorbis audio decoder - v1.11 - public domain // Ogg Vorbis audio decoder - v1.19 - 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
// //
...@@ -26,26 +26,36 @@ ...@@ -26,26 +26,36 @@
// Terje Mathisen Niklas Frykholm Andy Hill // Terje Mathisen Niklas Frykholm Andy Hill
// Casey Muratori John Bolton Gargaj // Casey Muratori John Bolton Gargaj
// Laurent Gomila Marc LeBlanc Ronny Chevalier // Laurent Gomila Marc LeBlanc Ronny Chevalier
// Bernhard Wodo Evan Balster alxprd@github // Bernhard Wodo Evan Balster github:alxprd
// 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 github:infatum // github:manxorist saga musix github:infatum
// Timur Gagiev Maxwell Koo Peter Waller
// github:audinowho Dougall Johnson
// //
// Partial history: // Partial history:
// 1.11 - 2017/07/23 - fix MinGW compilation // 1.19 - 2020-02-05 - warnings
// 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory // 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc.
// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version // 1.17 - 2019-07-08 - fix CVE-2019-13217..CVE-2019-13223 (by ForAllSecure)
// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame // 1.16 - 2019-03-04 - fix warnings
// 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const // 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found
// 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) // 1.14 - 2018-02-11 - delete bogus dealloca usage
// 1.13 - 2018-01-29 - fix truncation of last frame (hopefully)
// 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
// 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.
...@@ -123,9 +133,20 @@ typedef struct ...@@ -123,9 +133,20 @@ typedef struct
int max_frame_size; int max_frame_size;
} stb_vorbis_info; } stb_vorbis_info;
typedef struct
{
char *vendor;
int comment_list_length;
char **comment_list;
} stb_vorbis_comment;
// get general information about the file // get general information about the file
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f); extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
// get ogg comments
extern stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f);
// get the last error detected (clears it, too) // get the last error detected (clears it, too)
extern int stb_vorbis_get_error(stb_vorbis *f); extern int stb_vorbis_get_error(stb_vorbis *f);
...@@ -249,7 +270,7 @@ extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, ...@@ -249,7 +270,7 @@ extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
// create an ogg vorbis decoder from an open FILE *, looking for a stream at // create an ogg vorbis decoder from an open FILE *, looking for a stream at
// the _current_ seek point (ftell). on failure, returns NULL and sets *error. // the _current_ seek point (ftell). on failure, returns NULL and sets *error.
// note that stb_vorbis must "own" this stream; if you seek it in between // note that stb_vorbis must "own" this stream; if you seek it in between
// calls to stb_vorbis, it will become confused. Morever, if you attempt to // calls to stb_vorbis, it will become confused. Moreover, if you attempt to
// perform stb_vorbis_seek_*() operations on this file, it will assume it // perform stb_vorbis_seek_*() operations on this file, it will assume it
// owns the _entire_ rest of the file after the start point. Use the next // owns the _entire_ rest of the file after the start point. Use the next
// function, stb_vorbis_open_file_section(), to limit it. // function, stb_vorbis_open_file_section(), to limit it.
...@@ -370,7 +391,8 @@ enum STBVorbisError ...@@ -370,7 +391,8 @@ enum STBVorbisError
VORBIS_invalid_first_page, VORBIS_invalid_first_page,
VORBIS_bad_packet_type, VORBIS_bad_packet_type,
VORBIS_cant_find_last_page, VORBIS_cant_find_last_page,
VORBIS_seek_failed VORBIS_seek_failed,
VORBIS_ogg_skeleton_not_supported
}; };
...@@ -751,6 +773,10 @@ struct stb_vorbis ...@@ -751,6 +773,10 @@ struct stb_vorbis
unsigned int temp_memory_required; unsigned int temp_memory_required;
unsigned int setup_temp_memory_required; unsigned int setup_temp_memory_required;
char *vendor;
int comment_list_length;
char **comment_list;
// input config // input config
#ifndef STB_VORBIS_NO_STDIO #ifndef STB_VORBIS_NO_STDIO
FILE *f; FILE *f;
...@@ -766,8 +792,11 @@ struct stb_vorbis ...@@ -766,8 +792,11 @@ struct stb_vorbis
uint8 push_mode; uint8 push_mode;
// the page to seek to when seeking to start, may be zero
uint32 first_audio_page_offset; uint32 first_audio_page_offset;
// p_first is the page on which the first audio packet ends
// (but not necessarily the page on which it starts)
ProbedPage p_first, p_last; ProbedPage p_first, p_last;
// memory management // memory management
...@@ -880,11 +909,7 @@ static int error(vorb *f, enum STBVorbisError e) ...@@ -880,11 +909,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) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size)) #define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size))
#ifdef dealloca #define temp_free(f,p) (void)0
#define temp_free(f,p) (f->alloc.alloc_buffer ? 0 : dealloca(size))
#else
#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))
...@@ -905,7 +930,7 @@ static void *make_block_array(void *mem, int count, int size) ...@@ -905,7 +930,7 @@ static void *make_block_array(void *mem, int count, int size)
static void *setup_malloc(vorb *f, int sz) static void *setup_malloc(vorb *f, int sz)
{ {
sz = (sz+3) & ~3; sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs.
f->setup_memory_required += sz; f->setup_memory_required += sz;
if (f->alloc.alloc_buffer) { if (f->alloc.alloc_buffer) {
void *p = (char *) f->alloc.alloc_buffer + f->setup_offset; void *p = (char *) f->alloc.alloc_buffer + f->setup_offset;
...@@ -924,7 +949,7 @@ static void setup_free(vorb *f, void *p) ...@@ -924,7 +949,7 @@ static void setup_free(vorb *f, void *p)
static void *setup_temp_malloc(vorb *f, int sz) static void *setup_temp_malloc(vorb *f, int sz)
{ {
sz = (sz+3) & ~3; sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs.
if (f->alloc.alloc_buffer) { if (f->alloc.alloc_buffer) {
if (f->temp_offset - sz < f->setup_offset) return NULL; if (f->temp_offset - sz < f->setup_offset) return NULL;
f->temp_offset -= sz; f->temp_offset -= sz;
...@@ -1073,7 +1098,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) ...@@ -1073,7 +1098,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
assert(z >= 0 && z < 32); assert(z >= 0 && z < 32);
available[z] = 0; available[z] = 0;
add_entry(c, bit_reverse(res), i, m++, len[i], values); add_entry(c, bit_reverse(res), i, m++, len[i], values);
// propogate availability up the tree // propagate availability up the tree
if (z != len[i]) { if (z != len[i]) {
assert(len[i] >= 0 && len[i] < 32); assert(len[i] >= 0 && len[i] < 32);
for (y=len[i]; y > z; --y) { for (y=len[i]; y > z; --y) {
...@@ -1199,8 +1224,10 @@ static int lookup1_values(int entries, int dim) ...@@ -1199,8 +1224,10 @@ 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));
if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning; if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning;
++r; // floor() to avoid _ftol() when non-CRT ++r; // floor() to avoid _ftol() when non-CRT
assert(pow((float) r+1, dim) > entries); if (pow((float) r+1, dim) <= entries)
assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above return -1;
if ((int) floor(pow((float) r, dim)) > entries)
return -1;
return r; return r;
} }
...@@ -1398,6 +1425,9 @@ static int capture_pattern(vorb *f) ...@@ -1398,6 +1425,9 @@ static int capture_pattern(vorb *f)
static int start_page_no_capturepattern(vorb *f) static int start_page_no_capturepattern(vorb *f)
{ {
uint32 loc0,loc1,n; uint32 loc0,loc1,n;
if (f->first_decode && !IS_PUSH_MODE(f)) {
f->p_first.page_start = stb_vorbis_get_file_offset(f) - 4;
}
// stream structure version // stream structure version
if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version); if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version);
// header flag // header flag
...@@ -1434,15 +1464,12 @@ static int start_page_no_capturepattern(vorb *f) ...@@ -1434,15 +1464,12 @@ static int start_page_no_capturepattern(vorb *f)
} }
if (f->first_decode) { if (f->first_decode) {
int i,len; int i,len;
ProbedPage p;
len = 0; len = 0;
for (i=0; i < f->segment_count; ++i) for (i=0; i < f->segment_count; ++i)
len += f->segments[i]; len += f->segments[i];
len += 27 + f->segment_count; len += 27 + f->segment_count;
p.page_start = f->first_audio_page_offset; f->p_first.page_end = f->p_first.page_start + len;
p.page_end = p.page_start + len; f->p_first.last_decoded_sample = loc0;
p.last_decoded_sample = loc0;
f->p_first = p;
} }
f->next_seg = 0; f->next_seg = 0;
return TRUE; return TRUE;
...@@ -1533,6 +1560,16 @@ static int get8_packet(vorb *f) ...@@ -1533,6 +1560,16 @@ static int get8_packet(vorb *f)
return x; return x;
} }
static int get32_packet(vorb *f)
{
uint32 x;
x = get8_packet(f);
x += get8_packet(f) << 8;
x += get8_packet(f) << 16;
x += (uint32) get8_packet(f) << 24;
return x;
}
static void flush_packet(vorb *f) static void flush_packet(vorb *f)
{ {
while (get8_packet_raw(f) != EOP); while (get8_packet_raw(f) != EOP);
...@@ -2010,7 +2047,7 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y ...@@ -2010,7 +2047,7 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y
ady -= abs(base) * adx; ady -= abs(base) * adx;
if (x1 > n) x1 = n; if (x1 > n) x1 = n;
if (x < x1) { if (x < x1) {
LINE_OP(output[x], inverse_db_table[y]); LINE_OP(output[x], inverse_db_table[y&255]);
for (++x; x < x1; ++x) { for (++x; x < x1; ++x) {
err += ady; err += ady;
if (err >= adx) { if (err >= adx) {
...@@ -2018,7 +2055,7 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y ...@@ -2018,7 +2055,7 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y
y += sy; y += sy;
} else } else
y += base; y += base;
LINE_OP(output[x], inverse_db_table[y]); LINE_OP(output[x], inverse_db_table[y&255]);
} }
} }
} }
...@@ -2042,6 +2079,8 @@ static int residue_decode(vorb *f, Codebook *book, float *target, int offset, in ...@@ -2042,6 +2079,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;
...@@ -2049,7 +2088,10 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int ...@@ -2049,7 +2088,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
...@@ -2119,47 +2161,7 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int ...@@ -2119,47 +2161,7 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
++class_set; ++class_set;
#endif #endif
} }
} else if (ch == 1) { } else if (ch > 2) {
while (pcount < part_read) {
int z = r->begin + pcount*r->part_size;
int c_inter = 0, p_inter = z;
if (pass == 0) {
Codebook *c = f->codebooks+r->classbook;
int q;
DECODE(q,f,c);
if (q == EOP) goto done;
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
part_classdata[0][class_set] = r->classdata[q];
#else
for (i=classwords-1; i >= 0; --i) {
classifications[0][i+pcount] = q % r->classifications;
q /= r->classifications;
}
#endif
}
for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
int z = r->begin + pcount*r->part_size;
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
int c = part_classdata[0][class_set][i];
#else
int c = classifications[0][pcount];
#endif
int b = r->residue_books[c][pass];
if (b >= 0) {
Codebook *book = f->codebooks + b;
if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done;
} else {
z += r->part_size;
c_inter = 0;
p_inter = z;
}
}
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
++class_set;
#endif
}
} else {
while (pcount < part_read) { while (pcount < part_read) {
int z = r->begin + pcount*r->part_size; int z = r->begin + pcount*r->part_size;
int c_inter = z % ch, p_inter = z/ch; int c_inter = z % ch, p_inter = z/ch;
...@@ -2632,7 +2634,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) ...@@ -2632,7 +2634,7 @@ static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype)
// once I combined the passes. // once I combined the passes.
// so there's a missing 'times 2' here (for adding X to itself). // so there's a missing 'times 2' here (for adding X to itself).
// this propogates through linearly to the end, where the numbers // this propagates through linearly to the end, where the numbers
// are 1/2 too small, and need to be compensated for. // are 1/2 too small, and need to be compensated for.
{ {
...@@ -3040,7 +3042,6 @@ static float *get_window(vorb *f, int len) ...@@ -3040,7 +3042,6 @@ static float *get_window(vorb *f, int len)
len <<= 1; len <<= 1;
if (len == f->blocksize_0) return f->window[0]; if (len == f->blocksize_0) return f->window[0];
if (len == f->blocksize_1) return f->window[1]; if (len == f->blocksize_1) return f->window[1];
assert(0);
return NULL; return NULL;
} }
...@@ -3391,7 +3392,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, ...@@ -3391,7 +3392,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) {
...@@ -3400,7 +3401,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, ...@@ -3400,7 +3401,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;
...@@ -3446,6 +3447,7 @@ static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) ...@@ -3446,6 +3447,7 @@ static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right)
if (f->previous_length) { if (f->previous_length) {
int i,j, n = f->previous_length; int i,j, n = f->previous_length;
float *w = get_window(f, n); float *w = get_window(f, n);
if (w == NULL) return 0;
for (i=0; i < f->channels; ++i) { for (i=0; i < f->channels; ++i) {
for (j=0; j < n; ++j) for (j=0; j < n; ++j)
f->channel_buffers[i][left+j] = f->channel_buffers[i][left+j] =
...@@ -3493,7 +3495,7 @@ static int vorbis_pump_first_frame(stb_vorbis *f) ...@@ -3493,7 +3495,7 @@ static int vorbis_pump_first_frame(stb_vorbis *f)
} }
#ifndef STB_VORBIS_NO_PUSHDATA_API #ifndef STB_VORBIS_NO_PUSHDATA_API
static int is_whole_packet_present(stb_vorbis *f, int end_page) static int is_whole_packet_present(stb_vorbis *f)
{ {
// make sure that we have the packet available before continuing... // make sure that we have the packet available before continuing...
// this requires a full ogg parse, but we know we can fetch from f->stream // this requires a full ogg parse, but we know we can fetch from f->stream
...@@ -3513,8 +3515,6 @@ static int is_whole_packet_present(stb_vorbis *f, int end_page) ...@@ -3513,8 +3515,6 @@ static int is_whole_packet_present(stb_vorbis *f, int end_page)
break; break;
} }
// either this continues, or it ends it... // either this continues, or it ends it...
if (end_page)
if (s < f->segment_count-1) return error(f, VORBIS_invalid_stream);
if (s == f->segment_count) if (s == f->segment_count)
s = -1; // set 'crosses page' flag s = -1; // set 'crosses page' flag
if (p > f->stream_end) return error(f, VORBIS_need_more_data); if (p > f->stream_end) return error(f, VORBIS_need_more_data);
...@@ -3547,8 +3547,6 @@ static int is_whole_packet_present(stb_vorbis *f, int end_page) ...@@ -3547,8 +3547,6 @@ static int is_whole_packet_present(stb_vorbis *f, int end_page)
if (q[s] < 255) if (q[s] < 255)
break; break;
} }
if (end_page)
if (s < n-1) return error(f, VORBIS_invalid_stream);
if (s == n) if (s == n)
s = -1; // set 'crosses page' flag s = -1; // set 'crosses page' flag
if (p > f->stream_end) return error(f, VORBIS_need_more_data); if (p > f->stream_end) return error(f, VORBIS_need_more_data);
...@@ -3565,6 +3563,7 @@ static int start_decoder(vorb *f) ...@@ -3565,6 +3563,7 @@ static int start_decoder(vorb *f)
int longest_floorlist=0; int longest_floorlist=0;
// first page, first packet // first page, first packet
f->first_decode = TRUE;
if (!start_page(f)) return FALSE; if (!start_page(f)) return FALSE;
// validate page flag // validate page flag
...@@ -3573,7 +3572,22 @@ static int start_decoder(vorb *f) ...@@ -3573,7 +3572,22 @@ static int start_decoder(vorb *f)
if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page); if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page);
// check for expected packet length // check for expected packet length
if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page); if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page);
if (f->segments[0] != 30) return error(f, VORBIS_invalid_first_page); if (f->segments[0] != 30) {
// check for the Ogg skeleton fishead identifying header to refine our error
if (f->segments[0] == 64 &&
getn(f, header, 6) &&
header[0] == 'f' &&
header[1] == 'i' &&
header[2] == 's' &&
header[3] == 'h' &&
header[4] == 'e' &&
header[5] == 'a' &&
get8(f) == 'd' &&
get8(f) == '\0') return error(f, VORBIS_ogg_skeleton_not_supported);
else
return error(f, VORBIS_invalid_first_page);
}
// read packet // read packet
// check packet header // check packet header
if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page); if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page);
...@@ -3607,6 +3621,41 @@ static int start_decoder(vorb *f) ...@@ -3607,6 +3621,41 @@ static int start_decoder(vorb *f)
if (!start_page(f)) return FALSE; if (!start_page(f)) return FALSE;
if (!start_packet(f)) return FALSE; if (!start_packet(f)) return FALSE;
if (!next_segment(f)) return FALSE;
if (get8_packet(f) != VORBIS_packet_comment) return error(f, VORBIS_invalid_setup);
for (i=0; i < 6; ++i) header[i] = get8_packet(f);
if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup);
//file vendor
len = get32_packet(f);
f->vendor = (char*)setup_malloc(f, sizeof(char) * (len+1));
for(i=0; i < len; ++i) {
f->vendor[i] = get8_packet(f);
}
f->vendor[len] = (char)'\0';
//user comments
f->comment_list_length = get32_packet(f);
f->comment_list = (char**)setup_malloc(f, sizeof(char*) * (f->comment_list_length));
for(i=0; i < f->comment_list_length; ++i) {
len = get32_packet(f);
f->comment_list[i] = (char*)setup_malloc(f, sizeof(char) * (len+1));
for(j=0; j < len; ++j) {
f->comment_list[i][j] = get8_packet(f);
}
f->comment_list[i][len] = (char)'\0';
}
// framing_flag
x = get8_packet(f);
if (!(x & 1)) return error(f, VORBIS_invalid_setup);
skip(f, f->bytes_in_seg);
f->bytes_in_seg = 0;
do { do {
len = next_segment(f); len = next_segment(f);
skip(f, len); skip(f, len);
...@@ -3618,7 +3667,7 @@ static int start_decoder(vorb *f) ...@@ -3618,7 +3667,7 @@ static int start_decoder(vorb *f)
#ifndef STB_VORBIS_NO_PUSHDATA_API #ifndef STB_VORBIS_NO_PUSHDATA_API
if (IS_PUSH_MODE(f)) { if (IS_PUSH_MODE(f)) {
if (!is_whole_packet_present(f, TRUE)) { if (!is_whole_packet_present(f)) {
// convert error in ogg header to write type // convert error in ogg header to write type
if (f->error == VORBIS_invalid_stream) if (f->error == VORBIS_invalid_stream)
f->error = VORBIS_invalid_setup; f->error = VORBIS_invalid_setup;
...@@ -3672,6 +3721,7 @@ static int start_decoder(vorb *f) ...@@ -3672,6 +3721,7 @@ static int start_decoder(vorb *f)
while (current_entry < c->entries) { while (current_entry < c->entries) {
int limit = c->entries - current_entry; int limit = c->entries - current_entry;
int n = get_bits(f, ilog(limit)); int n = get_bits(f, ilog(limit));
if (current_length >= 32) return error(f, VORBIS_invalid_setup);
if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); } if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); }
memset(lengths + current_entry, current_length, n); memset(lengths + current_entry, current_length, n);
current_entry += n; current_entry += n;
...@@ -3775,7 +3825,9 @@ static int start_decoder(vorb *f) ...@@ -3775,7 +3825,9 @@ static int start_decoder(vorb *f)
c->value_bits = get_bits(f, 4)+1; c->value_bits = get_bits(f, 4)+1;
c->sequence_p = get_bits(f,1); c->sequence_p = get_bits(f,1);
if (c->lookup_type == 1) { if (c->lookup_type == 1) {
c->lookup_values = lookup1_values(c->entries, c->dimensions); int values = lookup1_values(c->entries, c->dimensions);
if (values < 0) return error(f, VORBIS_invalid_setup);
c->lookup_values = (uint32) values;
} else { } else {
c->lookup_values = c->entries * c->dimensions; c->lookup_values = c->entries * c->dimensions;
} }
...@@ -3911,11 +3963,14 @@ static int start_decoder(vorb *f) ...@@ -3911,11 +3963,14 @@ static int start_decoder(vorb *f)
p[j].id = 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-1; ++j)
if (p[j].x == p[j+1].x)
return error(f, VORBIS_invalid_setup);
for (j=0; j < g->values; ++j) for (j=0; j < g->values; ++j)
g->sorted_order[j] = (uint8) p[j].id; 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 = 0,hi = 0;
neighbors(g->Xlist, j, &low,&hi); neighbors(g->Xlist, j, &low,&hi);
g->neighbors[j][0] = low; g->neighbors[j][0] = low;
g->neighbors[j][1] = hi; g->neighbors[j][1] = hi;
...@@ -3997,6 +4052,7 @@ static int start_decoder(vorb *f) ...@@ -3997,6 +4052,7 @@ static int start_decoder(vorb *f)
max_submaps = m->submaps; max_submaps = m->submaps;
if (get_bits(f,1)) { if (get_bits(f,1)) {
m->coupling_steps = get_bits(f,8)+1; m->coupling_steps = get_bits(f,8)+1;
if (m->coupling_steps > f->channels) return error(f, VORBIS_invalid_setup);
for (k=0; k < m->coupling_steps; ++k) { for (k=0; k < m->coupling_steps; ++k) {
m->chan[k].magnitude = get_bits(f, ilog(f->channels-1)); m->chan[k].magnitude = get_bits(f, ilog(f->channels-1));
m->chan[k].angle = get_bits(f, ilog(f->channels-1)); m->chan[k].angle = get_bits(f, ilog(f->channels-1));
...@@ -4050,6 +4106,7 @@ static int start_decoder(vorb *f) ...@@ -4050,6 +4106,7 @@ static int start_decoder(vorb *f)
f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist); f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist);
if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem); if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem);
memset(f->channel_buffers[i], 0, sizeof(float) * f->blocksize_1);
#ifdef STB_VORBIS_NO_DEFER_FLOOR #ifdef STB_VORBIS_NO_DEFER_FLOOR
f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem); if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem);
...@@ -4077,7 +4134,10 @@ static int start_decoder(vorb *f) ...@@ -4077,7 +4134,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;
...@@ -4088,12 +4148,13 @@ static int start_decoder(vorb *f) ...@@ -4088,12 +4148,13 @@ 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;
} }
f->first_decode = TRUE;
if (f->alloc.alloc_buffer) { if (f->alloc.alloc_buffer) {
assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes); assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes);
...@@ -4102,7 +4163,17 @@ static int start_decoder(vorb *f) ...@@ -4102,7 +4163,17 @@ static int start_decoder(vorb *f)
return error(f, VORBIS_outofmem); return error(f, VORBIS_outofmem);
} }
// @TODO: stb_vorbis_seek_start expects first_audio_page_offset to point to a page
// without PAGEFLAG_continued_packet, so this either points to the first page, or
// the page after the end of the headers. It might be cleaner to point to a page
// in the middle of the headers, when that's the page where the first audio packet
// starts, but we'd have to also correctly skip the end of any continued packet in
// stb_vorbis_seek_start.
if (f->next_seg == -1) {
f->first_audio_page_offset = stb_vorbis_get_file_offset(f); f->first_audio_page_offset = stb_vorbis_get_file_offset(f);
} else {
f->first_audio_page_offset = 0;
}
return TRUE; return TRUE;
} }
...@@ -4110,6 +4181,13 @@ static int start_decoder(vorb *f) ...@@ -4110,6 +4181,13 @@ static int start_decoder(vorb *f)
static void vorbis_deinit(stb_vorbis *p) static void vorbis_deinit(stb_vorbis *p)
{ {
int i,j; int i,j;
setup_free(p, p->vendor);
for (i=0; i < p->comment_list_length; ++i) {
setup_free(p, p->comment_list[i]);
}
setup_free(p, p->comment_list);
if (p->residue_config) { if (p->residue_config) {
for (i=0; i < p->residue_count; ++i) { for (i=0; i < p->residue_count; ++i) {
Residue *r = p->residue_config+i; Residue *r = p->residue_config+i;
...@@ -4209,6 +4287,15 @@ stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f) ...@@ -4209,6 +4287,15 @@ stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f)
return d; return d;
} }
stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f)
{
stb_vorbis_comment d;
d.vendor = f->vendor;
d.comment_list_length = f->comment_list_length;
d.comment_list = f->comment_list;
return d;
}
int stb_vorbis_get_error(stb_vorbis *f) int stb_vorbis_get_error(stb_vorbis *f)
{ {
int e = f->error; int e = f->error;
...@@ -4350,7 +4437,7 @@ int stb_vorbis_decode_frame_pushdata( ...@@ -4350,7 +4437,7 @@ int stb_vorbis_decode_frame_pushdata(
f->error = VORBIS__no_error; f->error = VORBIS__no_error;
// check that we have the entire packet in memory // check that we have the entire packet in memory
if (!is_whole_packet_present(f, FALSE)) { if (!is_whole_packet_present(f)) {
*samples = 0; *samples = 0;
return 0; return 0;
} }
...@@ -4555,7 +4642,7 @@ static int get_seek_page_info(stb_vorbis *f, ProbedPage *z) ...@@ -4555,7 +4642,7 @@ static int get_seek_page_info(stb_vorbis *f, ProbedPage *z)
return 1; return 1;
} }
// rarely used function to seek back to the preceeding page while finding the // rarely used function to seek back to the preceding page while finding the
// start of a packet // start of a packet
static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset) static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset)
{ {
...@@ -4586,8 +4673,8 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) ...@@ -4586,8 +4673,8 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
{ {
ProbedPage left, right, mid; ProbedPage left, right, mid;
int i, start_seg_with_known_loc, end_pos, page_start; int i, start_seg_with_known_loc, end_pos, page_start;
uint32 delta, stream_length, padding; uint32 delta, stream_length, padding, last_sample_limit;
double offset, bytes_per_sample; double offset = 0.0, bytes_per_sample = 0.0;
int probe = 0; int probe = 0;
// find the last page and validate the target sample // find the last page and validate the target sample
...@@ -4600,9 +4687,9 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) ...@@ -4600,9 +4687,9 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
// indicates should be the granule position (give or take one)). // indicates should be the granule position (give or take one)).
padding = ((f->blocksize_1 - f->blocksize_0) >> 2); padding = ((f->blocksize_1 - f->blocksize_0) >> 2);
if (sample_number < padding) if (sample_number < padding)
sample_number = 0; last_sample_limit = 0;
else else
sample_number -= padding; last_sample_limit = sample_number - padding;
left = f->p_first; left = f->p_first;
while (left.last_decoded_sample == ~0U) { while (left.last_decoded_sample == ~0U) {
...@@ -4615,9 +4702,12 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) ...@@ -4615,9 +4702,12 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
assert(right.last_decoded_sample != ~0U); assert(right.last_decoded_sample != ~0U);
// starting from the start is handled differently // starting from the start is handled differently
if (sample_number <= left.last_decoded_sample) { if (last_sample_limit <= left.last_decoded_sample) {
if (stb_vorbis_seek_start(f)) if (stb_vorbis_seek_start(f)) {
if (f->current_loc > sample_number)
return error(f, VORBIS_seek_failed);
return 1; return 1;
}
return 0; return 0;
} }
...@@ -4634,10 +4724,10 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) ...@@ -4634,10 +4724,10 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
// first probe (interpolate) // first probe (interpolate)
double data_bytes = right.page_end - left.page_start; double data_bytes = right.page_end - left.page_start;
bytes_per_sample = data_bytes / right.last_decoded_sample; bytes_per_sample = data_bytes / right.last_decoded_sample;
offset = left.page_start + bytes_per_sample * (sample_number - left.last_decoded_sample); offset = left.page_start + bytes_per_sample * (last_sample_limit - left.last_decoded_sample);
} else { } else {
// second probe (try to bound the other side) // second probe (try to bound the other side)
double error = ((double) sample_number - mid.last_decoded_sample) * bytes_per_sample; double error = ((double) last_sample_limit - mid.last_decoded_sample) * bytes_per_sample;
if (error >= 0 && error < 8000) error = 8000; if (error >= 0 && error < 8000) error = 8000;
if (error < 0 && error > -8000) error = -8000; if (error < 0 && error > -8000) error = -8000;
offset += error * 2; offset += error * 2;
...@@ -4668,14 +4758,16 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) ...@@ -4668,14 +4758,16 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
} }
// if we've just found the last page again then we're in a tricky file, // if we've just found the last page again then we're in a tricky file,
// and we're close enough. // and we're close enough (if it wasn't an interpolation probe).
if (mid.page_start == right.page_start) if (mid.page_start == right.page_start) {
if (probe >= 2 || delta <= 65536)
break; break;
} else {
if (sample_number < mid.last_decoded_sample) if (last_sample_limit < mid.last_decoded_sample)
right = mid; right = mid;
else else
left = mid; left = mid;
}
++probe; ++probe;
} }
...@@ -4791,8 +4883,8 @@ int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) ...@@ -4791,8 +4883,8 @@ int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number)
flush_packet(f); flush_packet(f);
} }
} }
// the next frame will start with the sample // the next frame should start with the sample
assert(f->current_loc == sample_number); if (f->current_loc != sample_number) return error(f, VORBIS_seek_failed);
return 1; return 1;
} }
...@@ -4962,7 +5054,13 @@ stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, con ...@@ -4962,7 +5054,13 @@ stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, con
stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc) stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc)
{ {
FILE *f = fopen(filename, "rb"); FILE *f;
#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__)
if (0 != fopen_s(&f, filename, "rb"))
f = NULL;
#else
f = fopen(filename, "rb");
#endif
if (f) if (f)
return stb_vorbis_open_file(f, TRUE, error, alloc); return stb_vorbis_open_file(f, TRUE, error, alloc);
if (error) *error = VORBIS_file_open_failure; if (error) *error = VORBIS_file_open_failure;
...@@ -5128,7 +5226,7 @@ static void convert_samples_short(int buf_c, short **buffer, int b_offset, int d ...@@ -5128,7 +5226,7 @@ static void convert_samples_short(int buf_c, short **buffer, int b_offset, int d
int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples) int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples)
{ {
float **output; float **output = NULL;
int len = stb_vorbis_get_frame_float(f, NULL, &output); int len = stb_vorbis_get_frame_float(f, NULL, &output);
if (len > num_samples) len = num_samples; if (len > num_samples) len = num_samples;
if (len) if (len)
...@@ -5351,20 +5449,28 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in ...@@ -5351,20 +5449,28 @@ 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.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory 1.17 - 2019-07-08 - fix CVE-2019-13217, -13218, -13219, -13220, -13221, -13222, -13223
1.09 - 2016/04/04 - back out 'avoid discarding last frame' fix from previous version found with Mayhem by ForAllSecure
1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks; 1.16 - 2019-03-04 - fix warnings
1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found
1.14 - 2018-02-11 - delete bogus dealloca usage
1.13 - 2018-01-29 - fix truncation of last frame (hopefully)
1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment