Ver código fonte

Merge branch 'working'

Sean Barrett 9 anos atrás
pai
commit
667d840860
7 arquivos alterados com 595 adições e 404 exclusões
  1. 300 199
      stb_image.h
  2. 91 40
      stb_image_write.h
  3. 32 21
      stb_truetype.h
  4. 160 139
      stb_vorbis.c
  5. 6 4
      tests/image_test.c
  6. 4 0
      tests/stb.dsp
  7. 2 1
      tests/test_vorbis.c

+ 300 - 199
stb_image.h

@@ -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
-    Sean Barrett (jpeg, png, bmp)                Marc LeBlanc
-    Nicolas Schulz (hdr, psd)                    Christpher Lloyd
-    Jonathan Dummer (tga)                        Dave Moore
-    Jean-Marc Lienher (gif)                      Won Chun
-    Tom Seddon (pic)                             the Horde3D community
-    Thatcher Ulrich (psd)                        Janez Zemva
-    Ken Miller (pgm, ppm)                        Jonathan Blow
-    urraka@github (animated gif)                 Laurent Gomila
-                                                 Aruelien Pocheville
-                                                 Ryamond Barbiero
-                                                 David Woo
- Extensions, features                            Martin Golini
-    Jetro Lauha (stbi_info)                      Roy Eltham
-    Martin "SpartanJ" Golini (stbi_info)         Luke Graham
-    James "moose2000" Brown (iPhone PNG)         Thomas Ruf
-    Ben "Disch" Wenger (io callbacks)            John Bartholomew
-    Omar Cornut (1/2/4-bit PNG)                  Ken Hamada
-    Nicolas Guillemot (vertical flip)            Cort Stratton
-    Richard Mitton (16-bit PSD)                  Blazej Dariusz Roszkowski
-                                                 Thibault Reuille
-                                                 Paul Du Bois
-                                                 Guillaume George
-                                                 Jerry Jansson
-                                                 Hayaki Saito
-                                                 Johan Duparc
-                                                 Ronny Chevalier
- Optimizations & bugfixes                        Michal Cichon
-    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
+ Image formats                          Extensions, features
+    Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info)
+    Nicolas Schulz (hdr, psd)              Martin "SpartanJ" Golini (stbi_info)
+    Jonathan Dummer (tga)                  James "moose2000" Brown (iPhone PNG)
+    Jean-Marc Lienher (gif)                Ben "Disch" Wenger (io callbacks)
+    Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG)
+    Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip)
+    Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD)
+    urraka@github (animated gif)           Junggon Kim (PNM comments)
+                                           Daniel Gibson (16-bit TGA)
+
+ Optimizations & bugfixes
+    Fabian "ryg" Giesen
+    Arseny Kapoulkine
+
+ Bug & warning fixes
+    Marc LeBlanc            David Woo          Guillaume George   Martins Mozeiko
+    Christpher Lloyd        Martin Golini      Jerry Jansson      Joseph Thomson
+    Dave Moore              Roy Eltham         Hayaki Saito       Phil Jordan
+    Won Chun                Luke Graham        Johan Duparc       Nathan Reed
+    the Horde3D community   Thomas Ruf         Ronny Chevalier    Nick Verigakis
+    Janez Zemva             John Bartholomew   Michal Cichon      svdijk@github
+    Jonathan Blow           Ken Hamada         Tero Hanninen      Baldur Karlsson
+    Laurent Gomila          Cort Stratton      Sergio Gonzalez    romigrou@github
+    Aruelien Pocheville     Thibault Reuille   Cass Everitt
+    Ryamond Barbiero        Paul Du Bois       Engin Manap
+    Blazej Dariusz Roszkowski
+    Michaelangel007@github
+
 
 
 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_REALLOC(p,sz) realloc(p,sz)
