1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/imagiff.cpp
3 // Purpose:     wxImage handler for Amiga IFF images
4 // Author:      Steffen Gutmann, Thomas Meyer
5 // Copyright:   (c) Steffen Gutmann, 2002
6 // Licence:     wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 // Parts of this source are based on the iff loading algorithm found
10 // in xviff.c.  Permission by the original author, Thomas Meyer, and
11 // by the author of xv, John Bradley for using the iff loading part
12 // in wxWidgets has been gratefully given.
13 
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16 
17 
18 #if wxUSE_IMAGE && wxUSE_IFF
19 
20 #ifndef WX_PRECOMP
21     #include "wx/log.h"
22     #include "wx/intl.h"
23 #endif
24 
25 #include "wx/imagiff.h"
26 #include "wx/wfstream.h"
27 
28 #if wxUSE_PALETTE
29     #include "wx/palette.h"
30 #endif // wxUSE_PALETTE
31 
32 #include <stdlib.h>
33 #include <string.h>
34 
35 
36 // --------------------------------------------------------------------------
37 // Constants
38 // --------------------------------------------------------------------------
39 
40 // Error codes:
41 //  Note that the error code wxIFF_TRUNCATED means that the image itself
42 //  is most probably OK, but the decoder didn't reach the end of the data
43 //  stream; this means that if it was not reading directly from file,
44 //  the stream will not be correctly positioned.
45 //
46 
47 enum
48 {
49     wxIFF_OK = 0,                   /* everything was OK */
50     wxIFF_INVFORMAT,                /* error in iff header */
51     wxIFF_MEMERR,                   /* error allocating memory */
52     wxIFF_TRUNCATED                 /* file appears to be truncated */
53 };
54 
55 // --------------------------------------------------------------------------
56 // wxIFFDecoder class
57 // --------------------------------------------------------------------------
58 
59 // internal class for storing IFF image data
60 class IFFImage
61 {
62 public:
63     unsigned int w;                 /* width */
64     unsigned int h;                 /* height */
65     int transparent;                /* transparent color (-1 = none) */
66     int colors;                     /* number of colors */
67     unsigned char *p;               /* bitmap */
68     unsigned char *pal;             /* palette */
69 
IFFImage()70     IFFImage() : w(0), h(0), colors(0), p(0), pal(0) {}
~IFFImage()71     ~IFFImage() { delete [] p; delete [] pal; }
72 };
73 
74 class WXDLLEXPORT wxIFFDecoder
75 {
76 private:
77     IFFImage *m_image;        // image data
78     wxInputStream *m_f;       // input stream
79     unsigned char *databuf;
80     unsigned char *decomp_mem;
81 
82     void Destroy();
83 
84 public:
85     // get data of current frame
86     unsigned char* GetData() const;
87     unsigned char* GetPalette() const;
88     int GetNumColors() const;
89     unsigned int GetWidth() const;
90     unsigned int GetHeight() const;
91     int GetTransparentColour() const;
92 
93     // constructor, destructor, etc.
94     wxIFFDecoder(wxInputStream *s);
~wxIFFDecoder()95     ~wxIFFDecoder() { Destroy(); }
96 
97     // NOTE: this function modifies the current stream position
98     bool CanRead();
99 
100     int ReadIFF();
101     bool ConvertToImage(wxImage *image) const;
102 };
103 
104 
105 //---------------------------------------------------------------------------
106 // wxIFFDecoder constructor and destructor
107 //---------------------------------------------------------------------------
108 
wxIFFDecoder(wxInputStream * s)109 wxIFFDecoder::wxIFFDecoder(wxInputStream *s)
110 {
111     m_f = s;
112     m_image = 0;
113     databuf = 0;
114     decomp_mem = 0;
115 }
116 
Destroy()117 void wxIFFDecoder::Destroy()
118 {
119     wxDELETE(m_image);
120     wxDELETEA(databuf);
121     wxDELETEA(decomp_mem);
122 }
123 
124 //---------------------------------------------------------------------------
125 // Convert this image to a wxImage object
126 //---------------------------------------------------------------------------
127 
128 // This function was designed by Vaclav Slavik
129 
ConvertToImage(wxImage * image) const130 bool wxIFFDecoder::ConvertToImage(wxImage *image) const
131 {
132     // just in case...
133     image->Destroy();
134 
135     // create the image
136     image->Create(GetWidth(), GetHeight());
137 
138     if (!image->IsOk())
139         return false;
140 
141     unsigned char *pal = GetPalette();
142     unsigned char *src = GetData();
143     unsigned char *dst = image->GetData();
144     int colors = GetNumColors();
145     int transparent = GetTransparentColour();
146     long i;
147 
148     // set transparent colour mask
149     if (transparent != -1)
150     {
151         for (i = 0; i < colors; i++)
152         {
153             if ((pal[3 * i + 0] == 255) &&
154                 (pal[3 * i + 1] == 0) &&
155                 (pal[3 * i + 2] == 255))
156             {
157                 pal[3 * i + 2] = 254;
158             }
159         }
160 
161         pal[3 * transparent + 0] = 255,
162         pal[3 * transparent + 1] = 0,
163         pal[3 * transparent + 2] = 255;
164 
165         image->SetMaskColour(255, 0, 255);
166     }
167     else
168         image->SetMask(false);
169 
170 #if wxUSE_PALETTE
171     if (pal && colors > 0)
172     {
173         unsigned char* r = new unsigned char[colors];
174         unsigned char* g = new unsigned char[colors];
175         unsigned char* b = new unsigned char[colors];
176 
177         for (i = 0; i < colors; i++)
178         {
179             r[i] = pal[3*i + 0];
180             g[i] = pal[3*i + 1];
181             b[i] = pal[3*i + 2];
182         }
183 
184         image->SetPalette(wxPalette(colors, r, g, b));
185 
186         delete [] r;
187         delete [] g;
188         delete [] b;
189     }
190 #endif // wxUSE_PALETTE
191 
192     // copy image data
193     for (i = 0; i < (long)(GetWidth() * GetHeight()); i++, src += 3, dst += 3)
194     {
195     dst[0] = src[0];
196     dst[1] = src[1];
197     dst[2] = src[2];
198     }
199 
200     return true;
201 }
202 
203 
204 //---------------------------------------------------------------------------
205 // Data accessors
206 //---------------------------------------------------------------------------
207 
208 // Get data for current frame
209 
GetData() const210 unsigned char* wxIFFDecoder::GetData() const    { return (m_image->p); }
GetPalette() const211 unsigned char* wxIFFDecoder::GetPalette() const { return (m_image->pal); }
GetNumColors() const212 int wxIFFDecoder::GetNumColors() const          { return m_image->colors; }
GetWidth() const213 unsigned int wxIFFDecoder::GetWidth() const     { return (m_image->w); }
GetHeight() const214 unsigned int wxIFFDecoder::GetHeight() const    { return (m_image->h); }
GetTransparentColour() const215 int wxIFFDecoder::GetTransparentColour() const { return m_image->transparent; }
216 
217 //---------------------------------------------------------------------------
218 // IFF reading and decoding
219 //---------------------------------------------------------------------------
220 
221 //
222 // CanRead:
223 //  Returns true if the file looks like a valid IFF, false otherwise.
224 //
CanRead()225 bool wxIFFDecoder::CanRead()
226 {
227     unsigned char buf[12];
228 
229     if ( !m_f->Read(buf, WXSIZEOF(buf)) )
230         return false;
231 
232     return (memcmp(buf, "FORM", 4) == 0) && (memcmp(buf+8, "ILBM", 4) == 0);
233 }
234 
235 
236 // ReadIFF:
237 // Based on xv source code by Thomas Meyer
238 // Permission for use in wxWidgets has been gratefully given.
239 
240 typedef unsigned char byte;
241 
242 /*************************************************************************
243 void decomprle(source, destination, source length, buffer size)
244 
245 Decompress run-length encoded data from source to destination. Terminates
246 when source is decoded completely or destination buffer is full.
247 
248 The decruncher is as optimized as I could make it, without risking
249 safety in case of corrupt BODY chunks.
250 **************************************************************************/
251 
decomprle(const byte * sptr,byte * dptr,long slen,long dlen)252 static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen)
253 {
254     byte codeByte, dataByte;
255 
256     while ((slen > 0) && (dlen > 0)) {
257     // read control byte
258     codeByte = *sptr++;
259 
260     if (codeByte < 0x80) {
261         codeByte++;
262         if ((slen > (long) codeByte) && (dlen >= (long) codeByte)) {
263         slen -= codeByte + 1;
264         dlen -= codeByte;
265         while (codeByte > 0) {
266             *dptr++ = *sptr++;
267             codeByte--;
268         }
269         }
270         else slen = 0;
271     }
272 
273     else if (codeByte > 0x80) {
274         codeByte = 0x81 - (codeByte & 0x7f);
275         if ((slen > (long) 0) && (dlen >= (long) codeByte)) {
276         dataByte = *sptr++;
277         slen -= 2;
278         dlen -= codeByte;
279         while (codeByte > 0) {
280             *dptr++ = dataByte;
281             codeByte--;
282         }
283         }
284         else slen = 0;
285     }
286     }
287 }
288 
289 /******************************************/
iff_getword(const byte * ptr)290 static unsigned int iff_getword(const byte *ptr)
291 {
292     unsigned int v;
293 
294     v = *ptr++;
295     v = (v << 8) + *ptr;
296     return v;
297 }
298 
299 /******************************************/
iff_getlong(const byte * ptr)300 static unsigned long iff_getlong(const byte *ptr)
301 {
302     unsigned long l;
303 
304     l = *ptr++;
305     l = (l << 8) + *ptr++;
306     l = (l << 8) + *ptr++;
307     l = (l << 8) + *ptr;
308     return l;
309 }
310 
311 // Define internal ILBM types
312 #define ILBM_NORMAL     0
313 #define ILBM_EHB        1
314 #define ILBM_HAM        2
315 #define ILBM_HAM8       3
316 #define ILBM_24BIT      4
317 
ReadIFF()318 int wxIFFDecoder::ReadIFF()
319 {
320     Destroy();
321 
322     m_image = new IFFImage();
323     if (m_image == 0) {
324         Destroy();
325         return wxIFF_MEMERR;
326     }
327 
328     // compute file length
329     wxFileOffset currentPos = m_f->TellI();
330     if (m_f->SeekI(0, wxFromEnd) == wxInvalidOffset) {
331         Destroy();
332         return wxIFF_MEMERR;
333     }
334 
335     long filesize = m_f->TellI();
336     if (m_f->SeekI(currentPos, wxFromStart) == wxInvalidOffset) {
337         Destroy();
338         return wxIFF_MEMERR;
339     }
340 
341     // allocate memory for complete file
342     if ((databuf = new byte[filesize]) == 0) {
343         Destroy();
344         return wxIFF_MEMERR;
345     }
346 
347     m_f->Read(databuf, filesize);
348     const byte *dataend = databuf + filesize;
349 
350     // initialize work pointer. used to trace the buffer for IFF chunks
351     const byte *dataptr = databuf;
352 
353     // check for minmal size
354     if (dataptr + 12 > dataend) {
355         Destroy();
356         return wxIFF_INVFORMAT;
357     }
358 
359     // check if we really got an IFF file
360     if (strncmp(reinterpret_cast<const char*>(dataptr), "FORM", 4) != 0) {
361         Destroy();
362         return wxIFF_INVFORMAT;
363     }
364 
365     dataptr = dataptr + 8;                  // skip ID and length of FORM
366 
367     // check if the IFF file is an ILBM (picture) file
368     if (strncmp(reinterpret_cast<const char*>(dataptr), "ILBM", 4) != 0) {
369         Destroy();
370         return wxIFF_INVFORMAT;
371     }
372 
373     wxLogTrace(wxT("iff"), wxT("IFF ILBM file recognized"));
374 
375     dataptr = dataptr + 4;                                // skip ID
376 
377     //
378     // main decoding loop. searches IFF chunks and handles them.
379     // terminates when BODY chunk was found or dataptr ran over end of file
380     //
381     bool BMHDok = false, CAMGok = false;
382     int bmhd_width = 0, bmhd_height = 0, bmhd_bitplanes = 0, bmhd_transcol = -1;
383     byte bmhd_compression = 0;
384     long camg_viewmode = 0;
385     int colors = 0;
386     while (dataptr + 8 <= dataend) {
387     // get chunk length and make even
388     long chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe;
389     if (chunkLen < 0) {     // format error?
390         break;
391     }
392     bool truncated = (dataptr + 8 + chunkLen > dataend);
393 
394     if (strncmp(reinterpret_cast<const char*>(dataptr), "BMHD", 4) == 0) { // BMHD chunk?
395         if (chunkLen < 12 + 2 || truncated) {
396         break;
397         }
398         bmhd_width = iff_getword(dataptr + 8);      // width of picture
399         bmhd_height= iff_getword(dataptr + 8 + 2);  // height of picture
400         bmhd_bitplanes = *(dataptr + 8 + 8);        // # of bitplanes
401         // bmhd_masking  = *(dataptr + 8 + 9); -- unused currently
402         bmhd_compression = *(dataptr + 8 + 10);     // get compression
403         bmhd_transcol    = iff_getword(dataptr + 8 + 12);
404         BMHDok = true;                              // got BMHD
405         dataptr += 8 + chunkLen;                    // to next chunk
406     }
407     else if (strncmp(reinterpret_cast<const char*>(dataptr), "CMAP", 4) == 0) { // CMAP ?
408         if (truncated) {
409         break;
410         }
411         const byte *cmapptr = dataptr + 8;
412         colors = chunkLen / 3;                  // calc no of colors
413 
414         wxDELETEA(m_image->pal);
415         m_image->colors = colors;
416         if (colors > 0) {
417         m_image->pal = new byte[3*colors];
418         if (!m_image->pal) {
419             Destroy();
420             return wxIFF_MEMERR;
421         }
422 
423         // copy colors to color map
424         for (int i=0; i < colors; i++) {
425             m_image->pal[3*i + 0] = *cmapptr++;
426             m_image->pal[3*i + 1] = *cmapptr++;
427             m_image->pal[3*i + 2] = *cmapptr++;
428         }
429         }
430 
431         wxLogTrace(wxT("iff"), wxT("Read %d colors from IFF file."),
432             colors);
433 
434         dataptr += 8 + chunkLen;                    // to next chunk
435     } else if (strncmp(reinterpret_cast<const char*>(dataptr), "CAMG", 4) == 0) { // CAMG ?
436         if (chunkLen < 4 || truncated) {
437         break;
438         }
439         camg_viewmode = iff_getlong(dataptr + 8);   // get viewmodes
440         CAMGok = true;                              // got CAMG
441         dataptr += 8 + chunkLen;                    // to next chunk
442     }
443     else if (strncmp(reinterpret_cast<const char*>(dataptr), "BODY", 4) == 0) { // BODY ?
444         if (!BMHDok) {                              // BMHD found?
445         break;
446         }
447         const byte *bodyptr = dataptr + 8;          // -> BODY data
448 
449         if (truncated) {
450         chunkLen = dataend - dataptr;
451         }
452 
453         //
454             // if BODY is compressed, allocate buffer for decrunched BODY
455         // and decompress it (run length encoding)
456         //
457         if (bmhd_compression == 1) {
458         // calc size of decrunch buffer - (size of the actual pic.
459         // decompressed in interleaved Amiga bitplane format)
460 
461         size_t decomp_bufsize = (((bmhd_width + 15) >> 4) << 1)
462             * bmhd_height * bmhd_bitplanes;
463 
464         if ((decomp_mem = new byte[decomp_bufsize]) == 0) {
465             Destroy();
466             return wxIFF_MEMERR;
467         }
468 
469         decomprle(bodyptr, decomp_mem, chunkLen, decomp_bufsize);
470         bodyptr = decomp_mem;                 // -> uncompressed BODY
471         chunkLen = decomp_bufsize;
472         wxDELETEA(databuf);
473         }
474 
475         // the following determines the type of the ILBM file.
476         // it's either NORMAL, EHB, HAM, HAM8 or 24BIT
477 
478         int fmt = ILBM_NORMAL;                 // assume normal ILBM
479         if (bmhd_bitplanes == 24) {
480         fmt = ILBM_24BIT;
481         } else if (bmhd_bitplanes == 8) {
482         if (CAMGok && (camg_viewmode & 0x800)) {
483             fmt = ILBM_HAM8;
484         }
485         } else if ((bmhd_bitplanes > 5) && CAMGok) {
486         if (camg_viewmode & 0x80) {
487             fmt = ILBM_EHB;
488         } else if (camg_viewmode & 0x800) {
489             fmt = ILBM_HAM;
490         }
491         }
492 
493         wxLogTrace(wxT("iff"),
494             wxT("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"),
495             (fmt==ILBM_NORMAL) ? "Normal ILBM" :
496             (fmt==ILBM_HAM)    ? "HAM ILBM" :
497             (fmt==ILBM_HAM8)   ? "HAM8 ILBM" :
498             (fmt==ILBM_EHB)    ? "EHB ILBM" :
499             (fmt==ILBM_24BIT)  ? "24BIT ILBM" : "unknown ILBM",
500             bmhd_width, bmhd_height, bmhd_bitplanes,
501             1<<bmhd_bitplanes, bmhd_compression);
502 
503         if ((fmt==ILBM_NORMAL) || (fmt==ILBM_EHB) || (fmt==ILBM_HAM)) {
504         wxLogTrace(wxT("iff"),
505             wxT("Converting CMAP from normal ILBM CMAP"));
506 
507         switch(fmt) {
508             case ILBM_NORMAL: colors = 1 << bmhd_bitplanes; break;
509             case ILBM_EHB:    colors = 32*2; break;
510             case ILBM_HAM:    colors = 16; break;
511         }
512 
513         if (colors > m_image->colors) {
514             byte *pal = new byte[colors*3];
515             if (!pal) {
516             Destroy();
517             return wxIFF_MEMERR;
518             }
519             int i;
520             for (i = 0; i < m_image->colors; i++) {
521             pal[3*i + 0] = m_image->pal[3*i + 0];
522             pal[3*i + 1] = m_image->pal[3*i + 1];
523             pal[3*i + 2] = m_image->pal[3*i + 2];
524             }
525             for (; i < colors; i++) {
526             pal[3*i + 0] = 0;
527             pal[3*i + 1] = 0;
528             pal[3*i + 2] = 0;
529             }
530             delete[] m_image->pal;
531             m_image->pal = pal;
532             m_image->colors = colors;
533         }
534 
535             for (int i=0; i < colors; i++) {
536             m_image->pal[3*i + 0] = (m_image->pal[3*i + 0] >> 4) * 17;
537             m_image->pal[3*i + 1] = (m_image->pal[3*i + 1] >> 4) * 17;
538             m_image->pal[3*i + 2] = (m_image->pal[3*i + 2] >> 4) * 17;
539         }
540         }
541 
542         m_image->p = new byte[bmhd_width * bmhd_height * 3];
543         byte *picptr = m_image->p;
544         if (!picptr) {
545         Destroy();
546         return wxIFF_MEMERR;
547         }
548 
549         byte *pal = m_image->pal;
550         int lineskip = ((bmhd_width + 15) >> 4) << 1;
551             int height = chunkLen / (lineskip * bmhd_bitplanes);
552 
553         if (bmhd_height < height) {
554             height = bmhd_height;
555         }
556 
557         if (fmt == ILBM_HAM || fmt == ILBM_HAM8 || fmt == ILBM_24BIT) {
558         byte *pic = picptr;
559         const byte *workptr = bodyptr;
560 
561         for (int i=0; i < height; i++) {
562             byte bitmsk = 0x80;
563             const byte *workptr2 = workptr;
564 
565             // at start of each line, init RGB values to background
566             byte rval = pal[0];
567             byte gval = pal[1];
568             byte bval = pal[2];
569 
570             for (int j=0; j < bmhd_width; j++) {
571             long col = 0;
572             long colbit = 1;
573             const byte *workptr3 = workptr2;
574             for (int k=0; k < bmhd_bitplanes; k++) {
575                 if (*workptr3 & bitmsk) {
576                 col += colbit;
577                 }
578                 workptr3 += lineskip;
579                 colbit <<= 1;
580             }
581 
582             if (fmt==ILBM_HAM) {
583                 int c = (col & 0x0f);
584                 switch (col & 0x30) {
585                 case 0x00: if (c >= 0 && c < colors) {
586                         rval = pal[3*c + 0];
587                         gval = pal[3*c + 1];
588                         bval = pal[3*c + 2];
589                     }
590                     break;
591 
592                 case 0x10: bval = c * 17;
593                     break;
594 
595                 case 0x20: rval = c * 17;
596                     break;
597 
598                 case 0x30: gval = c * 17;
599                     break;
600                 }
601             } else if (fmt == ILBM_HAM8) {
602                 int c = (col & 0x3f);
603                 switch(col & 0xc0) {
604                 case 0x00: if (c >= 0 && c < colors) {
605                         rval = pal[3*c + 0];
606                         gval = pal[3*c + 1];
607                         bval = pal[3*c + 2];
608                     }
609                     break;
610 
611                 case 0x40: bval = (bval & 3) | (c << 2);
612                     break;
613 
614                 case 0x80: rval = (rval & 3) | (c << 2);
615                     break;
616 
617                 case 0xc0: gval = (rval & 3) | (c << 2);
618                 }
619             } else {
620                 rval = col & 0xff;
621                 gval = (col >> 8) & 0xff;
622                 bval = (col >> 16) & 0xff;
623             }
624 
625             *pic++ = rval;
626             *pic++ = gval;
627             *pic++ = bval;
628 
629             bitmsk = bitmsk >> 1;
630             if (bitmsk == 0) {
631                 bitmsk = 0x80;
632                 workptr2++;
633             }
634             }
635             workptr += lineskip * bmhd_bitplanes;
636         }
637         }  else if ((fmt == ILBM_NORMAL) || (fmt == ILBM_EHB)) {
638         if (fmt == ILBM_EHB) {
639             wxLogTrace(wxT("iff"), wxT("Doubling CMAP for EHB mode"));
640 
641             for (int i=0; i<32; i++) {
642             pal[3*(i + 32) + 0] = pal[3*i + 0] >> 1;
643             pal[3*(i + 32) + 1] = pal[3*i + 1] >> 1;
644             pal[3*(i + 32) + 2] = pal[3*i + 2] >> 1;
645             }
646         }
647 
648         byte *pic = picptr;         // ptr to buffer
649         const byte *workptr = bodyptr;  // ptr to pic, planar format
650 
651         if (bmhd_height < height) {
652             height = bmhd_height;
653         }
654 
655         for (int i=0; i < height; i++) {
656             byte bitmsk = 0x80;                 // left most bit (mask)
657             const byte *workptr2 = workptr;     // work ptr to source
658             for (int j=0; j < bmhd_width; j++) {
659             long col = 0;
660             long colbit = 1;
661             const byte *workptr3 = workptr2;  // 1st byte in 1st pln
662 
663             for (int k=0; k < bmhd_bitplanes; k++) {
664                 if (*workptr3 & bitmsk) { // if bit set in this pln
665                 col = col + colbit; // add bit to chunky byte
666                 }
667                 workptr3 += lineskip;   // go to next line
668                 colbit <<= 1;           // shift color bit
669             }
670 
671             if (col >= 0 && col < colors) {
672                 pic[0] = pal[3*col + 0];
673                 pic[1] = pal[3*col + 1];
674                 pic[2] = pal[3*col + 2];
675             } else {
676                 pic[0] = pic[1] = pic[2] = 0;
677             }
678             pic += 3;
679             bitmsk = bitmsk >> 1;   // shift mask to next bit
680             if (bitmsk == 0) {      // if mask is zero
681                 bitmsk = 0x80;      // reset mask
682                 workptr2++;         // mv ptr to next byte
683             }
684             }
685 
686             workptr += lineskip * bmhd_bitplanes;  // to next line
687         }
688         } else {
689         break;      // unknown format
690         }
691 
692         m_image->w = bmhd_width;
693         m_image->h = height;
694         m_image->transparent = bmhd_transcol;
695 
696         wxLogTrace(wxT("iff"), wxT("Loaded IFF picture %s"),
697             truncated? "truncated" : "completely");
698 
699         return (truncated? wxIFF_TRUNCATED : wxIFF_OK);
700     } else {
701         wxLogTrace(wxT("iff"), wxT("Skipping unknown chunk '%c%c%c%c'"),
702                 *dataptr, *(dataptr+1), *(dataptr+2), *(dataptr+3));
703 
704         dataptr = dataptr + 8 + chunkLen;      // skip unknown chunk
705     }
706     }
707 
708     Destroy();
709     return wxIFF_INVFORMAT;
710 }
711 
712 
713 
714 //-----------------------------------------------------------------------------
715 // wxIFFHandler
716 //-----------------------------------------------------------------------------
717 
718 wxIMPLEMENT_DYNAMIC_CLASS(wxIFFHandler, wxImageHandler);
719 
720 #if wxUSE_STREAMS
721 
LoadFile(wxImage * image,wxInputStream & stream,bool verbose,int WXUNUSED (index))722 bool wxIFFHandler::LoadFile(wxImage *image, wxInputStream& stream,
723                             bool verbose, int WXUNUSED(index))
724 {
725     wxIFFDecoder *decod;
726     int error;
727     bool ok;
728 
729     decod = new wxIFFDecoder(&stream);
730     error = decod->ReadIFF();
731 
732     if ((error != wxIFF_OK) && (error != wxIFF_TRUNCATED))
733     {
734         if (verbose)
735         {
736             switch (error)
737             {
738                 case wxIFF_INVFORMAT:
739                     wxLogError(_("IFF: error in IFF image format."));
740                     break;
741                 case wxIFF_MEMERR:
742                     wxLogError(_("IFF: not enough memory."));
743                     break;
744                 default:
745                     wxLogError(_("IFF: unknown error!!!"));
746                     break;
747             }
748         }
749         delete decod;
750         return false;
751     }
752 
753     if ((error == wxIFF_TRUNCATED) && verbose)
754     {
755         wxLogError(_("IFF: data stream seems to be truncated."));
756         /* go on; image data is OK */
757     }
758 
759     ok = decod->ConvertToImage(image);
760     delete decod;
761 
762     return ok;
763 }
764 
SaveFile(wxImage * WXUNUSED (image),wxOutputStream & WXUNUSED (stream),bool verbose)765 bool wxIFFHandler::SaveFile(wxImage * WXUNUSED(image),
766                             wxOutputStream& WXUNUSED(stream), bool verbose)
767 {
768     if (verbose)
769     {
770         wxLogDebug(wxT("IFF: the handler is read-only!!"));
771     }
772 
773     return false;
774 }
775 
DoCanRead(wxInputStream & stream)776 bool wxIFFHandler::DoCanRead(wxInputStream& stream)
777 {
778     wxIFFDecoder decod(&stream);
779 
780     return decod.CanRead();
781          // it's ok to modify the stream position here
782 }
783 
784 #endif // wxUSE_STREAMS
785 
786 #endif // wxUSE_IFF
787