]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/anidecod.cpp
Fix another off-by-1 bug in wxMBConv::ToWChar().
[wxWidgets.git] / src / common / anidecod.cpp
index 455dc12a4e422f4eab1e84eeeb6592017d6c611e..9d202672c66e6dd3f5c190c4830a221ed3542763 100644 (file)
@@ -14,7 +14,9 @@
     #pragma hdrstop
 #endif
 
     #pragma hdrstop
 #endif
 
-#if wxUSE_STREAMS && wxUSE_GIF
+#if wxUSE_STREAMS && wxUSE_ICO_CUR
+
+#include "wx/anidecod.h"
 
 #ifndef WX_PRECOMP
     #include "wx/palette.h"
 
 #ifndef WX_PRECOMP
     #include "wx/palette.h"
 
 #include <stdlib.h>
 #include <string.h>
 
 #include <stdlib.h>
 #include <string.h>
-#include "wx/anidecod.h"
 
 // static
 wxCURHandler wxANIDecoder::sm_handler;
 
 
 // static
 wxCURHandler wxANIDecoder::sm_handler;
 
-
-
 //---------------------------------------------------------------------------
 // wxANIFrameInfo
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 // wxANIFrameInfo
 //---------------------------------------------------------------------------
@@ -36,20 +35,18 @@ wxCURHandler wxANIDecoder::sm_handler;
 class wxANIFrameInfo
 {
 public:
 class wxANIFrameInfo
 {
 public:
-    wxANIFrameInfo(size_t delay = 0, int idx = -1)
+    wxANIFrameInfo(unsigned int delay = 0, int idx = -1)
         { m_delay=delay; m_imageIndex=idx; }
 
         { m_delay=delay; m_imageIndex=idx; }
 
-    size_t m_delay;
+    unsigned int m_delay;
     int m_imageIndex;
 };
 
     int m_imageIndex;
 };
 
-#include <wx/arrimpl.cpp> // this is a magic incantation which must be done!
-WX_DEFINE_OBJARRAY(wxImageArray);
-
-#include <wx/arrimpl.cpp> // this is a magic incantation which must be done!
-WX_DEFINE_OBJARRAY(wxANIFrameInfoArray);
-
+#include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
+WX_DEFINE_OBJARRAY(wxImageArray)
 
 
+#include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
+WX_DEFINE_OBJARRAY(wxANIFrameInfoArray)
 
 
 //---------------------------------------------------------------------------
 
 
 //---------------------------------------------------------------------------
@@ -64,9 +61,9 @@ wxANIDecoder::~wxANIDecoder()
 {
 }
 
 {
 }
 
-bool wxANIDecoder::ConvertToImage(size_t frame, wxImage *image) const
+bool wxANIDecoder::ConvertToImage(unsigned int frame, wxImage *image) const
 {
 {
-    size_t idx = m_info[frame].m_imageIndex;
+    unsigned int idx = m_info[frame].m_imageIndex;
     *image = m_images[idx];       // copy
     return image->IsOk();
 }
     *image = m_images[idx];       // copy
     return image->IsOk();
 }
@@ -76,38 +73,50 @@ bool wxANIDecoder::ConvertToImage(size_t frame, wxImage *image) const
 // Data accessors
 //---------------------------------------------------------------------------
 
 // Data accessors
 //---------------------------------------------------------------------------
 
-wxSize wxANIDecoder::GetFrameSize(size_t WXUNUSED(frame)) const
+wxSize wxANIDecoder::GetFrameSize(unsigned int WXUNUSED(frame)) const
 {
     // all frames are of the same size...
     return m_szAnimation;
 }
 
 {
     // all frames are of the same size...
     return m_szAnimation;
 }
 
-wxPoint wxANIDecoder::GetFramePosition(size_t WXUNUSED(frame)) const
+wxPoint wxANIDecoder::GetFramePosition(unsigned int WXUNUSED(frame)) const
 {
     // all frames are of the same size...
     return wxPoint(0,0);
 }
 
 {
     // all frames are of the same size...
     return wxPoint(0,0);
 }
 