-#define STBI_FREE(p)       free(p)
+#define STBI_MALLOC(sz)           malloc(sz)
+#define STBI_REALLOC(p,newsz)     realloc(p,newsz)
+#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;
-   unsigned int mr=0,mg=0,mb=0,ma=0, all_a=255;
-   stbi_uc pal[256][4];
-   int psize=0,i,j,compress=0,width;
-   int bpp, flip_vertically, pad, target, offset, hsz;
+   int bpp, offset, hsz;
+   unsigned int mr,mg,mb,ma, all_a;
+} stbi__bmp_data;
+
+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);
-   hsz = stbi__get32le(s);
+   info->offset = 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);
-   if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
-   flip_vertically = ((int) s->img_y) > 0;
-   s->img_y = abs((int) s->img_y);
-   if (hsz == 12) {
-      if (bpp < 24)
-         psize = (offset - 14 - 24) / 3;
-   } else {
-      compress = stbi__get32le(s);
+   info->bpp = stbi__get16le(s);
+   if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
+   if (hsz != 12) {
+      int 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) {
-            mr = mg = mb = 0;
+         if (info->bpp == 16 || info->bpp == 32) {
+            info->mr = info->mg = info->mb = 0;
             if (compress == 0) {
             if (compress == 0) {
-               if (bpp == 32) {
-                  mr = 0xffu << 16;
-                  mg = 0xffu <<  8;
-                  mb = 0xffu <<  0;
-                  ma = 0xffu << 24;
-                  all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
+               if (info->bpp == 32) {
+                  info->mr = 0xffu << 16;
+                  info->mg = 0xffu <<  8;
+                  info->mb = 0xffu <<  0;
+                  info->ma = 0xffu << 24;
+                  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;
-                  mg = 31u <<  5;
-                  mb = 31u <<  0;
+                  info->mr = 31u << 10;
+                  info->mg = 31u <<  5;
+                  info->mb = 31u <<  0;
                }
                }
             } else if (compress == 3) {
             } else if (compress == 3) {
-               mr = stbi__get32le(s);
-               mg = stbi__get32le(s);
-               mb = stbi__get32le(s);
+               info->mr = stbi__get32le(s);
+               info->mg = 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);
-         mr = stbi__get32le(s);
-         mg = stbi__get32le(s);
-         mb = stbi__get32le(s);
-         ma = stbi__get32le(s);
+         int i;
+         if (hsz != 108 && hsz != 124)
+            return stbi__errpuc("bad BMP", "bad BMP");
+         info->mr = 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));
-      if (bpp == 4) width = (s->img_x + 1) >> 1;
-      else if (bpp == 8) width = s->img_x;
+      stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
+      if (info.bpp == 4) width = (s->img_x + 1) >> 1;
+      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);
-      if (bpp == 24) width = 3 * s->img_x;
-      else if (bpp == 16) width = 2*s->img_x;
+      stbi__skip(s, info.offset - 14 - info.hsz);
+      if (info.bpp == 24) width = 3 * 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 sz;
+    int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;
+    int sz, tga_colormap_type;
     stbi__get8(s);                   // discard Offset
     stbi__get8(s);                   // discard Offset
-    sz = stbi__get8(s);              // color type
-    if( sz > 1 ) {
+    tga_colormap_type = stbi__get8(s); // colormap type
+    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
-    // only RGB or grey allowed, +/- RLE
-    if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0;
-    stbi__skip(s,9);
+    tga_image_type = stbi__get8(s); // image type
+    if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
+        if (tga_image_type != 1 && tga_image_type != 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
-    // only RGB or RGBA or grey allowed
-    if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) {
-        stbi__rewind(s);
-        return 0;
+    tga_bits_per_pixel = stbi__get8(s); // bits per pixel
+    stbi__get8(s); // ignore alpha bits
+    if (tga_colormap_bpp != 0) {
+        if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
+            // 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 sz;
+   int res = 0;
+   int sz, tga_color_type;
    stbi__get8(s);      //   discard Offset
    stbi__get8(s);      //   discard Offset
-   sz = stbi__get8(s);   //   color type
-   if ( sz > 1 ) return 0;   //   only RGB or indexed allowed
+   tga_color_type = stbi__get8(s);   //   color type
+   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
-   stbi__get16be(s);      //   discard palette start
-   stbi__get16be(s);      //   discard palette length
-   stbi__get8(s);         //   discard bits per palette color entry
-   stbi__get16be(s);      //   discard x origin
-   stbi__get16be(s);      //   discard y origin
-   if ( stbi__get16be(s) < 1 ) return 0;      //   test width
-   if ( stbi__get16be(s) < 1 ) return 0;      //   test height
+   if ( tga_color_type == 1 ) { // colormapped (paletted) image
+      if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
+      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) ) goto errorEnd;
+      stbi__skip(s,4);       // skip image x and y origin
+   } else { // "normal" image w/o colormap
+      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) )
-      res = 0;
-   else
-      res = 1;
+   if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
+   if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+
+   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 )
-   {
-      tga_comp = tga_palette_bits / 8;
-   }
+   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);
+
+   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 )) {
-            STBI_FREE(tga_data);
-            STBI_FREE(tga_palette);
-            return stbi__errpuc("bad palette", "Corrupt TGA");
+         if (tga_rgb16) {
+            stbi_uc *pal_entry = tga_palette;
+            STBI_ASSERT(tga_comp == STBI_rgb);
+            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
-               int pal_idx = stbi__get8(s);
-               if ( pal_idx >= tga_palette_len )
-               {
-                  //   invalid index
+               // read in index, then perform the lookup
+               int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
+               if ( pal_idx >= tga_palette_len ) {
+                  // invalid index
                   pal_idx = 0;
                   pal_idx = 0;
                }
                }
-               pal_idx *= tga_bits_per_pixel / 8;
-               for (j = 0; j*8 < tga_bits_per_pixel; ++j)
-               {
+               pal_idx *= tga_comp;
+               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
-   if (tga_comp >= 3)
+   // swap RGB - if the source data was RGB16, it already is in the right order
+   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;
-   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') {
-       stbi__rewind( s );
-       return 0;
-   }
-   stbi__skip(s,12);
-   hsz = stbi__get32le(s);
-   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) {
-       stbi__rewind( s );
-       return 0;
-   }
-   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;
+   void *p;
+   stbi__bmp_data info;
+
+   info.all_a = 255;   
+   p = stbi__bmp_parse_header(s, &info);
+   stbi__rewind( s );
+   if (p == NULL)
+      return 0;
+   *x = s->img_x;
+   *y = s->img_y;
+   *comp = info.ma ? 4 : 3;
    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))
