Merge branch 'working'

pull/225/head
Sean Barrett 2016-01-16 10:17:15 -08:00
commit 667d840860
7 changed files with 594 additions and 403 deletions

View File

@ -1,4 +1,4 @@
/* stb_image - v2.08 - public domain image loader - http://nothings.org/stb_image.h /* stb_image - v2.09 - public domain image loader - http://nothings.org/stb_image.h
no warranty implied; use at your own risk no warranty implied; use at your own risk
Do this: Do this:
@ -146,6 +146,7 @@
Latest revision history: Latest revision history:
2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
2.07 (2015-09-13) partial animated GIF support 2.07 (2015-09-13) partial animated GIF support
limited 16-bit PSD support limited 16-bit PSD support
@ -175,44 +176,35 @@
============================ Contributors ========================= ============================ Contributors =========================
Image formats Bug fixes & warning fixes Image formats Extensions, features
Sean Barrett (jpeg, png, bmp) Marc LeBlanc Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
Nicolas Schulz (hdr, psd) Christpher Lloyd Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
Jonathan Dummer (tga) Dave Moore Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
Jean-Marc Lienher (gif) Won Chun Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
Tom Seddon (pic) the Horde3D community Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
Thatcher Ulrich (psd) Janez Zemva Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
Ken Miller (pgm, ppm) Jonathan Blow Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
urraka@github (animated gif) Laurent Gomila urraka@github (animated gif) Junggon Kim (PNM comments)
Aruelien Pocheville Daniel Gibson (16-bit TGA)
Ryamond Barbiero
David Woo Optimizations & bugfixes
Extensions, features Martin Golini Fabian "ryg" Giesen
Jetro Lauha (stbi_info) Roy Eltham Arseny Kapoulkine
Martin "SpartanJ" Golini (stbi_info) Luke Graham
James "moose2000" Brown (iPhone PNG) Thomas Ruf Bug & warning fixes
Ben "Disch" Wenger (io callbacks) John Bartholomew Marc LeBlanc David Woo Guillaume George Martins Mozeiko
Omar Cornut (1/2/4-bit PNG) Ken Hamada Christpher Lloyd Martin Golini Jerry Jansson Joseph Thomson
Nicolas Guillemot (vertical flip) Cort Stratton Dave Moore Roy Eltham Hayaki Saito Phil Jordan
Richard Mitton (16-bit PSD) Blazej Dariusz Roszkowski Won Chun Luke Graham Johan Duparc Nathan Reed
Thibault Reuille the Horde3D community Thomas Ruf Ronny Chevalier Nick Verigakis
Paul Du Bois Janez Zemva John Bartholomew Michal Cichon svdijk@github
Guillaume George Jonathan Blow Ken Hamada Tero Hanninen Baldur Karlsson
Jerry Jansson Laurent Gomila Cort Stratton Sergio Gonzalez romigrou@github
Hayaki Saito Aruelien Pocheville Thibault Reuille Cass Everitt
Johan Duparc Ryamond Barbiero Paul Du Bois Engin Manap
Ronny Chevalier Blazej Dariusz Roszkowski
Optimizations & bugfixes Michal Cichon Michaelangel007@github
Fabian "ryg" Giesen Tero Hanninen
Arseny Kapoulkine Sergio Gonzalez
Cass Everitt
Engin Manap
If your name should be here but Martins Mozeiko
isn't, let Sean know. Joseph Thomson
Phil Jordan
Nathan Reed
Michaelangel007@github
Nick Verigakis
LICENSE LICENSE
@ -461,12 +453,12 @@ STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y,
#ifndef STBI_NO_HDR #ifndef STBI_NO_HDR
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
STBIDEF void stbi_hdr_to_ldr_scale(float scale); STBIDEF void stbi_hdr_to_ldr_scale(float scale);
#endif #endif // STBI_NO_HDR
#ifndef STBI_NO_LINEAR #ifndef STBI_NO_LINEAR
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
STBIDEF void stbi_ldr_to_hdr_scale(float scale); STBIDEF void stbi_ldr_to_hdr_scale(float scale);
#endif // STBI_NO_HDR #endif // STBI_NO_LINEAR
// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR // stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
@ -630,18 +622,22 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y))))
#endif #endif
#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
// ok // ok
#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) #elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
// ok // ok
#else #else
#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." #error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
#endif #endif
#ifndef STBI_MALLOC #ifndef STBI_MALLOC
#define STBI_MALLOC(sz) malloc(sz) #define STBI_MALLOC(sz) malloc(sz)
#define STBI_REALLOC(p,sz) realloc(p,sz) #define STBI_REALLOC(p,newsz) realloc(p,newsz)
#define STBI_FREE(p) free(p) #define STBI_FREE(p) free(p)
#endif
#ifndef STBI_REALLOC_SIZED
#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
#endif #endif
// x86/x64 detection // x86/x64 detection
@ -1186,14 +1182,15 @@ STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void
#endif #endif
} }
static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; #ifndef STBI_NO_LINEAR
static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
#ifndef STBI_NO_LINEAR
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
#endif #endif
static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
@ -3616,14 +3613,14 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes
{ {
char *q; char *q;
int cur, limit; int cur, limit, old_limit;
z->zout = zout; z->zout = zout;
if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
cur = (int) (z->zout - z->zout_start); cur = (int) (z->zout - z->zout_start);
limit = (int) (z->zout_end - z->zout_start); limit = old_limit = (int) (z->zout_end - z->zout_start);
while (cur + n > limit) while (cur + n > limit)
limit *= 2; limit *= 2;
q = (char *) STBI_REALLOC(z->zout_start, limit); q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
if (q == NULL) return stbi__err("outofmem", "Out of memory"); if (q == NULL) return stbi__err("outofmem", "Out of memory");
z->zout_start = q; z->zout_start = q;
z->zout = q + cur; z->zout = q + cur;
@ -4408,11 +4405,12 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
if ((int)(ioff + c.length) < (int)ioff) return 0; if ((int)(ioff + c.length) < (int)ioff) return 0;
if (ioff + c.length > idata_limit) { if (ioff + c.length > idata_limit) {
stbi__uint32 idata_limit_old = idata_limit;
stbi_uc *p; stbi_uc *p;
if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
while (ioff + c.length > idata_limit) while (ioff + c.length > idata_limit)
idata_limit *= 2; idata_limit *= 2;
p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
z->idata = p; z->idata = p;
} }
if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
@ -4598,19 +4596,22 @@ static int stbi__shiftsigned(int v, int shift, int bits)
return result; return result;
} }
static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) typedef struct
{ {
stbi_uc *out; int bpp, offset, hsz;
unsigned int mr=0,mg=0,mb=0,ma=0, all_a=255; unsigned int mr,mg,mb,ma, all_a;
stbi_uc pal[256][4]; } stbi__bmp_data;
int psize=0,i,j,compress=0,width;
int bpp, flip_vertically, pad, target, offset, hsz; static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
{
int hsz;
if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
stbi__get32le(s); // discard filesize stbi__get32le(s); // discard filesize
stbi__get16le(s); // discard reserved stbi__get16le(s); // discard reserved
stbi__get16le(s); // discard reserved stbi__get16le(s); // discard reserved
offset = stbi__get32le(s); info->offset = stbi__get32le(s);
hsz = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s);
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
if (hsz == 12) { if (hsz == 12) {
s->img_x = stbi__get16le(s); s->img_x = stbi__get16le(s);
@ -4620,15 +4621,10 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
s->img_y = stbi__get32le(s); s->img_y = stbi__get32le(s);
} }
if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
bpp = stbi__get16le(s); info->bpp = stbi__get16le(s);
if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
flip_vertically = ((int) s->img_y) > 0; if (hsz != 12) {
s->img_y = abs((int) s->img_y); int compress = stbi__get32le(s);
if (hsz == 12) {
if (bpp < 24)
psize = (offset - 14 - 24) / 3;
} else {
compress = stbi__get32le(s);
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard sizeof
stbi__get32le(s); // discard hres stbi__get32le(s); // discard hres
@ -4642,26 +4638,26 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
stbi__get32le(s); stbi__get32le(s);
stbi__get32le(s); stbi__get32le(s);
} }
if (bpp == 16 || bpp == 32) { if (info->bpp == 16 || info->bpp == 32) {
mr = mg = mb = 0; info->mr = info->mg = info->mb = 0;
if (compress == 0) { if (compress == 0) {
if (bpp == 32) { if (info->bpp == 32) {
mr = 0xffu << 16; info->mr = 0xffu << 16;
mg = 0xffu << 8; info->mg = 0xffu << 8;
mb = 0xffu << 0; info->mb = 0xffu << 0;
ma = 0xffu << 24; info->ma = 0xffu << 24;
all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
} else { } else {
mr = 31u << 10; info->mr = 31u << 10;
mg = 31u << 5; info->mg = 31u << 5;
mb = 31u << 0; info->mb = 31u << 0;
} }
} else if (compress == 3) { } else if (compress == 3) {
mr = stbi__get32le(s); info->mr = stbi__get32le(s);
mg = stbi__get32le(s); info->mg = stbi__get32le(s);
mb = stbi__get32le(s); info->mb = stbi__get32le(s);
// not documented, but generated by photoshop and handled by mspaint // not documented, but generated by photoshop and handled by mspaint
if (mr == mg && mg == mb) { if (info->mr == info->mg && info->mg == info->mb) {
// ?!?!? // ?!?!?
return stbi__errpuc("bad BMP", "bad BMP"); return stbi__errpuc("bad BMP", "bad BMP");
} }
@ -4669,11 +4665,13 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
return stbi__errpuc("bad BMP", "bad BMP"); return stbi__errpuc("bad BMP", "bad BMP");
} }
} else { } else {
STBI_ASSERT(hsz == 108 || hsz == 124); int i;
mr = stbi__get32le(s); if (hsz != 108 && hsz != 124)
mg = stbi__get32le(s); return stbi__errpuc("bad BMP", "bad BMP");
mb = stbi__get32le(s); info->mr = stbi__get32le(s);
ma = stbi__get32le(s); info->mg = stbi__get32le(s);
info->mb = stbi__get32le(s);
info->ma = stbi__get32le(s);
stbi__get32le(s); // discard color space stbi__get32le(s); // discard color space
for (i=0; i < 12; ++i) for (i=0; i < 12; ++i)
stbi__get32le(s); // discard color space parameters stbi__get32le(s); // discard color space parameters
@ -4684,35 +4682,68 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
stbi__get32le(s); // discard reserved stbi__get32le(s); // discard reserved
} }
} }
if (bpp < 16)
psize = (offset - 14 - hsz) >> 2;
} }
return (void *) 1;
}
static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{
stbi_uc *out;
unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
stbi_uc pal[256][4];
int psize=0,i,j,width;
int flip_vertically, pad, target;
stbi__bmp_data info;
info.all_a = 255;
if (stbi__bmp_parse_header(s, &info) == NULL)
return NULL; // error code already set
flip_vertically = ((int) s->img_y) > 0;
s->img_y = abs((int) s->img_y);
mr = info.mr;
mg = info.mg;
mb = info.mb;
ma = info.ma;
all_a = info.all_a;
if (info.hsz == 12) {
if (info.bpp < 24)
psize = (info.offset - 14 - 24) / 3;
} else {
if (info.bpp < 16)
psize = (info.offset - 14 - info.hsz) >> 2;
}
s->img_n = ma ? 4 : 3; s->img_n = ma ? 4 : 3;
if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
target = req_comp; target = req_comp;
else else
target = s->img_n; // if they want monochrome, we'll post-convert target = s->img_n; // if they want monochrome, we'll post-convert
out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y);
if (!out) return stbi__errpuc("outofmem", "Out of memory"); if (!out) return stbi__errpuc("outofmem", "Out of memory");
if (bpp < 16) { if (info.bpp < 16) {
int z=0; int z=0;
if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
for (i=0; i < psize; ++i) { for (i=0; i < psize; ++i) {
pal[i][2] = stbi__get8(s); pal[i][2] = stbi__get8(s);
pal[i][1] = stbi__get8(s); pal[i][1] = stbi__get8(s);
pal[i][0] = stbi__get8(s); pal[i][0] = stbi__get8(s);
if (hsz != 12) stbi__get8(s); if (info.hsz != 12) stbi__get8(s);
pal[i][3] = 255; pal[i][3] = 255;
} }
stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
if (bpp == 4) width = (s->img_x + 1) >> 1; if (info.bpp == 4) width = (s->img_x + 1) >> 1;
else if (bpp == 8) width = s->img_x; else if (info.bpp == 8) width = s->img_x;
else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
pad = (-width)&3; pad = (-width)&3;
for (j=0; j < (int) s->img_y; ++j) { for (j=0; j < (int) s->img_y; ++j) {
for (i=0; i < (int) s->img_x; i += 2) { for (i=0; i < (int) s->img_x; i += 2) {
int v=stbi__get8(s),v2=0; int v=stbi__get8(s),v2=0;
if (bpp == 4) { if (info.bpp == 4) {
v2 = v & 15; v2 = v & 15;
v >>= 4; v >>= 4;
} }
@ -4721,7 +4752,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
out[z++] = pal[v][2]; out[z++] = pal[v][2];
if (target == 4) out[z++] = 255; if (target == 4) out[z++] = 255;
if (i+1 == (int) s->img_x) break; if (i+1 == (int) s->img_x) break;
v = (bpp == 8) ? stbi__get8(s) : v2; v = (info.bpp == 8) ? stbi__get8(s) : v2;
out[z++] = pal[v][0]; out[z++] = pal[v][0];
out[z++] = pal[v][1]; out[z++] = pal[v][1];
out[z++] = pal[v][2]; out[z++] = pal[v][2];
@ -4733,14 +4764,14 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
int z = 0; int z = 0;
int easy=0; int easy=0;
stbi__skip(s, offset - 14 - hsz); stbi__skip(s, info.offset - 14 - info.hsz);
if (bpp == 24) width = 3 * s->img_x; if (info.bpp == 24) width = 3 * s->img_x;
else if (bpp == 16) width = 2*s->img_x; else if (info.bpp == 16) width = 2*s->img_x;
else /* bpp = 32 and pad = 0 */ width=0; else /* bpp = 32 and pad = 0 */ width=0;
pad = (-width) & 3; pad = (-width) & 3;
if (bpp == 24) { if (info.bpp == 24) {
easy = 1; easy = 1;
} else if (bpp == 32) { } else if (info.bpp == 32) {
if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
easy = 2; easy = 2;
} }
@ -4765,6 +4796,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
if (target == 4) out[z++] = a; if (target == 4) out[z++] = a;
} }
} else { } else {
int bpp = info.bpp;
for (i=0; i < (int) s->img_x; ++i) { for (i=0; i < (int) s->img_x; ++i) {
stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
int a; int a;
@ -4811,20 +4843,55 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
// Targa Truevision - TGA // Targa Truevision - TGA
// by Jonathan Dummer // by Jonathan Dummer
#ifndef STBI_NO_TGA #ifndef STBI_NO_TGA
// returns STBI_rgb or whatever, 0 on error
static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
{
// only RGB or RGBA (incl. 16bit) or grey allowed
if(is_rgb16) *is_rgb16 = 0;
switch(bits_per_pixel) {
case 8: return STBI_grey;
case 16: if(is_grey) return STBI_grey_alpha;
// else: fall-through
case 15: if(is_rgb16) *is_rgb16 = 1;
return STBI_rgb;
case 24: // fall-through
case 32: return bits_per_pixel/8;
default: return 0;
}
}
static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
{ {
int tga_w, tga_h, tga_comp; int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;
int sz; int sz, tga_colormap_type;
stbi__get8(s); // discard Offset stbi__get8(s); // discard Offset
sz = stbi__get8(s); // color type tga_colormap_type = stbi__get8(s); // colormap type
if( sz > 1 ) { if( tga_colormap_type > 1 ) {
stbi__rewind(s); stbi__rewind(s);
return 0; // only RGB or indexed allowed return 0; // only RGB or indexed allowed
} }
sz = stbi__get8(s); // image type tga_image_type = stbi__get8(s); // image type
// only RGB or grey allowed, +/- RLE if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; if (tga_image_type != 1 && tga_image_type != 9) {
stbi__skip(s,9); stbi__rewind(s);
return 0;
}
stbi__skip(s,4); // skip index of first colormap entry and number of entries
sz = stbi__get8(s); // check bits per palette color entry
if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {
stbi__rewind(s);
return 0;
}
stbi__skip(s,4); // skip image x and y origin
tga_colormap_bpp = sz;
} else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE
if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {
stbi__rewind(s);
return 0; // only RGB or grey allowed, +/- RLE
}
stbi__skip(s,9); // skip colormap specification and image x/y origin
tga_colormap_bpp = 0;
}
tga_w = stbi__get16le(s); tga_w = stbi__get16le(s);
if( tga_w < 1 ) { if( tga_w < 1 ) {
stbi__rewind(s); stbi__rewind(s);
@ -4835,44 +4902,80 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
stbi__rewind(s); stbi__rewind(s);
return 0; // test height return 0; // test height
} }
sz = stbi__get8(s); // bits per pixel tga_bits_per_pixel = stbi__get8(s); // bits per pixel
// only RGB or RGBA or grey allowed stbi__get8(s); // ignore alpha bits
if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { if (tga_colormap_bpp != 0) {
stbi__rewind(s); if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
return 0; // when using a colormap, tga_bits_per_pixel is the size of the indexes
// I don't think anything but 8 or 16bit indexes makes sense
stbi__rewind(s);
return 0;
}
tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);
} else {
tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);
}
if(!tga_comp) {
stbi__rewind(s);
return 0;
} }
tga_comp = sz;
if (x) *x = tga_w; if (x) *x = tga_w;
if (y) *y = tga_h; if (y) *y = tga_h;
if (comp) *comp = tga_comp / 8; if (comp) *comp = tga_comp;
return 1; // seems to have passed everything return 1; // seems to have passed everything
} }
static int stbi__tga_test(stbi__context *s) static int stbi__tga_test(stbi__context *s)
{ {
int res; int res = 0;
int sz; int sz, tga_color_type;
stbi__get8(s); // discard Offset stbi__get8(s); // discard Offset
sz = stbi__get8(s); // color type tga_color_type = stbi__get8(s); // color type
if ( sz > 1 ) return 0; // only RGB or indexed allowed if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed
sz = stbi__get8(s); // image type sz = stbi__get8(s); // image type
if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE if ( tga_color_type == 1 ) { // colormapped (paletted) image
stbi__get16be(s); // discard palette start if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
stbi__get16be(s); // discard palette length stbi__skip(s,4); // skip index of first colormap entry and number of entries
stbi__get8(s); // discard bits per palette color entry sz = stbi__get8(s); // check bits per palette color entry
stbi__get16be(s); // discard x origin if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
stbi__get16be(s); // discard y origin stbi__skip(s,4); // skip image x and y origin
if ( stbi__get16be(s) < 1 ) return 0; // test width } else { // "normal" image w/o colormap
if ( stbi__get16be(s) < 1 ) return 0; // test height if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE
stbi__skip(s,9); // skip colormap specification and image x/y origin
}
if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width
if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height
sz = stbi__get8(s); // bits per pixel sz = stbi__get8(s); // bits per pixel
if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
res = 0; if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
else
res = 1; res = 1; // if we got this far, everything's good and we can return 1 instead of 0
errorEnd:
stbi__rewind(s); stbi__rewind(s);
return res; return res;
} }
// read 16bit value and convert to 24bit RGB
void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
{
stbi__uint16 px = stbi__get16le(s);
stbi__uint16 fiveBitMask = 31;
// we have 3 channels with 5bits each
int r = (px >> 10) & fiveBitMask;
int g = (px >> 5) & fiveBitMask;
int b = px & fiveBitMask;
// Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later
out[0] = (r * 255)/31;
out[1] = (g * 255)/31;
out[2] = (b * 255)/31;
// some people claim that the most significant bit might be used for alpha
// (possibly if an alpha-bit is set in the "image descriptor byte")
// but that only made 16bit test images completely translucent..
// so let's treat all 15 and 16bit TGAs as RGB with no alpha.
}
static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{ {
// read in the TGA header stuff // read in the TGA header stuff
@ -4888,8 +4991,9 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
int tga_width = stbi__get16le(s); int tga_width = stbi__get16le(s);
int tga_height = stbi__get16le(s); int tga_height = stbi__get16le(s);
int tga_bits_per_pixel = stbi__get8(s); int tga_bits_per_pixel = stbi__get8(s);
int tga_comp = tga_bits_per_pixel / 8; int tga_comp, tga_rgb16=0;
int tga_inverted = stbi__get8(s); int tga_inverted = stbi__get8(s);
// int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)
// image data // image data
unsigned char *tga_data; unsigned char *tga_data;
unsigned char *tga_palette = NULL; unsigned char *tga_palette = NULL;
@ -4905,25 +5009,14 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
tga_image_type -= 8; tga_image_type -= 8;
tga_is_RLE = 1; tga_is_RLE = 1;
} }
/* int tga_alpha_bits = tga_inverted & 15; */
tga_inverted = 1 - ((tga_inverted >> 5) & 1); tga_inverted = 1 - ((tga_inverted >> 5) & 1);
// error check
if ( //(tga_indexed) ||
(tga_width < 1) || (tga_height < 1) ||
(tga_image_type < 1) || (tga_image_type > 3) ||
((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) &&
(tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32))
)
{
return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA
}
// If I'm paletted, then I'll use the number of bits from the palette // If I'm paletted, then I'll use the number of bits from the palette
if ( tga_indexed ) if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
{ else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
tga_comp = tga_palette_bits / 8;
} if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency
return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
// tga info // tga info
*x = tga_width; *x = tga_width;
@ -4936,7 +5029,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
// skip to the data's starting position (offset usually = 0) // skip to the data's starting position (offset usually = 0)
stbi__skip(s, tga_offset ); stbi__skip(s, tga_offset );
if ( !tga_indexed && !tga_is_RLE) { if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {
for (i=0; i < tga_height; ++i) { for (i=0; i < tga_height; ++i) {
int row = tga_inverted ? tga_height -i - 1 : i; int row = tga_inverted ? tga_height -i - 1 : i;
stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
@ -4949,15 +5042,22 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
// any data to skip? (offset usually = 0) // any data to skip? (offset usually = 0)
stbi__skip(s, tga_palette_start ); stbi__skip(s, tga_palette_start );
// load the palette // load the palette
tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_comp );
if (!tga_palette) { if (!tga_palette) {
STBI_FREE(tga_data); STBI_FREE(tga_data);
return stbi__errpuc("outofmem", "Out of memory"); return stbi__errpuc("outofmem", "Out of memory");
} }
if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { if (tga_rgb16) {
STBI_FREE(tga_data); stbi_uc *pal_entry = tga_palette;
STBI_FREE(tga_palette); STBI_ASSERT(tga_comp == STBI_rgb);
return stbi__errpuc("bad palette", "Corrupt TGA"); for (i=0; i < tga_palette_len; ++i) {
stbi__tga_read_rgb16(s, pal_entry);
pal_entry += tga_comp;
}
} else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {
STBI_FREE(tga_data);
STBI_FREE(tga_palette);
return stbi__errpuc("bad palette", "Corrupt TGA");
} }
} }
// load the data // load the data
@ -4987,23 +5087,22 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
// load however much data we did have // load however much data we did have
if ( tga_indexed ) if ( tga_indexed )
{ {
// read in 1 byte, then perform the lookup // read in index, then perform the lookup
int pal_idx = stbi__get8(s); int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
if ( pal_idx >= tga_palette_len ) if ( pal_idx >= tga_palette_len ) {
{ // invalid index
// invalid index
pal_idx = 0; pal_idx = 0;
} }
pal_idx *= tga_bits_per_pixel / 8; pal_idx *= tga_comp;
for (j = 0; j*8 < tga_bits_per_pixel; ++j) for (j = 0; j < tga_comp; ++j) {
{
raw_data[j] = tga_palette[pal_idx+j]; raw_data[j] = tga_palette[pal_idx+j];
} }
} else } else if(tga_rgb16) {
{ STBI_ASSERT(tga_comp == STBI_rgb);
stbi__tga_read_rgb16(s, raw_data);
} else {
// read in the data raw // read in the data raw
for (j = 0; j*8 < tga_bits_per_pixel; ++j) for (j = 0; j < tga_comp; ++j) {
{
raw_data[j] = stbi__get8(s); raw_data[j] = stbi__get8(s);
} }
} }
@ -5042,8 +5141,8 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
} }
} }
// swap RGB // swap RGB - if the source data was RGB16, it already is in the right order
if (tga_comp >= 3) if (tga_comp >= 3 && !tga_rgb16)
{ {
unsigned char* tga_pixel = tga_data; unsigned char* tga_pixel = tga_data;
for (i=0; i < tga_width * tga_height; ++i) for (i=0; i < tga_width * tga_height; ++i)
@ -6017,7 +6116,7 @@ static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
char *token; char *token;
int valid = 0; int valid = 0;
if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { if (stbi__hdr_test(s) == 0) {
stbi__rewind( s ); stbi__rewind( s );
return 0; return 0;
} }
@ -6054,29 +6153,17 @@ static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
#ifndef STBI_NO_BMP #ifndef STBI_NO_BMP
static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
{ {
int hsz; void *p;
if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') { stbi__bmp_data info;
stbi__rewind( s );
return 0; info.all_a = 255;
} p = stbi__bmp_parse_header(s, &info);
stbi__skip(s,12); stbi__rewind( s );
hsz = stbi__get32le(s); if (p == NULL)
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) { return 0;
stbi__rewind( s ); *x = s->img_x;
return 0; *y = s->img_y;
} *comp = info.ma ? 4 : 3;
if (hsz == 12) {
*x = stbi__get16le(s);
*y = stbi__get16le(s);
} else {
*x = stbi__get32le(s);
*y = stbi__get32le(s);
}
if (stbi__get16le(s) != 1) {
stbi__rewind( s );
return 0;
}
*comp = stbi__get16le(s) / 8;
return 1; return 1;
} }
#endif #endif
@ -6222,8 +6309,16 @@ static int stbi__pnm_isspace(char c)
static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) static void stbi__pnm_skip_whitespace(stbi__context *s, char *c)
{ {
while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) for (;;) {
*c = (char) stbi__get8(s); while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
*c = (char) stbi__get8(s);
if (stbi__at_eof(s) || *c != '#')
break;
while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' )
*c = (char) stbi__get8(s);
}
} }
static int stbi__pnm_isdigit(char c) static int stbi__pnm_isdigit(char c)
@ -6361,10 +6456,16 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
/* /*
revision history: revision history:
2.09 (2016-01-16) allow comments in PNM files
16-bit-per-pixel TGA (not bit-per-component)
info() for TGA could break due to .hdr handling
info() for BMP to shares code instead of sloppy parse
can use STBI_REALLOC_SIZED if allocator doesn't support realloc
code cleanup
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
2.07 (2015-09-13) fix compiler warnings 2.07 (2015-09-13) fix compiler warnings
partial animated GIF support partial animated GIF support
limited 16-bit PSD support limited 16-bpc PSD support
#ifdef unused functions #ifdef unused functions
bug with < 92 byte PIC,PNM,HDR,TGA bug with < 92 byte PIC,PNM,HDR,TGA
2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value

View File

@ -1,4 +1,4 @@
/* stb_image_write - v1.00 - public domain - http://nothings.org/stb/stb_image_write.h /* stb_image_write - v1.01 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015 writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk no warranty implied; use at your own risk
@ -34,7 +34,7 @@ USAGE:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data); int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
There are also four equivalent functions that use an arbitrary write function. You are There are also four equivalent functions that use an arbitrary write function. You are
expected to open/close your file-equivalent before and after calling these: expected to open/close your file-equivalent before and after calling these:
@ -98,12 +98,16 @@ CREDITS:
github:Chribba github:Chribba
Guillaume Chereau Guillaume Chereau
github:jry2 github:jry2
github:romigrou
Sergio Gonzalez
Jonas Karlsson
Filip Wasil
LICENSE LICENSE
This software is in the public domain. Where that dedication is not This software is in the public domain. Where that dedication is not
recognized, you are granted a perpetual, irrevocable license to copy, recognized, you are granted a perpetual, irrevocable license to copy,
distribute, and modify this file as you see fit. distribute, and modify this file as you see fit.
*/ */
@ -144,8 +148,12 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w,
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION #ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#ifdef _WIN32 #ifdef _WIN32
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE #define _CRT_NONSTDC_NO_DEPRECATE
#endif
#endif #endif
#ifndef STBI_WRITE_NO_STDIO #ifndef STBI_WRITE_NO_STDIO
@ -157,19 +165,25 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w,
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && defined(STBIW_REALLOC) #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
// ok // ok
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
// ok // ok
#else #else
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC." #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
#endif #endif
#ifndef STBIW_MALLOC #ifndef STBIW_MALLOC
#define STBIW_MALLOC(sz) malloc(sz) #define STBIW_MALLOC(sz) malloc(sz)
#define STBIW_REALLOC(p,sz) realloc(p,sz) #define STBIW_REALLOC(p,newsz) realloc(p,newsz)
#define STBIW_FREE(p) free(p) #define STBIW_FREE(p) free(p)
#endif #endif
#ifndef STBIW_REALLOC_SIZED
#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
#endif
#ifndef STBIW_MEMMOVE #ifndef STBIW_MEMMOVE
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
#endif #endif
@ -180,6 +194,8 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w,
#define STBIW_ASSERT(x) assert(x) #define STBIW_ASSERT(x) assert(x)
#endif #endif
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
typedef struct typedef struct
{ {
stbi_write_func *func; stbi_write_func *func;
@ -228,21 +244,21 @@ static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
while (*fmt) { while (*fmt) {
switch (*fmt++) { switch (*fmt++) {
case ' ': break; case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
s->func(s->context,&x,1); s->func(s->context,&x,1);
break; } break; }
case '2': { int x = va_arg(v,int); case '2': { int x = va_arg(v,int);
unsigned char b[2]; unsigned char b[2];
b[0] = (unsigned char) x; b[0] = STBIW_UCHAR(x);
b[1] = (unsigned char) (x>>8); b[1] = STBIW_UCHAR(x>>8);
s->func(s->context,b,2); s->func(s->context,b,2);
break; } break; }
case '4': { stbiw_uint32 x = va_arg(v,int); case '4': { stbiw_uint32 x = va_arg(v,int);
unsigned char b[4]; unsigned char b[4];
b[0]=(unsigned char)x; b[0]=STBIW_UCHAR(x);
b[1]=(unsigned char)(x>>8); b[1]=STBIW_UCHAR(x>>8);
b[2]=(unsigned char)(x>>16); b[2]=STBIW_UCHAR(x>>16);
b[3]=(unsigned char)(x>>24); b[3]=STBIW_UCHAR(x>>24);
s->func(s->context,b,4); s->func(s->context,b,4);
break; } break; }
default: default:
@ -419,13 +435,13 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
} }
if (diff) { if (diff) {
unsigned char header = (unsigned char) (len - 1); unsigned char header = STBIW_UCHAR(len - 1);
s->func(s->context, &header, 1); s->func(s->context, &header, 1);
for (k = 0; k < len; ++k) { for (k = 0; k < len; ++k) {
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
} }
} else { } else {
unsigned char header = (unsigned char) (len - 129); unsigned char header = STBIW_UCHAR(len - 129);
s->func(s->context, &header, 1); s->func(s->context, &header, 1);
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
} }
@ -467,7 +483,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
int exponent; int exponent;
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
if (maxcomp < 1e-32) { if (maxcomp < 1e-32f) {
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
} else { } else {
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
@ -481,7 +497,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
{ {
unsigned char lengthbyte = (unsigned char) (length+128); unsigned char lengthbyte = STBIW_UCHAR(length+128);
STBIW_ASSERT(length+128 <= 255); STBIW_ASSERT(length+128 <= 255);
s->func(s->context, &lengthbyte, 1); s->func(s->context, &lengthbyte, 1);
s->func(s->context, &databyte, 1); s->func(s->context, &databyte, 1);
@ -489,7 +505,7 @@ void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char dat
void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
{ {
unsigned char lengthbyte = (unsigned char )(length & 0xff); unsigned char lengthbyte = STBIW_UCHAR(length);
STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
s->func(s->context, &lengthbyte, 1); s->func(s->context, &lengthbyte, 1);
s->func(s->context, data, length); s->func(s->context, data, length);
@ -647,7 +663,7 @@ int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *da
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
{ {
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
void *p = STBIW_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2); void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
STBIW_ASSERT(p); STBIW_ASSERT(p);
if (p) { if (p) {
if (!*arr) ((int *) p)[1] = 0; if (!*arr) ((int *) p)[1] = 0;
@ -660,7 +676,7 @@ static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{ {
while (*bitcount >= 8) { while (*bitcount >= 8) {
stbiw__sbpush(data, (unsigned char) *bitbuffer); stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
*bitbuffer >>= 8; *bitbuffer >>= 8;
*bitcount -= 8; *bitcount -= 8;
} }
@ -795,7 +811,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
{ {
// compute adler32 on input // compute adler32 on input
unsigned int k=0, s1=1, s2=0; unsigned int s1=1, s2=0;
int blocklen = (int) (data_len % 5552); int blocklen = (int) (data_len % 5552);
j=0; j=0;
while (j < data_len) { while (j < data_len) {
@ -804,10 +820,10 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
j += blocklen; j += blocklen;
blocklen = 5552; blocklen = 5552;
} }
stbiw__sbpush(out, (unsigned char) (s2 >> 8)); stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
stbiw__sbpush(out, (unsigned char) s2); stbiw__sbpush(out, STBIW_UCHAR(s2));
stbiw__sbpush(out, (unsigned char) (s1 >> 8)); stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
stbiw__sbpush(out, (unsigned char) s1); stbiw__sbpush(out, STBIW_UCHAR(s1));
} }
*out_len = stbiw__sbn(out); *out_len = stbiw__sbn(out);
// make returned pointer freeable // make returned pointer freeable
@ -815,21 +831,52 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
return (unsigned char *) stbiw__sbraw(out); return (unsigned char *) stbiw__sbraw(out);
} }
unsigned int stbiw__crc32(unsigned char *buffer, int len) static unsigned int stbiw__crc32(unsigned char *buffer, int len)
{ {
static unsigned int crc_table[256]; static unsigned int crc_table[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
unsigned int crc = ~0u; unsigned int crc = ~0u;
int i,j; int i;
if (crc_table[1] == 0)
for(i=0; i < 256; i++)
for (crc_table[i]=i, j=0; j < 8; ++j)
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
for (i=0; i < len; ++i) for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc; return ~crc;
} }
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4) #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
@ -842,9 +889,9 @@ static void stbiw__wpcrc(unsigned char **data, int len)
static unsigned char stbiw__paeth(int a, int b, int c) static unsigned char stbiw__paeth(int a, int b, int c)
{ {
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
if (pa <= pb && pa <= pc) return (unsigned char) a; if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
if (pb <= pc) return (unsigned char) b; if (pb <= pc) return STBIW_UCHAR(b);
return (unsigned char) c; return STBIW_UCHAR(c);
} }
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
@ -917,7 +964,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
stbiw__wp32(o, x); stbiw__wp32(o, x);
stbiw__wp32(o, y); stbiw__wp32(o, y);
*o++ = 8; *o++ = 8;
*o++ = (unsigned char) ctype[n]; *o++ = STBIW_UCHAR(ctype[n]);
*o++ = 0; *o++ = 0;
*o++ = 0; *o++ = 0;
*o++ = 0; *o++ = 0;
@ -968,6 +1015,10 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x,
#endif // STB_IMAGE_WRITE_IMPLEMENTATION #endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history /* Revision history
1.01 (2016-01-16)
STBIW_REALLOC_SIZED: support allocators with no realloc support
avoid race-condition in crc initialization
minor compile issues
1.00 (2015-09-14) 1.00 (2015-09-14)
installable file IO function installable file IO function
0.99 (2015-09-13) 0.99 (2015-09-13)

View File

@ -1,4 +1,4 @@
// stb_truetype.h - v1.08 - public domain // stb_truetype.h - v1.09 - public domain
// authored from 2009-2015 by Sean Barrett / RAD Game Tools // authored from 2009-2015 by Sean Barrett / RAD Game Tools
// //
// This library processes TrueType files: // This library processes TrueType files:
@ -42,12 +42,15 @@
// Sergey Popov // Sergey Popov
// Giumo X. Clanjor // Giumo X. Clanjor
// Higor Euripedes // Higor Euripedes
// Thomas Fields
// Derek Vinyard
// //
// Misc other: // Misc other:
// Ryan Gordon // Ryan Gordon
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 1.09 (????-??-??) warning fix; avoid crash on outofmem
// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
// variant PackFontRanges to pack and render in separate phases; // variant PackFontRanges to pack and render in separate phases;
@ -1556,7 +1559,7 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
{ {
int x0,y0,x1,y1; int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning
if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
// e.g. space character // e.g. space character
if (ix0) *ix0 = 0; if (ix0) *ix0 = 0;
@ -1672,6 +1675,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i
{ {
stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
STBTT_assert(z != NULL);
if (!z) return z; if (!z) return z;
// round dx down to avoid overshooting // round dx down to avoid overshooting
@ -1693,6 +1697,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i
{ {
stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
STBTT_assert(z != NULL);
//STBTT_assert(e->y0 <= start_point); //STBTT_assert(e->y0 <= start_point);
if (!z) return z; if (!z) return z;
z->fdx = dxdy; z->fdx = dxdy;
@ -1817,21 +1822,23 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
while (e->y0 <= scan_y) { while (e->y0 <= scan_y) {
if (e->y1 > scan_y) { if (e->y1 > scan_y) {
stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
// find insertion point if (z != NULL) {
if (active == NULL) // find insertion point
active = z; if (active == NULL)
else if (z->x < active->x) { active = z;
// insert at front else if (z->x < active->x) {
z->next = active; // insert at front
active = z; z->next = active;
} else { active = z;
// find thing to insert AFTER } else {
stbtt__active_edge *p = active; // find thing to insert AFTER
while (p->next && p->next->x < z->x) stbtt__active_edge *p = active;
p = p->next; while (p->next && p->next->x < z->x)
// at this point, p->next->x is NOT < z->x p = p->next;
z->next = p->next; // at this point, p->next->x is NOT < z->x
p->next = z; z->next = p->next;
p->next = z;
}
} }
} }
++e; ++e;
@ -2101,10 +2108,12 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
while (e->y0 <= scan_y_bottom) { while (e->y0 <= scan_y_bottom) {
if (e->y0 != e->y1) { if (e->y0 != e->y1) {
stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
STBTT_assert(z->ey >= scan_y_top); if (z != NULL) {
// insert at front STBTT_assert(z->ey >= scan_y_top);
z->next = active; // insert at front
active = z; z->next = active;
active = z;
}
} }
++e; ++e;
} }
@ -2706,6 +2715,7 @@ static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_i
unsigned char buffer[STBTT_MAX_OVERSAMPLE]; unsigned char buffer[STBTT_MAX_OVERSAMPLE];
int safe_w = w - kernel_width; int safe_w = w - kernel_width;
int j; int j;
STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
for (j=0; j < h; ++j) { for (j=0; j < h; ++j) {
int i; int i;
unsigned int total; unsigned int total;
@ -2767,6 +2777,7 @@ static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_i
unsigned char buffer[STBTT_MAX_OVERSAMPLE]; unsigned char buffer[STBTT_MAX_OVERSAMPLE];
int safe_h = h - kernel_width; int safe_h = h - kernel_width;
int j; int j;
STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
for (j=0; j < w; ++j) { for (j=0; j < w; ++j) {
int i; int i;
unsigned int total; unsigned int total;

View File

@ -1,8 +1,11 @@
// Ogg Vorbis audio decoder - v1.06 - public domain // Ogg Vorbis audio decoder - v1.07 - public domain
// http://nothings.org/stb_vorbis/ // http://nothings.org/stb_vorbis/
// //
// Written by Sean Barrett in 2007, last updated in 2014 // Original version written by Sean Barrett in 2007.
// Sponsored by RAD Game Tools. //
// Originally sponsored by RAD Game Tools. Seeking sponsored
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software,
// Aras Pranckevicius, and Sean Barrett.
// //
// LICENSE // LICENSE
// //
@ -30,11 +33,10 @@
// Laurent Gomila Marc LeBlanc Ronny Chevalier // Laurent Gomila Marc LeBlanc Ronny Chevalier
// Bernhard Wodo Evan Balster "alxprd"@github // Bernhard Wodo Evan Balster "alxprd"@github
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot // Tom Beaumont Ingo Leitgeb Nicolas Guillemot
// (If you reported a bug but do not appear in this list, it is because // Phillip Bennefall Rohit
// someone else reported the bug before you. There were too many of you to
// list them all because I was lax about updating for a long time, sorry.)
// //
// Partial history: // Partial history:
// 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) // 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
@ -45,8 +47,6 @@
// 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
// 0.99996 - - bracket #include <malloc.h> for macintosh compilation
// 0.99995 - - avoid alias-optimization issue in float-to-int conversion
// //
// See end of file for full version history. // See end of file for full version history.
@ -155,10 +155,10 @@ extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
// specification does not bound the size of an individual frame. // specification does not bound the size of an individual frame.
extern stb_vorbis *stb_vorbis_open_pushdata( extern stb_vorbis *stb_vorbis_open_pushdata(
unsigned char *datablock, int datablock_length_in_bytes, const unsigned char * datablock, int datablock_length_in_bytes,
int *datablock_memory_consumed_in_bytes, int *datablock_memory_consumed_in_bytes,
int *error, int *error,
stb_vorbis_alloc *alloc_buffer); const stb_vorbis_alloc *alloc_buffer);
// create a vorbis decoder by passing in the initial data block containing // create a vorbis decoder by passing in the initial data block containing
// the ogg&vorbis headers (you don't need to do parse them, just provide // the ogg&vorbis headers (you don't need to do parse them, just provide
// the first N bytes of the file--you're told if it's not enough, see below) // the first N bytes of the file--you're told if it's not enough, see below)
@ -169,7 +169,8 @@ extern stb_vorbis *stb_vorbis_open_pushdata(
// incomplete and you need to pass in a larger block from the start of the file // incomplete and you need to pass in a larger block from the start of the file
extern int stb_vorbis_decode_frame_pushdata( extern int stb_vorbis_decode_frame_pushdata(
stb_vorbis *f, unsigned char *datablock, int datablock_length_in_bytes, stb_vorbis *f,
const unsigned char *datablock, int datablock_length_in_bytes,
int *channels, // place to write number of float * buffers int *channels, // place to write number of float * buffers
float ***output, // place to write float ** array of float * buffers float ***output, // place to write float ** array of float * buffers
int *samples // place to write number of output samples int *samples // place to write number of output samples
@ -233,18 +234,18 @@ extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *chan
// When you're done with it, just free() the pointer returned in *output. // When you're done with it, just free() the pointer returned in *output.
extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
int *error, stb_vorbis_alloc *alloc_buffer); int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note // create an ogg vorbis decoder from an ogg vorbis stream in memory (note
// this must be the entire stream!). on failure, returns NULL and sets *error // this must be the entire stream!). on failure, returns NULL and sets *error
#ifndef STB_VORBIS_NO_STDIO #ifndef STB_VORBIS_NO_STDIO
extern stb_vorbis * stb_vorbis_open_filename(const char *filename, extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
int *error, stb_vorbis_alloc *alloc_buffer); int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from a filename via fopen(). on failure, // create an ogg vorbis decoder from a filename via fopen(). on failure,
// returns NULL and sets *error (possibly to VORBIS_file_open_failure). // returns NULL and sets *error (possibly to VORBIS_file_open_failure).
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
int *error, stb_vorbis_alloc *alloc_buffer); int *error, const stb_vorbis_alloc *alloc_buffer);
// 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
@ -254,7 +255,7 @@ extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
// function, stb_vorbis_open_file_section(), to limit it. // function, stb_vorbis_open_file_section(), to limit it.
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close, extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
int *error, stb_vorbis_alloc *alloc_buffer, unsigned int len); int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);
// 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); the stream will be of length 'len' bytes. // the _current_ seek point (ftell); the stream will be of length 'len' bytes.
// on failure, returns NULL and sets *error. note that stb_vorbis must "own" // on failure, returns NULL and sets *error. note that stb_vorbis must "own"
@ -292,15 +293,17 @@ extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***out
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts); extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples); extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
#endif #endif
// decode the next frame and return the number of samples per channel. the // decode the next frame and return the number of *samples* per channel.
// data is coerced to the number of channels you request according to the // Note that for interleaved data, you pass in the number of shorts (the
// size of your array), but the return value is the number of samples per
// channel, not the total number of samples.
//
// The data is coerced to the number of channels you request according to the
// channel coercion rules (see below). You must pass in the size of your // channel coercion rules (see below). You must pass in the size of your
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer. // buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
// The maximum buffer size needed can be gotten from get_info(); however, // The maximum buffer size needed can be gotten from get_info(); however,
// the Vorbis I specification implies an absolute maximum of 4096 samples // the Vorbis I specification implies an absolute maximum of 4096 samples
// per channel. Note that for interleaved data, you pass in the number of // per channel.
// shorts (the size of your array), but the return value is the number of
// samples per channel, not the total number of samples.
// Channel coercion rules: // Channel coercion rules:
// Let M be the number of channels requested, and N the number of channels present, // Let M be the number of channels requested, and N the number of channels present,
@ -367,7 +370,7 @@ 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
}; };
@ -488,14 +491,8 @@ enum STBVorbisError
// trade off storage for speed. // trade off storage for speed.
//#define STB_VORBIS_DIVIDES_IN_CODEBOOK //#define STB_VORBIS_DIVIDES_IN_CODEBOOK
// STB_VORBIS_CODEBOOK_SHORTS #ifdef STB_VORBIS_CODEBOOK_SHORTS
// The vorbis file format encodes VQ codebook floats as ax+b where a and #error "STB_VORBIS_CODEBOOK_SHORTS is no longer supported as it produced incorrect results for some input formats"
// b are floating point per-codebook constants, and x is a 16-bit int.
// Normally, stb_vorbis decodes them to floats rather than leaving them
// as 16-bit ints and computing ax+b while decoding. This is a speed/space
// tradeoff; you can save space by defining this flag.
#ifndef STB_VORBIS_CODEBOOK_SHORTS
#define STB_VORBIS_CODEBOOK_FLOATS
#endif #endif
// STB_VORBIS_DIVIDE_TABLE // STB_VORBIS_DIVIDE_TABLE
@ -556,11 +553,26 @@ enum STBVorbisError
#if !(defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh)) #if !(defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh))
#include <malloc.h> #include <malloc.h>
#endif #endif
#else #else // STB_VORBIS_NO_CRT
#define NULL 0 #define NULL 0
#endif #define malloc(s) 0
#define free(s) ((void) 0)
#define realloc(s) 0
#endif // STB_VORBIS_NO_CRT
#if !defined(_MSC_VER) && !(defined(__MINGW32__) && defined(__forceinline)) #include <limits.h>
#ifdef __MINGW32__
// eff you mingw:
// "fixed":
// http://sourceforge.net/p/mingw-w64/mailman/message/32882927/
// "no that broke the build, reverted, who cares about C":
// http://sourceforge.net/p/mingw-w64/mailman/message/32890381/
#ifdef __forceinline
#undef __forceinline
#endif
#define __forceinline
#elif !defined(_MSC_VER)
#if __GNUC__ #if __GNUC__
#define __forceinline inline #define __forceinline inline
#else #else
@ -577,6 +589,13 @@ enum STBVorbisError
#endif #endif
#if 0
#include <crtdbg.h>
#define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1])
#else
#define CHECK(f) ((void) 0)
#endif
#define MAX_BLOCKSIZE_LOG 13 // from specification #define MAX_BLOCKSIZE_LOG 13 // from specification
#define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG) #define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG)
@ -593,11 +612,7 @@ typedef signed int int32;
#define FALSE 0 #define FALSE 0
#endif #endif
#ifdef STB_VORBIS_CODEBOOK_FLOATS
typedef float codetype; typedef float codetype;
#else
typedef uint16 codetype;
#endif
// @NOTE // @NOTE
// //
@ -831,13 +846,6 @@ struct stb_vorbis
int channel_buffer_end; int channel_buffer_end;
}; };
extern int my_prof(int slot);
//#define stb_prof my_prof
#ifndef stb_prof
#define stb_prof(x) ((void) 0)
#endif
#if defined(STB_VORBIS_NO_PUSHDATA_API) #if defined(STB_VORBIS_NO_PUSHDATA_API)
#define IS_PUSH_MODE(f) FALSE #define IS_PUSH_MODE(f) FALSE
#elif defined(STB_VORBIS_NO_PULLDATA_API) #elif defined(STB_VORBIS_NO_PULLDATA_API)
@ -904,7 +912,7 @@ static void *setup_malloc(vorb *f, int sz)
static void setup_free(vorb *f, void *p) static void setup_free(vorb *f, void *p)
{ {
if (f->alloc.alloc_buffer) return; // do nothing; setup mem is not a stack if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack
free(p); free(p);
} }
@ -1055,10 +1063,12 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
while (z > 0 && !available[z]) --z; while (z > 0 && !available[z]) --z;
if (z == 0) { return FALSE; } if (z == 0) { return FALSE; }
res = available[z]; res = available[z];
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 // propogate availability up the tree
if (z != len[i]) { if (z != len[i]) {
assert(len[i] >= 0 && len[i] < 32);
for (y=len[i]; y > z; --y) { for (y=len[i]; y > z; --y) {
assert(available[y] == 0); assert(available[y] == 0);
available[y] = res + (1 << (32-y)); available[y] = res + (1 << (32-y));
@ -1576,7 +1586,7 @@ enum
{ {
VORBIS_packet_id = 1, VORBIS_packet_id = 1,
VORBIS_packet_comment = 3, VORBIS_packet_comment = 3,
VORBIS_packet_setup = 5, VORBIS_packet_setup = 5
}; };
static int codebook_decode_scalar_raw(vorb *f, Codebook *c) static int codebook_decode_scalar_raw(vorb *f, Codebook *c)
@ -1584,7 +1594,9 @@ static int codebook_decode_scalar_raw(vorb *f, Codebook *c)
int i; int i;
prep_huffman(f); prep_huffman(f);
assert(c->sorted_codewords || c->codewords); if (c->codewords == NULL && c->sorted_codewords == NULL)
return -1;
// cases to use binary search: sorted_codewords && !c->codewords // cases to use binary search: sorted_codewords && !c->codewords
// sorted_codewords && c->entries > 8 // sorted_codewords && c->entries > 8
if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) { if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) {
@ -1692,15 +1704,9 @@ static int codebook_decode_scalar(vorb *f, Codebook *c)
// CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case // CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case
// where we avoid one addition // where we avoid one addition
#ifndef STB_VORBIS_CODEBOOK_FLOATS #define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off])
#define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off] * c->delta_value + c->minimum_value) #define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off])
#define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off] * c->delta_value) #define CODEBOOK_ELEMENT_BASE(c) (0)
#define CODEBOOK_ELEMENT_BASE(c) (c->minimum_value)
#else
#define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off])
#define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off])
#define CODEBOOK_ELEMENT_BASE(c) (0)
#endif
static int codebook_decode_start(vorb *f, Codebook *c) static int codebook_decode_start(vorb *f, Codebook *c)
{ {
@ -1892,7 +1898,6 @@ static int codebook_decode_deinterleave_repeat_2(vorb *f, Codebook *c, float **o
{ {
z *= c->dimensions; z *= c->dimensions;
stb_prof(11);
if (c->sequence_p) { if (c->sequence_p) {
// haven't optimized this case because I don't have any examples // haven't optimized this case because I don't have any examples
for (i=0; i < effective; ++i) { for (i=0; i < effective; ++i) {
@ -1904,7 +1909,7 @@ static int codebook_decode_deinterleave_repeat_2(vorb *f, Codebook *c, float **o
} }
} else { } else {
i=0; i=0;
if (c_inter == 1) { if (c_inter == 1 && i < effective) {
float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
if (outputs[c_inter]) if (outputs[c_inter])
outputs[c_inter][p_inter] += val; outputs[c_inter][p_inter] += val;
@ -2076,15 +2081,17 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y
#endif #endif
ady -= abs(base) * adx; ady -= abs(base) * adx;
if (x1 > n) x1 = n; if (x1 > n) x1 = n;
LINE_OP(output[x], inverse_db_table[y]); if (x < x1) {
for (++x; x < x1; ++x) {
err += ady;
if (err >= adx) {
err -= adx;
y += sy;
} else
y += base;
LINE_OP(output[x], inverse_db_table[y]); LINE_OP(output[x], inverse_db_table[y]);
for (++x; x < x1; ++x) {
err += ady;
if (err >= adx) {
err -= adx;
y += sy;
} else
y += base;
LINE_OP(output[x], inverse_db_table[y]);
}
} }
} }
@ -2123,7 +2130,8 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications)); int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications));
#endif #endif
stb_prof(2); CHECK(f);
for (i=0; i < ch; ++i) for (i=0; i < ch; ++i)
if (!do_not_decode[i]) if (!do_not_decode[i])
memset(residue_buffers[i], 0, sizeof(float) * n); memset(residue_buffers[i], 0, sizeof(float) * n);
@ -2135,11 +2143,9 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
if (j == ch) if (j == ch)
goto done; goto done;
stb_prof(3);
for (pass=0; pass < 8; ++pass) { for (pass=0; pass < 8; ++pass) {
int pcount = 0, class_set = 0; int pcount = 0, class_set = 0;
if (ch == 2) { if (ch == 2) {
stb_prof(13);
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 & 1), p_inter = z>>1; int c_inter = (z & 1), p_inter = z>>1;
@ -2157,7 +2163,6 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
} }
#endif #endif
} }
stb_prof(5);
for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
int z = r->begin + pcount*r->part_size; int z = r->begin + pcount*r->part_size;
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
@ -2168,23 +2173,20 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int b = r->residue_books[c][pass]; int b = r->residue_books[c][pass];
if (b >= 0) { if (b >= 0) {
Codebook *book = f->codebooks + b; Codebook *book = f->codebooks + b;
stb_prof(20); // accounts for X time
#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done; goto done;
#else #else
// saves 1% // saves 1%
if (!codebook_decode_deinterleave_repeat_2(f, book, residue_buffers, &c_inter, &p_inter, n, r->part_size)) if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done; goto done;
#endif #endif
stb_prof(7);
} else { } else {
z += r->part_size; z += r->part_size;
c_inter = z & 1; c_inter = z & 1;
p_inter = z >> 1; p_inter = z >> 1;
} }
} }
stb_prof(8);
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
++class_set; ++class_set;
#endif #endif
@ -2217,10 +2219,8 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int b = r->residue_books[c][pass]; int b = r->residue_books[c][pass];
if (b >= 0) { if (b >= 0) {
Codebook *book = f->codebooks + b; Codebook *book = f->codebooks + b;
stb_prof(22);
if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done; goto done;
stb_prof(3);
} else { } else {
z += r->part_size; z += r->part_size;
c_inter = 0; c_inter = 0;
@ -2259,10 +2259,8 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int b = r->residue_books[c][pass]; int b = r->residue_books[c][pass];
if (b >= 0) { if (b >= 0) {
Codebook *book = f->codebooks + b; Codebook *book = f->codebooks + b;
stb_prof(22);
if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done; goto done;
stb_prof(3);
} else { } else {
z += r->part_size; z += r->part_size;
c_inter = z % ch; c_inter = z % ch;
@ -2277,7 +2275,7 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
} }
goto done; goto done;
} }
stb_prof(9); CHECK(f);
for (pass=0; pass < 8; ++pass) { for (pass=0; pass < 8; ++pass) {
int pcount = 0, class_set=0; int pcount = 0, class_set=0;
@ -2326,7 +2324,7 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
} }
} }
done: done:
stb_prof(0); CHECK(f);
temp_alloc_restore(f,temp_alloc_point); temp_alloc_restore(f,temp_alloc_point);
} }
@ -3140,13 +3138,16 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f
int hx = g->Xlist[j]; int hx = g->Xlist[j];
if (lx != hx) if (lx != hx)
draw_line(target, lx,ly, hx,hy, n2); draw_line(target, lx,ly, hx,hy, n2);
CHECK(f);
lx = hx, ly = hy; lx = hx, ly = hy;
} }
} }
if (lx < n2) if (lx < n2) {
// optimization of: draw_line(target, lx,ly, n,ly, n2); // optimization of: draw_line(target, lx,ly, n,ly, n2);
for (j=lx; j < n2; ++j) for (j=lx; j < n2; ++j)
LINE_OP(target[j], inverse_db_table[ly]); LINE_OP(target[j], inverse_db_table[ly]);
CHECK(f);
}
} }
return TRUE; return TRUE;
} }
@ -3217,6 +3218,7 @@ static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, in
*p_right_start = window_center; *p_right_start = window_center;
*p_right_end = n; *p_right_end = n;
} }
return TRUE; return TRUE;
} }
@ -3235,7 +3237,8 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
// FLOORS // FLOORS
n2 = n >> 1; n2 = n >> 1;
stb_prof(1); CHECK(f);
for (i=0; i < f->channels; ++i) { for (i=0; i < f->channels; ++i) {
int s = map->chan[i].mux, floor; int s = map->chan[i].mux, floor;
zero_channel[i] = FALSE; zero_channel[i] = FALSE;
@ -3327,7 +3330,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
// at this point we've decoded the floor into buffer // at this point we've decoded the floor into buffer
} }
} }
stb_prof(0); CHECK(f);
// at this point we've decoded all floors // at this point we've decoded all floors
if (f->alloc.alloc_buffer) if (f->alloc.alloc_buffer)
@ -3340,6 +3343,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE; zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE;
} }
CHECK(f);
// RESIDUE DECODE // RESIDUE DECODE
for (i=0; i < map->submaps; ++i) { for (i=0; i < map->submaps; ++i) {
float *residue_buffers[STB_VORBIS_MAX_CHANNELS]; float *residue_buffers[STB_VORBIS_MAX_CHANNELS];
@ -3364,9 +3368,9 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->alloc.alloc_buffer) if (f->alloc.alloc_buffer)
assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
CHECK(f);
// INVERSE COUPLING // INVERSE COUPLING
stb_prof(14);
for (i = map->coupling_steps-1; i >= 0; --i) { for (i = map->coupling_steps-1; i >= 0; --i) {
int n2 = n >> 1; int n2 = n >> 1;
float *m = f->channel_buffers[map->chan[i].magnitude]; float *m = f->channel_buffers[map->chan[i].magnitude];
@ -3387,10 +3391,10 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
a[j] = a2; a[j] = a2;
} }
} }
CHECK(f);
// finish decoding the floors // finish decoding the floors
#ifndef STB_VORBIS_NO_DEFER_FLOOR #ifndef STB_VORBIS_NO_DEFER_FLOOR
stb_prof(15);
for (i=0; i < f->channels; ++i) { for (i=0; i < f->channels; ++i) {
if (really_zero_channel[i]) { if (really_zero_channel[i]) {
memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2); memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2);
@ -3410,10 +3414,10 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
#endif #endif
// INVERSE MDCT // INVERSE MDCT
stb_prof(16); CHECK(f);
for (i=0; i < f->channels; ++i) for (i=0; i < f->channels; ++i)
inverse_mdct(f->channel_buffers[i], n, f, m->blockflag); inverse_mdct(f->channel_buffers[i], n, f, m->blockflag);
stb_prof(0); CHECK(f);
// this shouldn't be necessary, unless we exited on an error // this shouldn't be necessary, unless we exited on an error
// and want to flush to get to the next packet // and want to flush to get to the next packet
@ -3455,7 +3459,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
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 - (n-right_end);
// 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) { if (current_end < f->current_loc + (right_end-left_start)) {
if (current_end < f->current_loc) { if (current_end < f->current_loc) {
// negative truncation, that's impossible! // negative truncation, that's impossible!
*len = 0; *len = 0;
@ -3463,6 +3467,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
*len = current_end - f->current_loc; *len = current_end - f->current_loc;
} }
*len += left_start; *len += left_start;
if (*len > right_end) *len = right_end; // this should never happen
f->current_loc += *len; f->current_loc += *len;
return TRUE; return TRUE;
} }
@ -3480,6 +3485,8 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->alloc.alloc_buffer) if (f->alloc.alloc_buffer)
assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
*len = right_end; // ignore samples after the window goes to 0 *len = right_end; // ignore samples after the window goes to 0
CHECK(f);
return TRUE; return TRUE;
} }
@ -3645,14 +3652,15 @@ static int start_decoder(vorb *f)
get32(f); // bitrate_nominal get32(f); // bitrate_nominal
get32(f); // bitrate_minimum get32(f); // bitrate_minimum
x = get8(f); x = get8(f);
{ int log0,log1; {
log0 = x & 15; int log0,log1;
log1 = x >> 4; log0 = x & 15;
f->blocksize_0 = 1 << log0; log1 = x >> 4;
f->blocksize_1 = 1 << log1; f->blocksize_0 = 1 << log0;
if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup); f->blocksize_1 = 1 << log1;
if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup); if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup);
if (log0 > log1) return error(f, VORBIS_invalid_setup); if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup);
if (log0 > log1) return error(f, VORBIS_invalid_setup);
} }
// framing_flag // framing_flag
@ -3701,6 +3709,7 @@ static int start_decoder(vorb *f)
int total=0; int total=0;
uint8 *lengths; uint8 *lengths;
Codebook *c = f->codebooks+i; Codebook *c = f->codebooks+i;
CHECK(f);
x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup); x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup);
x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup); x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup);
x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup); x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup);
@ -3712,6 +3721,8 @@ static int start_decoder(vorb *f)
ordered = get_bits(f,1); ordered = get_bits(f,1);
c->sparse = ordered ? 0 : get_bits(f,1); c->sparse = ordered ? 0 : get_bits(f,1);
if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup);
if (c->sparse) if (c->sparse)
lengths = (uint8 *) setup_temp_malloc(f, c->entries); lengths = (uint8 *) setup_temp_malloc(f, c->entries);
else else
@ -3736,6 +3747,8 @@ static int start_decoder(vorb *f)
if (present) { if (present) {
lengths[j] = get_bits(f, 5) + 1; lengths[j] = get_bits(f, 5) + 1;
++total; ++total;
if (lengths[j] == 32)
return error(f, VORBIS_invalid_setup);
} else { } else {
lengths[j] = NO_CODE; lengths[j] = NO_CODE;
} }
@ -3770,6 +3783,7 @@ static int start_decoder(vorb *f)
c->sorted_entries = sorted_count; c->sorted_entries = sorted_count;
values = NULL; values = NULL;
CHECK(f);
if (!c->sparse) { if (!c->sparse) {
c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries); c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries);
if (!c->codewords) return error(f, VORBIS_outofmem); if (!c->codewords) return error(f, VORBIS_outofmem);
@ -3815,6 +3829,7 @@ static int start_decoder(vorb *f)
compute_accelerated_huffman(c); compute_accelerated_huffman(c);
CHECK(f);
c->lookup_type = get_bits(f, 4); c->lookup_type = get_bits(f, 4);
if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup); if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup);
if (c->lookup_type > 0) { if (c->lookup_type > 0) {
@ -3828,6 +3843,7 @@ static int start_decoder(vorb *f)
} else { } else {
c->lookup_values = c->entries * c->dimensions; c->lookup_values = c->entries * c->dimensions;
} }
if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup);
mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values); mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values);
if (mults == NULL) return error(f, VORBIS_outofmem); if (mults == NULL) return error(f, VORBIS_outofmem);
for (j=0; j < (int) c->lookup_values; ++j) { for (j=0; j < (int) c->lookup_values; ++j) {
@ -3839,6 +3855,7 @@ static int start_decoder(vorb *f)
#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
if (c->lookup_type == 1) { if (c->lookup_type == 1) {
int len, sparse = c->sparse; int len, sparse = c->sparse;
float last=0;
// pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop // pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop
if (sparse) { if (sparse) {
if (c->sorted_entries == 0) goto skip; if (c->sorted_entries == 0) goto skip;
@ -3848,21 +3865,22 @@ static int start_decoder(vorb *f)
if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
len = sparse ? c->sorted_entries : c->entries; len = sparse ? c->sorted_entries : c->entries;
for (j=0; j < len; ++j) { for (j=0; j < len; ++j) {
int z = sparse ? c->sorted_values[j] : j, div=1; unsigned int z = sparse ? c->sorted_values[j] : j;
unsigned int div=1;
for (k=0; k < c->dimensions; ++k) { for (k=0; k < c->dimensions; ++k) {
int off = (z / div) % c->lookup_values; int off = (z / div) % c->lookup_values;
c->multiplicands[j*c->dimensions + k] = float val = mults[off];
#ifndef STB_VORBIS_CODEBOOK_FLOATS val = mults[off]*c->delta_value + c->minimum_value + last;
mults[off]; c->multiplicands[j*c->dimensions + k] = val;
#else if (c->sequence_p)
mults[off]*c->delta_value + c->minimum_value; last = val;
// in this case (and this case only) we could pre-expand c->sequence_p, if (k+1 < c->dimensions) {
// and throw away the decode logic for it; have to ALSO do if (div > UINT_MAX / (unsigned int) c->lookup_values) {
// it in the case below, but it can only be done if setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
// STB_VORBIS_CODEBOOK_FLOATS return error(f, VORBIS_invalid_setup);
// !STB_VORBIS_DIVIDES_IN_CODEBOOK }
#endif div *= c->lookup_values;
div *= c->lookup_values; }
} }
} }
setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
@ -3871,28 +3889,25 @@ static int start_decoder(vorb *f)
else else
#endif #endif
{ {
float last=0;
CHECK(f);
c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values); c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values);
if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
#ifndef STB_VORBIS_CODEBOOK_FLOATS for (j=0; j < (int) c->lookup_values; ++j) {
memcpy(c->multiplicands, mults, sizeof(c->multiplicands[0]) * c->lookup_values); float val = mults[j] * c->delta_value + c->minimum_value + last;
#else c->multiplicands[j] = val;
for (j=0; j < (int) c->lookup_values; ++j) if (c->sequence_p)
c->multiplicands[j] = mults[j] * c->delta_value + c->minimum_value; last = val;
#endif }
setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
} }
#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
skip:; skip:;
#endif #endif
#ifdef STB_VORBIS_CODEBOOK_FLOATS CHECK(f);
if (c->lookup_type == 2 && c->sequence_p) {
for (j=1; j < (int) c->lookup_values; ++j)
c->multiplicands[j] = c->multiplicands[j-1];
c->sequence_p = 0;
}
#endif
} }
CHECK(f);
} }
// time domain transfers (notused) // time domain transfers (notused)
@ -3988,9 +4003,11 @@ static int start_decoder(vorb *f)
if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup); if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup);
r->begin = get_bits(f, 24); r->begin = get_bits(f, 24);
r->end = get_bits(f, 24); r->end = get_bits(f, 24);
if (r->end < r->begin) return error(f, VORBIS_invalid_setup);
r->part_size = get_bits(f,24)+1; r->part_size = get_bits(f,24)+1;
r->classifications = get_bits(f,6)+1; r->classifications = get_bits(f,6)+1;
r->classbook = get_bits(f,8); r->classbook = get_bits(f,8);
if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup);
for (j=0; j < r->classifications; ++j) { for (j=0; j < r->classifications; ++j) {
uint8 high_bits=0; uint8 high_bits=0;
uint8 low_bits=get_bits(f,3); uint8 low_bits=get_bits(f,3);
@ -4171,6 +4188,7 @@ static void vorbis_deinit(stb_vorbis *p)
} }
if (p->codebooks) { if (p->codebooks) {
CHECK(p);
for (i=0; i < p->codebook_count; ++i) { for (i=0; i < p->codebook_count; ++i) {
Codebook *c = p->codebooks + i; Codebook *c = p->codebooks + i;
setup_free(p, c->codeword_lengths); setup_free(p, c->codeword_lengths);
@ -4189,6 +4207,7 @@ static void vorbis_deinit(stb_vorbis *p)
setup_free(p, p->mapping[i].chan); setup_free(p, p->mapping[i].chan);
setup_free(p, p->mapping); setup_free(p, p->mapping);
} }
CHECK(p);
for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) { for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) {
setup_free(p, p->channel_buffers[i]); setup_free(p, p->channel_buffers[i]);
setup_free(p, p->previous_window[i]); setup_free(p, p->previous_window[i]);
@ -4216,7 +4235,7 @@ void stb_vorbis_close(stb_vorbis *p)
setup_free(p,p); setup_free(p,p);
} }
static void vorbis_init(stb_vorbis *p, stb_vorbis_alloc *z) static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z)
{ {
memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start
if (z) { if (z) {
@ -4374,11 +4393,11 @@ static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len)
// return value: number of bytes we used // return value: number of bytes we used
int stb_vorbis_decode_frame_pushdata( int stb_vorbis_decode_frame_pushdata(
stb_vorbis *f, // the file we're decoding stb_vorbis *f, // the file we're decoding
uint8 *data, int data_len, // the memory available for decoding const uint8 *data, int data_len, // the memory available for decoding
int *channels, // place to write number of float * buffers int *channels, // place to write number of float * buffers
float ***output, // place to write float ** array of float * buffers float ***output, // place to write float ** array of float * buffers
int *samples // place to write number of output samples int *samples // place to write number of output samples
) )
{ {
int i; int i;
@ -4388,11 +4407,11 @@ int stb_vorbis_decode_frame_pushdata(
if (f->page_crc_tests >= 0) { if (f->page_crc_tests >= 0) {
*samples = 0; *samples = 0;
return vorbis_search_for_page_pushdata(f, data, data_len); return vorbis_search_for_page_pushdata(f, (uint8 *) data, data_len);
} }
f->stream = data; f->stream = (uint8 *) data;
f->stream_end = data + data_len; f->stream_end = (uint8 *) data + data_len;
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
@ -4444,14 +4463,14 @@ int stb_vorbis_decode_frame_pushdata(
} }
stb_vorbis *stb_vorbis_open_pushdata( stb_vorbis *stb_vorbis_open_pushdata(
unsigned char *data, int data_len, // the memory available for decoding const unsigned char *data, int data_len, // the memory available for decoding
int *data_used, // only defined if result is not NULL int *data_used, // only defined if result is not NULL
int *error, stb_vorbis_alloc *alloc) int *error, const stb_vorbis_alloc *alloc)
{ {
stb_vorbis *f, p; stb_vorbis *f, p;
vorbis_init(&p, alloc); vorbis_init(&p, alloc);
p.stream = data; p.stream = (uint8 *) data;
p.stream_end = data + data_len; p.stream_end = (uint8 *) data + data_len;
p.push_mode = TRUE; p.push_mode = TRUE;
if (!start_decoder(&p)) { if (!start_decoder(&p)) {
if (p.eof) if (p.eof)
@ -4971,7 +4990,7 @@ int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output)
#ifndef STB_VORBIS_NO_STDIO #ifndef STB_VORBIS_NO_STDIO
stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, stb_vorbis_alloc *alloc, unsigned int length) stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length)
{ {
stb_vorbis *f, p; stb_vorbis *f, p;
vorbis_init(&p, alloc); vorbis_init(&p, alloc);
@ -4992,7 +5011,7 @@ stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *er
return NULL; return NULL;
} }
stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, stb_vorbis_alloc *alloc) stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc)
{ {
unsigned int len, start; unsigned int len, start;
start = ftell(file); start = ftell(file);
@ -5002,7 +5021,7 @@ stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, stb
return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len); return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len);
} }
stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, 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 = fopen(filename, "rb");
if (f) if (f)
@ -5012,7 +5031,7 @@ stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, stb_vorb
} }
#endif // STB_VORBIS_NO_STDIO #endif // STB_VORBIS_NO_STDIO
stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, stb_vorbis_alloc *alloc) stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc)
{ {
stb_vorbis *f, p; stb_vorbis *f, p;
if (data == NULL) return NULL; if (data == NULL) return NULL;
@ -5392,6 +5411,8 @@ 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.07 - 2015/01/16 - fixed some warnings, fix mingw, const-correct API
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

View File

@ -7,7 +7,7 @@
#define STB_DEFINE #define STB_DEFINE
#include "stb.h" #include "stb.h"
#define PNGSUITE_PRIMARY //#define PNGSUITE_PRIMARY
#if 0 #if 0
void test_ycbcr(void) void test_ycbcr(void)
@ -65,7 +65,7 @@ int main(int argc, char **argv)
int w,h; int w,h;
//test_ycbcr(); //test_ycbcr();
#if 1 #if 0
// test hdr asserts // test hdr asserts
for (h=0; h < 100; h += 2) for (h=0; h < 100; h += 2)
for (w=0; w < 200; ++w) for (w=0; w < 200; ++w)
@ -81,15 +81,17 @@ int main(int argc, char **argv)
for (i=1; i < argc; ++i) { for (i=1; i < argc; ++i) {
int res; int res;
int w2,h2,n2;
unsigned char *data; unsigned char *data;
printf("%s\n", argv[i]); printf("%s\n", argv[i]);
res = stbi_info(argv[1], &w, &h, &n); res = stbi_info(argv[1], &w2, &h2, &n2);
data = stbi_load(argv[i], &w, &h, &n, 4); if (data) free(data); else printf("Failed &n\n"); data = stbi_load(argv[i], &w, &h, &n, 4); if (data) free(data); else printf("Failed &n\n");
data = stbi_load(argv[i], &w, &h, 0, 1); if (data) free(data); else printf("Failed 1\n"); data = stbi_load(argv[i], &w, &h, 0, 1); if (data) free(data); else printf("Failed 1\n");
data = stbi_load(argv[i], &w, &h, 0, 2); if (data) free(data); else printf("Failed 2\n"); data = stbi_load(argv[i], &w, &h, 0, 2); if (data) free(data); else printf("Failed 2\n");
data = stbi_load(argv[i], &w, &h, 0, 3); if (data) free(data); else printf("Failed 3\n"); data = stbi_load(argv[i], &w, &h, 0, 3); if (data) free(data); else printf("Failed 3\n");
data = stbi_load(argv[i], &w, &h, 0, 4); data = stbi_load(argv[i], &w, &h, &n, 4);
assert(data); assert(data);
assert(w == w2 && h == h2 && n == n2);
assert(res); assert(res);
if (data) { if (data) {
char fname[512]; char fname[512];

View File

@ -130,6 +130,10 @@ SOURCE=..\stb_leakcheck.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\stb_malloc.h
# End Source File
# Begin Source File
SOURCE=..\stb_perlin.h SOURCE=..\stb_perlin.h
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -8,10 +8,11 @@ extern void stb_vorbis_dumpmem(void);
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
size_t memlen; size_t memlen;
unsigned char *mem = stb_fileu("c:/x/theme_03.ogg", &memlen); unsigned char *mem = stb_fileu("c:/x/sketch008.ogg", &memlen);
int chan, samplerate; int chan, samplerate;
short *output; short *output;
int samples = stb_vorbis_decode_memory(mem, memlen, &chan, &samplerate, &output); int samples = stb_vorbis_decode_memory(mem, memlen, &chan, &samplerate, &output);
stb_filewrite("c:/x/sketch008.raw", output, samples*4);
return 0; return 0;
} }
#endif #endif