]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/imagiff.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / imagiff.cpp
index 6ceafceab0ab2b23eeb59c74d85535d6ad93f99d..635758c559d8e142c60adab30d62866d76c8865c 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        imagiff.h
+// Name:        src/common/imagiff.cpp
 // Purpose:     wxImage handler for Amiga IFF images
 // Author:      Steffen Gutmann, Thomas Meyer
 // RCS-ID:      $Id$
 // by the author of xv, John Bradley for using the iff loading part
 // in wxWidgets has been gratefully given.
 
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-#pragma implementation "imagiff.h"
-#endif
-
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-#  pragma hdrstop
+    #pragma hdrstop
 #endif
 
+#if wxUSE_IMAGE && wxUSE_IFF
+
 #ifndef WX_PRECOMP
-#  include "wx/defs.h"
+    #include "wx/log.h"
+    #include "wx/intl.h"
 #endif
 
-#if wxUSE_IMAGE && wxUSE_IFF
-
 #include "wx/imagiff.h"
 #include "wx/wfstream.h"
-#include "wx/log.h"
-#include "wx/intl.h"
 
 #if wxUSE_PALETTE
     #include "wx/palette.h"
@@ -72,7 +67,7 @@ public:
     unsigned int w;                 /* width */
     unsigned int h;                 /* height */
     int transparent;                /* transparent color (-1 = none) */
-    int colors;                            /* number of colors */
+    int colors;                     /* number of colors */
     unsigned char *p;               /* bitmap */
     unsigned char *pal;             /* palette */
 
@@ -83,10 +78,9 @@ public:
 class WXDLLEXPORT wxIFFDecoder
 {
 private:
-    IFFImage *m_image;         // image data
-    wxInputStream *m_f;        // input stream
+    IFFImage *m_image;        // image data
+    wxInputStream *m_f;       // input stream
     unsigned char *databuf;
-    unsigned char *picptr;
     unsigned char *decomp_mem;
 
     void Destroy();
@@ -103,7 +97,10 @@ public:
     // constructor, destructor, etc.
     wxIFFDecoder(wxInputStream *s);
     ~wxIFFDecoder() { Destroy(); }
+
+    // NOTE: this function modifies the current stream position
     bool CanRead();
+
     int ReadIFF();
     bool ConvertToImage(wxImage *image) const;
 };
@@ -123,12 +120,9 @@ wxIFFDecoder::wxIFFDecoder(wxInputStream *s)
 
 void wxIFFDecoder::Destroy()
 {
-    delete m_image;
-    m_image = 0;
-    delete [] databuf;
-    databuf = 0;
-    delete [] decomp_mem;
-    decomp_mem = 0;
+    wxDELETE(m_image);
+    wxDELETEA(databuf);
+    wxDELETEA(decomp_mem);
 }
 
 //---------------------------------------------------------------------------
@@ -145,8 +139,8 @@ bool wxIFFDecoder::ConvertToImage(wxImage *image) const
     // create the image
     image->Create(GetWidth(), GetHeight());
 
-    if (!image->Ok())
-        return FALSE;
+    if (!image->IsOk())
+        return false;
 
     unsigned char *pal = GetPalette();
     unsigned char *src = GetData();
@@ -175,7 +169,7 @@ bool wxIFFDecoder::ConvertToImage(wxImage *image) const
         image->SetMaskColour(255, 0, 255);
     }
     else
-        image->SetMask(FALSE);
+        image->SetMask(false);
 
 #if wxUSE_PALETTE
     if (pal && colors > 0)
@@ -207,7 +201,7 @@ bool wxIFFDecoder::ConvertToImage(wxImage *image) const
     dst[2] = src[2];
     }
 
-    return TRUE;
+    return true;
 }
 
 
@@ -230,16 +224,14 @@ int wxIFFDecoder::GetTransparentColour() const { return m_image->transparent; }
 
 //
 // CanRead:
-//  Returns TRUE if the file looks like a valid IFF, FALSE otherwise.
+//  Returns true if the file looks like a valid IFF, false otherwise.
 //
 bool wxIFFDecoder::CanRead()
 {
     unsigned char buf[12];
 
     if ( !m_f->Read(buf, WXSIZEOF(buf)) )
-        return FALSE;
-
-    m_f->SeekI(-(off_t)WXSIZEOF(buf), wxFromCurrent);
+        return false;
 
     return (memcmp(buf, "FORM", 4) == 0) && (memcmp(buf+8, "ILBM", 4) == 0);
 }