-      *c = (char) stbi__get8(s);
+   for (;;) {
+      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

+ 91 - 40
stb_image_write.h

@@ -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_REALLOC(p,sz) realloc(p,sz)
-#define STBIW_FREE(p)       free(p)
+#define STBIW_MALLOC(sz)        malloc(sz)
+#define STBIW_REALLOC(p,newsz)  realloc(p,newsz)
+#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[1] = (unsigned char) (x>>8);
+                     b[0] = STBIW_UCHAR(x);
+                     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[1]=(unsigned char)(x>>8);
-                     b[2]=(unsigned char)(x>>16);
-                     b[3]=(unsigned char)(x>>24);
+                     b[0]=STBIW_UCHAR(x);
+                     b[1]=STBIW_UCHAR(x>>8);
+                     b[2]=STBIW_UCHAR(x>>16);
+                     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, (unsigned char) s2);
-      stbiw__sbpush(out, (unsigned char) (s1 >> 8));
-      stbiw__sbpush(out, (unsigned char) s1);
+      stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
+      stbiw__sbpush(out, STBIW_UCHAR(s2));
+      stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
+      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;
-   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);
+   int i;
    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 (pb <= pc) return (unsigned char) b;
-   return (unsigned char) c;
+   if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
+   if (pb <= pc) return STBIW_UCHAR(b);
+   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)

+ 32 - 21
stb_truetype.h