-wxAnimationDisposal wxANIDecoder::GetDisposalMethod(size_t WXUNUSED(frame)) const
+wxAnimationDisposal wxANIDecoder::GetDisposalMethod(unsigned int WXUNUSED(frame)) const
 {
     // this disposal is implicit for all frames inside an ANI file
     return wxANIM_TOBACKGROUND;
 }
 
 {
     // this disposal is implicit for all frames inside an ANI file
     return wxANIM_TOBACKGROUND;
 }
 
-long wxANIDecoder::GetDelay(size_t frame) const
+long wxANIDecoder::GetDelay(unsigned int frame) const
 {
     return m_info[frame].m_delay;
 }
 
 {
     return m_info[frame].m_delay;
 }
 
+wxColour wxANIDecoder::GetTransparentColour(unsigned int frame) const
+{
+    unsigned int idx = m_info[frame].m_imageIndex;
+
+    if (!m_images[idx].HasMask())
+        return wxNullColour;
+
+    return wxColour(m_images[idx].GetMaskRed(),
+                    m_images[idx].GetMaskGreen(),
+                    m_images[idx].GetMaskBlue());
+}
+
 
 //---------------------------------------------------------------------------
 // ANI reading and decoding
 //---------------------------------------------------------------------------
 
 
 //---------------------------------------------------------------------------
 // ANI reading and decoding
 //---------------------------------------------------------------------------
 
-bool wxANIDecoder::CanRead(wxInputStream& stream) const
+bool wxANIDecoder::DoCanRead(wxInputStream& stream) const
 {
     wxInt32 FCC1, FCC2;
 {
     wxInt32 FCC1, FCC2;
-    wxUint32 datalen ;
+    wxUint32 datalen;
 
     wxInt32 riff32;
     memcpy( &riff32, "RIFF", 4 );
 
     wxInt32 riff32;
     memcpy( &riff32, "RIFF", 4 );
@@ -118,7 +127,6 @@ bool wxANIDecoder::CanRead(wxInputStream& stream) const
     wxInt32 anih32;
     memcpy( &anih32, "anih", 4 );
 
     wxInt32 anih32;
     memcpy( &anih32, "anih", 4 );
 
-    stream.SeekI(0);
     if ( !stream.Read(&FCC1, 4) )
         return false;
 
     if ( !stream.Read(&FCC1, 4) )
         return false;
 
@@ -145,7 +153,8 @@ bool wxANIDecoder::CanRead(wxInputStream& stream) const
         }
         else
         {
         }
         else
         {
-            stream.SeekI(stream.TellI() + datalen);
+            if ( stream.SeekI(stream.TellI() + datalen) == wxInvalidOffset )
+                return false;
         }
 
         // try to read next data chunk:
         }
 
         // try to read next data chunk:
@@ -171,13 +180,32 @@ struct wxANIHeader
     wxInt32 cPlanes;      // 1
     wxInt32 JifRate;      // Default Jiffies (1/60th of a second) if rate chunk not present.
     wxInt32 flags;        // Animation Flag (see AF_ constants)
     wxInt32 cPlanes;      // 1
     wxInt32 JifRate;      // Default Jiffies (1/60th of a second) if rate chunk not present.
     wxInt32 flags;        // Animation Flag (see AF_ constants)