@@ -253,13 +245,13 @@ typedef unsigned char byte;
 #define IFFDEBUG 0
 
 /*************************************************************************
-  void decomprle(source, destination, source length, buffer size)
+void decomprle(source, destination, source length, buffer size)
 
-  Decompress run-length encoded data from source to destination. Terminates
-  when source is decoded completely or destination buffer is full.
+Decompress run-length encoded data from source to destination. Terminates
+when source is decoded completely or destination buffer is full.
 
-  The decruncher is as optimized as I could make it, without risking
-  safety in case of corrupt BODY chunks.
+The decruncher is as optimized as I could make it, without risking
+safety in case of corrupt BODY chunks.
 **************************************************************************/
 
 static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen)
@@ -334,20 +326,27 @@ int wxIFFDecoder::ReadIFF()
 
     m_image = new IFFImage();
     if (m_image == 0) {
-    Destroy();
-    return wxIFF_MEMERR;
+        Destroy();
+        return wxIFF_MEMERR;
     }
 
     // compute file length
-    off_t currentPos = m_f->TellI();
-    m_f->SeekI(0, wxFromEnd);
+    wxFileOffset currentPos = m_f->TellI();
+    if (m_f->SeekI(0, wxFromEnd) == wxInvalidOffset) {
+        Destroy();
+        return wxIFF_MEMERR;
+    }
+
     long filesize = m_f->TellI();
-    m_f->SeekI(currentPos, wxFromStart);
+    if (m_f->SeekI(currentPos, wxFromStart) == wxInvalidOffset) {
+        Destroy();
+        return wxIFF_MEMERR;
+    }
 
     // allocate memory for complete file
     if ((databuf = new byte[filesize]) == 0) {
-    Destroy();
-    return wxIFF_MEMERR;
+        Destroy();
+        return wxIFF_MEMERR;
     }
 
     m_f->Read(databuf, filesize);
@@ -358,25 +357,25 @@ int wxIFFDecoder::ReadIFF()
 
     // check for minmal size
     if (dataptr + 12 > dataend) {
-    Destroy();
-    return wxIFF_INVFORMAT;
+        Destroy();
+        return wxIFF_INVFORMAT;
     }
 
     // check if we really got an IFF file
     if (strncmp((char *)dataptr, "FORM", 4) != 0) {
-    Destroy();
-    return wxIFF_INVFORMAT;
+        Destroy();
+        return wxIFF_INVFORMAT;
     }
 
     dataptr = dataptr + 8;                  // skip ID and length of FORM
 
     // check if the IFF file is an ILBM (picture) file
     if (strncmp((char *) dataptr, "ILBM", 4) != 0) {
-    Destroy();
-    return wxIFF_INVFORMAT;
+        Destroy();
+        return wxIFF_INVFORMAT;
     }
 
-    wxLogTrace(_T("iff"), _T("IFF ILBM file recognized"));
+    wxLogTrace(wxT("iff"), wxT("IFF ILBM file recognized"));
 
     dataptr = dataptr + 4;                                // skip ID
 
@@ -384,23 +383,16 @@ int wxIFFDecoder::ReadIFF()
     // main decoding loop. searches IFF chunks and handles them.
     // terminates when BODY chunk was found or dataptr ran over end of file
     //
-    bool BMHDok = FALSE, CMAPok = FALSE, CAMGok = FALSE;
+    bool BMHDok = false, CAMGok = false;
     int bmhd_width = 0, bmhd_height = 0, bmhd_bitplanes = 0, bmhd_transcol = -1;
