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