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