-    byte bmhd_masking = 0, bmhd_compression = 0;
+    byte bmhd_compression = 0;
     long camg_viewmode = 0;
     int colors = 0;
     while (dataptr + 8 <= dataend) {
     // get chunk length and make even
-    size_t chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe;
-#ifdef __VMS
-       // Silence compiler warning
-       int chunkLen_;
-       chunkLen_ = chunkLen;
-       if (chunkLen_ < 0) {     // format error?
-#else
-       if (chunkLen < 0) {     // format error?
-#endif
-         break;
+    long chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe;
+    if (chunkLen < 0) {     // format error?
+        break;
     }
     bool truncated = (dataptr + 8 + chunkLen > dataend);
 
@@ -411,10 +403,10 @@ int wxIFFDecoder::ReadIFF()
         bmhd_width = iff_getword(dataptr + 8);      // width of picture
         bmhd_height= iff_getword(dataptr + 8 + 2);  // height of picture
         bmhd_bitplanes = *(dataptr + 8 + 8);        // # of bitplanes
-        bmhd_masking  = *(dataptr + 8 + 9);
+        // bmhd_masking  = *(dataptr + 8 + 9); -- unused currently
         bmhd_compression = *(dataptr + 8 + 10);     // get compression
         bmhd_transcol    = iff_getword(dataptr + 8 + 12);
-        BMHDok = TRUE;                              // got BMHD
+        BMHDok = true;                              // got BMHD
         dataptr += 8 + chunkLen;                    // to next chunk
     }
     else if (strncmp((char *)dataptr, "CMAP", 4) == 0) { // CMAP ?
@@ -424,8 +416,7 @@ int wxIFFDecoder::ReadIFF()
         const byte *cmapptr = dataptr + 8;
         colors = chunkLen / 3;                  // calc no of colors
 
-        delete m_image->pal;
-        m_image->pal = 0;
+        wxDELETE(m_image->pal);
         m_image->colors = colors;
         if (colors > 0) {
         m_image->pal = new byte[3*colors];
@@ -442,17 +433,16 @@ int wxIFFDecoder::ReadIFF()
         }
         }
 
-        wxLogTrace(_T("iff"), _T("Read %d colors from IFF file."),
+        wxLogTrace(wxT("iff"), wxT("Read %d colors from IFF file."),
             colors);
 
-        CMAPok = TRUE;                              // got CMAP
         dataptr += 8 + chunkLen;                    // to next chunk
     } else if (strncmp((char *)dataptr, "CAMG", 4) == 0) { // CAMG ?
         if (chunkLen < 4 || truncated) {
         break;
         }
         camg_viewmode = iff_getlong(dataptr + 8);   // get viewmodes
-        CAMGok = TRUE;                              // got CAMG
+        CAMGok = true;                              // got CAMG
         dataptr += 8 + chunkLen;                    // to next chunk
     }
     else if (strncmp((char *)dataptr, "BODY", 4) == 0) { // BODY ?
@@ -484,8 +474,7 @@ int wxIFFDecoder::ReadIFF()
         decomprle(bodyptr, decomp_mem, chunkLen, decomp_bufsize);
         bodyptr = decomp_mem;                 // -> uncompressed BODY
         chunkLen = decomp_bufsize;
-        delete [] databuf;
-        databuf = 0;
+        wxDELETEA(databuf);
         }
 
         // the following determines the type of the ILBM file.
@@ -506,8 +495,8 @@ int wxIFFDecoder::ReadIFF()
         }
         }
 