@@ -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 (active == NULL)
-                  active = z;
-               else if (z->x < active->x) {
-                  // insert at front
-                  z->next = active;
-                  active = z;
-               } else {
-                  // find thing to insert AFTER
-                  stbtt__active_edge *p = active;
-                  while (p->next && p->next->x < z->x)
-                     p = p->next;
-                  // at this point, p->next->x is NOT < z->x
-                  z->next = p->next;
-                  p->next = z;
+               if (z != NULL) {
+                  // find insertion point
+                  if (active == NULL)
+                     active = z;
+                  else if (z->x < active->x) {
+                     // insert at front
+                     z->next = active;
+                     active = z;
+                  } else {
+                     // find thing to insert AFTER
+                     stbtt__active_edge *p = active;
+                     while (p->next && p->next->x < z->x)
+                        p = p->next;
+                     // at this point, p->next->x is NOT < z->x
+                     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);
-            // insert at front
-            z->next = active;
-            active = z;
+            if (z != NULL) {
+               STBTT_assert(z->ey >= scan_y_top);
+               // insert at front
+               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;

+ 160 - 139
stb_vorbis.c

@@ -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
-// Sponsored by RAD Game Tools.
+// Original version written by Sean Barrett in 2007.
+//
+// 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
-// 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.)
+//    Phillip Bennefall  Rohit
 //
 //
 // 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
-// data is coerced to the number of channels you request according to the
+// decode the next frame and return the number of *samples* per channel.
+// 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
-// shorts (the size of your array), but the return value is the number of
-// samples per channel, not the total number of samples.
+// per channel.
 
 
 // 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
-//     The vorbis file format encodes VQ codebook floats as ax+b where a and
-//     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
+#ifdef STB_VORBIS_CODEBOOK_SHORTS
+#error "STB_VORBIS_CODEBOOK_SHORTS is no longer supported as it produced incorrect results for some input formats"
 #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
-
-#if !defined(_MSC_VER) && !(defined(__MINGW32__) && defined(__forceinline))
+#define malloc(s)   0
+#define free(s)     ((void) 0)
+#define realloc(s)  0
+#endif // STB_VORBIS_NO_CRT
+
+#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] * c->delta_value + c->minimum_value)
-   #define CODEBOOK_ELEMENT_FAST(c,off)     (c->multiplicands[off] * c->delta_value)
-   #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
+#define CODEBOOK_ELEMENT(c,off)          (c->multiplicands[off])
+#define CODEBOOK_ELEMENT_FAST(c,off)     (c->multiplicands[off])
+#define CODEBOOK_ELEMENT_BASE(c)         (0)
 
 
 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]);
-   for (++x; x < x1; ++x) {
-      err += ady;
-      if (err >= adx) {
-         err -= adx;
-         y += sy;
-      } else
-         y += base;
+   if (x < x1) {
       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;
-   log1 = x >> 4;
-   f->blocksize_0 = 1 << log0;
-   f->blocksize_1 = 1 << log1;
-   if (log0 < 6 || log0 > 13)                       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);
+   {
+      int log0,log1;
+      log0 = x & 15;
+      log1 = x >> 4;
+      f->blocksize_0 = 1 << log0;
+      f->blocksize_1 = 1 << log1;
+      if (log0 < 6 || log0 > 13)                       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] =
-                         #ifndef STB_VORBIS_CODEBOOK_FLOATS
-                            mults[off];
-                         #else
-                            mults[off]*c->delta_value + c->minimum_value;
-                            // in this case (and this case only) we could pre-expand c->sequence_p,
-                            // and throw away the decode logic for it; have to ALSO do
-                            // it in the case below, but it can only be done if
-                            //    STB_VORBIS_CODEBOOK_FLOATS
-                            //   !STB_VORBIS_DIVIDES_IN_CODEBOOK
-                         #endif
-                  div *= c->lookup_values;
+                  float val = mults[off];
+                  val = mults[off]*c->delta_value + c->minimum_value + last;
+                  c->multiplicands[j*c->dimensions + k] = val;
+                  if (c->sequence_p)
+                     last = val;
+                  if (k+1 < c->dimensions) {
+                     if (div > UINT_MAX / (unsigned int) c->lookup_values) {
+                        setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
+                        return error(f, VORBIS_invalid_setup);
+                     }
+                     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
-            memcpy(c->multiplicands, mults, sizeof(c->multiplicands[0]) * c->lookup_values);
-            #else
-            for (j=0; j < (int) c->lookup_values; ++j)
-               c->multiplicands[j] = mults[j] * c->delta_value + c->minimum_value;
-            #endif
+            for (j=0; j < (int) c->lookup_values; ++j) {
+               float val = mults[j] * c->delta_value + c->minimum_value + last;
+               c->multiplicands[j] = val;
+               if (c->sequence_p)
+                  last = val;
+            }
             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
-         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);
       }
       }
+      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
-         uint8 *data, int data_len,     // the memory available for decoding
-         int *channels,                 // place to write number of float * buffers
-         float ***output,               // place to write float ** array of float * buffers
-         int *samples                   // place to write number of output samples
+         stb_vorbis *f,                   // the file we're decoding
+         const uint8 *data, int data_len, // the memory available for decoding
+         int *channels,                   // place to write number of float * buffers
+         float ***output,                 // place to write float ** array of float * buffers
+         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_end = data + data_len;
+   f->stream     = (uint8 *) data;
+   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_end = data + data_len;
+   p.stream     = (uint8 *) data;
+   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

+ 6 - 4
tests/image_test.c

@@ -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];

+ 4 - 0
tests/stb.dsp

@@ -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

+ 2 - 1
tests/test_vorbis.c

@@ -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