+
+    // ANI files are always little endian so we need to swap bytes on big
+    // endian architectures
+#ifdef WORDS_BIGENDIAN
+    void AdjustEndianness()
+    {
+        // this works because all our fields are wxInt32 and they must be
+        // packed without holes between them (if they're not, they wouldn't map
+        // to the file header!)
+        wxInt32 * const start = (wxInt32 *)this;
+        wxInt32 * const end = start + sizeof(wxANIHeader)/sizeof(wxInt32);
+        for ( wxInt32 *p = start; p != end; p++ )
+        {
+            *p = wxINT32_SWAP_ALWAYS(*p);
+        }
+    }
+#else
+    void AdjustEndianness() { }
+#endif
 };
 
 bool wxANIDecoder::Load( wxInputStream& stream )
 {
     wxInt32 FCC1, FCC2;
     wxUint32 datalen;
 };
 
 bool wxANIDecoder::Load( wxInputStream& stream )
 {
     wxInt32 FCC1, FCC2;
     wxUint32 datalen;
-    size_t globaldelay=0;
+    unsigned int globaldelay=0;
 
     wxInt32 riff32;
     memcpy( &riff32, "RIFF", 4 );
 
     wxInt32 riff32;
     memcpy( &riff32, "RIFF", 4 );
@@ -192,8 +220,8 @@ bool wxANIDecoder::Load( wxInputStream& stream )
     wxInt32 seq32;
     memcpy( &seq32, "seq ", 4 );
 
     wxInt32 seq32;
     memcpy( &seq32, "seq ", 4 );
 
-    stream.SeekI(0);
-    stream.Read(&FCC1, 4);
+    if ( !stream.Read(&FCC1, 4) )
+        return false;
     if ( FCC1 != riff32 )
         return false;
 
     if ( FCC1 != riff32 )
         return false;
 
@@ -204,10 +232,12 @@ bool wxANIDecoder::Load( wxInputStream& stream )
     m_info.Clear();
 
     // we have a riff file:
     m_info.Clear();
 
     // we have a riff file:
-    while ( stream.IsOk() )
+    while ( !stream.Eof() )
     {
         // we always have a data size:
     {
         // we always have a data size:
-        stream.Read(&datalen, 4);
+        if (!stream.Read(&datalen, 4))
+            return false;
+
         datalen = wxINT32_SWAP_ON_BE(datalen);
 
         //data should be padded to make even number of bytes
         datalen = wxINT32_SWAP_ON_BE(datalen);
 
         //data should be padded to make even number of bytes
@@ -216,7 +246,8 @@ bool wxANIDecoder::Load( wxInputStream& stream )
         // now either data or a FCC:
         if ( (FCC1 == riff32) || (FCC1 == list32) )
         {
         // now either data or a FCC:
         if ( (FCC1 == riff32) || (FCC1 == list32) )
         {
-            stream.Read(&FCC2, 4);
+            if (!stream.Read(&FCC2, 4))
+                return false;
         }
         else if ( FCC1 == anih32 )
         {
         }
         else if ( FCC1 == anih32 )
         {
@@ -227,7 +258,9 @@ bool wxANIDecoder::Load( wxInputStream& stream )
                 return false;       // already parsed an ani header?
 
             struct wxANIHeader header;
                 return false;       // already parsed an ani header?
 
             struct wxANIHeader header;
-            stream.Read(&header, sizeof(wxANIHeader));
+            if (!stream.Read(&header, sizeof(wxANIHeader)))
+                return false;
+            header.AdjustEndianness();
 
             // we should have a global frame size
             m_szAnimation = wxSize(header.cx, header.cy);
 
             // we should have a global frame size
             m_szAnimation = wxSize(header.cx, header.cy);
@@ -237,7 +270,7 @@ bool wxANIDecoder::Load( wxInputStream& stream )
             if ( m_nFrames == 0 )
                 return false;
 
             if ( m_nFrames == 0 )
                 return false;
 
-            globaldelay = wxINT32_SWAP_ON_BE(header.JifRate) * 1000 / 60;
+            globaldelay = header.JifRate * 1000 / 60;
 
             m_images.Alloc(header.cFrames);
             m_info.Add(wxANIFrameInfo(), m_nFrames);
 
             m_images.Alloc(header.cFrames);
             m_info.Add(wxANIFrameInfo(), m_nFrames);
@@ -249,9 +282,10 @@ bool wxANIDecoder::Load( wxInputStream& stream )
                 return false;       // rate chunks should always be placed after anih chunk
 
             wxASSERT(m_info.GetCount() == m_nFrames);
                 return false;       // rate chunks should always be placed after anih chunk
 
             wxASSERT(m_info.GetCount() == m_nFrames);
-            for (size_t i=0; i<m_nFrames; i++)
+            for (unsigned int i=0; i<m_nFrames; i++)
             {
             {
-                stream.Read(&FCC2, 4);
+                if (!stream.Read(&FCC2, 4))
+                    return false;
                 m_info[i].m_delay = wxINT32_SWAP_ON_BE(FCC2) * 1000 / 60;
             }
         }
                 m_info[i].m_delay = wxINT32_SWAP_ON_BE(FCC2) * 1000 / 60;
             }
         }
@@ -262,9 +296,10 @@ bool wxANIDecoder::Load( wxInputStream& stream )
                 return false;       // seq chunks should always be placed after anih chunk
 
             wxASSERT(m_info.GetCount() == m_nFrames);
                 return false;       // seq chunks should always be placed after anih chunk
 
             wxASSERT(m_info.GetCount() == m_nFrames);
-            for (size_t i=0; i<m_nFrames; i++)
+            for (unsigned int i=0; i<m_nFrames; i++)
             {
             {
-                stream.Read(&FCC2, 4);
+                if (!stream.Read(&FCC2, 4))
+                    return false;
                 m_info[i].m_imageIndex = wxINT32_SWAP_ON_BE(FCC2);
             }
         }
                 m_info[i].m_imageIndex = wxINT32_SWAP_ON_BE(FCC2);
             }
         }
@@ -275,13 +310,23 @@ bool wxANIDecoder::Load( wxInputStream& stream )
             if (!sm_handler.DoLoadFile(&image, stream, false /* verbose */, -1))
                 return false;
 
             if (!sm_handler.DoLoadFile(&image, stream, false /* verbose */, -1))
                 return false;
 
+            image.SetType(wxBITMAP_TYPE_ANI);
             m_images.Add(image);
         }
         else
             m_images.Add(image);
         }
         else