-        wxLogTrace(_T("iff"),
-            _T("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"),
+        wxLogTrace(wxT("iff"),
+            wxT("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"),
             (fmt==ILBM_NORMAL) ? "Normal ILBM" :
             (fmt==ILBM_HAM)    ? "HAM ILBM" :
             (fmt==ILBM_HAM8)   ? "HAM8 ILBM" :
@@ -517,8 +506,8 @@ int wxIFFDecoder::ReadIFF()
             1<<bmhd_bitplanes, bmhd_compression);
 
         if ((fmt==ILBM_NORMAL) || (fmt==ILBM_EHB) || (fmt==ILBM_HAM)) {
-        wxLogTrace(_T("iff"),
-            _T("Converting CMAP from normal ILBM CMAP"));
+        wxLogTrace(wxT("iff"),
+            wxT("Converting CMAP from normal ILBM CMAP"));
 
         switch(fmt) {
             case ILBM_NORMAL: colors = 1 << bmhd_bitplanes; break;
@@ -556,7 +545,7 @@ int wxIFFDecoder::ReadIFF()
         }
 
         m_image->p = new byte[bmhd_width * bmhd_height * 3];
-            byte *picptr = m_image->p;
+        byte *picptr = m_image->p;
         if (!picptr) {
         Destroy();
         return wxIFF_MEMERR;
@@ -599,36 +588,36 @@ int wxIFFDecoder::ReadIFF()
                 int c = (col & 0x0f);
                 switch (col & 0x30) {
                 case 0x00: if (c >= 0 && c < colors) {
-                           rval = pal[3*c + 0];
-                           gval = pal[3*c + 1];
-                           bval = pal[3*c + 2];
-                       }
-                       break;
+                        rval = pal[3*c + 0];
+                        gval = pal[3*c + 1];
+                        bval = pal[3*c + 2];
+                    }
+                    break;
 
                 case 0x10: bval = c * 17;
-                       break;
+                    break;
 
                 case 0x20: rval = c * 17;
-                       break;
+                    break;
 
                 case 0x30: gval = c * 17;
-                       break;
+                    break;
                 }
             } else if (fmt == ILBM_HAM8) {
                 int c = (col & 0x3f);
                 switch(col & 0xc0) {
                 case 0x00: if (c >= 0 && c < colors) {
-                           rval = pal[3*c + 0];
-                           gval = pal[3*c + 1];
-                           bval = pal[3*c + 2];
-                       }
-                       break;
+                        rval = pal[3*c + 0];
+                        gval = pal[3*c + 1];
+                        bval = pal[3*c + 2];
+                    }
+                    break;
 
                 case 0x40: bval = (bval & 3) | (c << 2);
-                       break;
+                    break;
 
                 case 0x80: rval = (rval & 3) | (c << 2);
-                       break;
+                    break;
 
                 case 0xc0: gval = (rval & 3) | (c << 2);
                 }
@@ -652,7 +641,7 @@ int wxIFFDecoder::ReadIFF()
         }
         }  else if ((fmt == ILBM_NORMAL) || (fmt == ILBM_EHB)) {
         if (fmt == ILBM_EHB) {
-            wxLogTrace(_T("iff"), _T("Doubling CMAP for EHB mode"));
+            wxLogTrace(wxT("iff"), wxT("Doubling CMAP for EHB mode"));
 
             for (int i=0; i<32; i++) {
             pal[3*(i + 32) + 0] = pal[3*i + 0] >> 1;
@@ -709,12 +698,12 @@ int wxIFFDecoder::ReadIFF()
         m_image->h = height;
         m_image->transparent = bmhd_transcol;
 
-        wxLogTrace(_T("iff"), _T("Loaded IFF picture %s"),
+        wxLogTrace(wxT("iff"), wxT("Loaded IFF picture %s"),
             truncated? "truncated" : "completely");
 
         return (truncated? wxIFF_TRUNCATED : wxIFF_OK);
     } else {
-        wxLogTrace(_T("iff"), _T("Skipping unknown chunk '%c%c%c%c'"),
+        wxLogTrace(wxT("iff"), wxT("Skipping unknown chunk '%c%c%c%c'"),
                 *dataptr, *(dataptr+1), *(dataptr+2), *(dataptr+3));
 
         dataptr = dataptr + 8 + chunkLen;      // skip unknown chunk
@@ -763,7 +752,7 @@ bool wxIFFHandler::LoadFile(wxImage *image, wxInputStream& stream,
             }
         }
         delete decod;
-        return FALSE;
+        return false;
     }
 
     if ((error == wxIFF_TRUNCATED) && verbose)
@@ -782,9 +771,11 @@ bool wxIFFHandler::SaveFile(wxImage * WXUNUSED(image),
                             wxOutputStream& WXUNUSED(stream), bool verbose)
 {
     if (verbose)
+    {
         wxLogDebug(wxT("IFF: the handler is read-only!!"));
+    }
 
-    return FALSE;
+    return false;
 }
 
 bool wxIFFHandler::DoCanRead(wxInputStream& stream)
@@ -792,6 +783,7 @@ bool wxIFFHandler::DoCanRead(wxInputStream& stream)
     wxIFFDecoder decod(&stream);
 
     return decod.CanRead();
+         // it's ok to modify the stream position here
 }
 
 #endif // wxUSE_STREAMS