-            stream.SeekI(stream.TellI() + datalen);
+        {
+            if ( stream.SeekI(stream.TellI() + datalen) == wxInvalidOffset )
+                return false;
+        }
 
         // try to read next data chunk:
 
         // try to read next data chunk:
-        stream.Read(&FCC1, 4);
+        if ( !stream.Read(&FCC1, 4) && !stream.Eof())
+        {
+            // we didn't reach the EOF! An other kind of error has occurred...
+            return false;
+        }
+        //else: proceed with the parsing of the next header block or
+        //      exiting this loop (if stream.Eof() == true)
     }
 
     if (m_nFrames==0)
     }
 
     if (m_nFrames==0)
@@ -291,14 +336,14 @@ bool wxANIDecoder::Load( wxInputStream& stream )
     {
         // if no SEQ chunk is available, display the frames in the order
         // they were loaded
     {
         // if no SEQ chunk is available, display the frames in the order
         // they were loaded
-        for (size_t i=0; i<m_nFrames; i++)
+        for (unsigned int i=0; i<m_nFrames; i++)
             if (m_info[i].m_imageIndex == -1)
                 m_info[i].m_imageIndex = i;
     }
 
     // if some frame has an invalid delay, use the global delay given in the
     // ANI header
             if (m_info[i].m_imageIndex == -1)
                 m_info[i].m_imageIndex = i;
     }
 
     // if some frame has an invalid delay, use the global delay given in the
     // ANI header
-    for (size_t i=0; i<m_nFrames; i++)
+    for (unsigned int i=0; i<m_nFrames; i++)
         if (m_info[i].m_delay == 0)
             m_info[i].m_delay = globaldelay;
 
         if (m_info[i].m_delay == 0)
             m_info[i].m_delay = globaldelay;
 
@@ -308,7 +353,7 @@ bool wxANIDecoder::Load( wxInputStream& stream )
         m_szAnimation.GetHeight() == 0)
         m_szAnimation = wxSize(m_images[0].GetWidth(), m_images[0].GetHeight());
 
         m_szAnimation.GetHeight() == 0)
         m_szAnimation = wxSize(m_images[0].GetWidth(), m_images[0].GetHeight());
 
-    return m_szAnimation!=wxDefaultSize;
+    return m_szAnimation != wxDefaultSize;
 }
 
 }
 
-#endif // wxUSE_STREAMS && wxUSE_GIF
+#endif // wxUSE_STREAMS && wxUSE_ICO_CUR