check the return code of wxStream::Read() in wxImageHandler::DoCanRead()
[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 if ( !m_f->Read(buf, WXSIZEOF(buf)) )
236 return FALSE;
237
238 m_f->SeekI(-WXSIZEOF(buf), wxFromCurrent);
239
240 return (memcmp(buf, "FORM", 4) == 0) && (memcmp(buf+8, "ILBM", 4) == 0);
241 }
242
243
244 // ReadIFF:
245 // Based on xv source code by Thomas Meyer
246 // Permission for use in wxWindows has been gratefully given.
247
248 typedef unsigned char byte;
249 #define IFFDEBUG 0
250
251 /*************************************************************************
252 void decomprle(source, destination, source length, buffer size)
253
254 Decompress run-length encoded data from source to destination. Terminates
255 when source is decoded completely or destination buffer is full.
256
257 The decruncher is as optimized as I could make it, without risking
258 safety in case of corrupt BODY chunks.
259 **************************************************************************/
260
261 static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen)
262 {
263 byte codeByte, dataByte;
264
265 while ((slen > 0) && (dlen > 0)) {
266 // read control byte
267 codeByte = *sptr++;
268
269 if (codeByte < 0x80) {
270 codeByte++;
271 if ((slen > (long) codeByte) && (dlen >= (long) codeByte)) {
272 slen -= codeByte + 1;
273 dlen -= codeByte;
274 while (codeByte > 0) {
275 *dptr++ = *sptr++;
276 codeByte--;
277 }
278 }
279 else slen = 0;
280 }
281
282 else if (codeByte > 0x80) {
283 codeByte = 0x81 - (codeByte & 0x7f);
284 if ((slen > (long) 0) && (dlen >= (long) codeByte)) {
285 dataByte = *sptr++;
286 slen -= 2;
287 dlen -= codeByte;
288 while (codeByte > 0) {
289 *dptr++ = dataByte;
290 codeByte--;
291 }
292 }
293 else slen = 0;
294 }
295 }
296 }
297
298 /******************************************/
299 static unsigned int iff_getword(const byte *ptr)
300 {
301 unsigned int v;
302
303 v = *ptr++;
304 v = (v << 8) + *ptr;
305 return v;
306 }
307
308 /******************************************/
309 static unsigned long iff_getlong(const byte *ptr)
310 {
311 unsigned long l;
312
313 l = *ptr++;
314 l = (l << 8) + *ptr++;
315 l = (l << 8) + *ptr++;
316 l = (l << 8) + *ptr;
317 return l;
318 }
319
320 // Define internal ILBM types
321 #define ILBM_NORMAL 0
322 #define ILBM_EHB 1
323 #define ILBM_HAM 2
324 #define ILBM_HAM8 3
325 #define ILBM_24BIT 4
326
327 int wxIFFDecoder::ReadIFF()
328 {
329 Destroy();
330
331 m_image = new IFFImage();
332 if (m_image == 0) {
333 Destroy();
334 return wxIFF_MEMERR;
335 }
336
337 // compute file length
338 off_t currentPos = m_f->TellI();
339 m_f->SeekI(0, wxFromEnd);
340 long filesize = m_f->TellI();
341 m_f->SeekI(currentPos, wxFromStart);
342
343 // allocate memory for complete file
344 if ((databuf = new byte[filesize]) == 0) {
345 Destroy();
346 return wxIFF_MEMERR;
347 }
348
349 m_f->Read(databuf, filesize);
350 const byte *dataend = databuf + filesize;
351
352 // initialize work pointer. used to trace the buffer for IFF chunks
353 const byte *dataptr = databuf;
354
355 // check for minmal size
356 if (dataptr + 12 > dataend) {
357 Destroy();
358 return wxIFF_INVFORMAT;
359 }
360
361 // check if we really got an IFF file
362 if (strncmp((char *)dataptr, "FORM", 4) != 0) {
363 Destroy();
364 return wxIFF_INVFORMAT;
365 }
366
367 dataptr = dataptr + 8; // skip ID and length of FORM
368
369 // check if the IFF file is an ILBM (picture) file
370 if (strncmp((char *) dataptr, "ILBM", 4) != 0) {
371 Destroy();
372 return wxIFF_INVFORMAT;
373 }
374
375 wxLogTrace(_T("iff"), _T("IFF ILBM file recognized"));
376
377 dataptr = dataptr + 4; // skip ID
378
379 //
380 // main decoding loop. searches IFF chunks and handles them.
381 // terminates when BODY chunk was found or dataptr ran over end of file
382 //
383 bool BMHDok = FALSE, CMAPok = FALSE, CAMGok = FALSE;
384 int bmhd_width = 0, bmhd_height = 0, bmhd_bitplanes = 0, bmhd_transcol = -1;
385 byte bmhd_masking = 0, bmhd_compression = 0;
386 long camg_viewmode = 0;
387 int colors = 0;
388 while (dataptr + 8 <= dataend) {
389 // get chunk length and make even
390 size_t chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe;
391 #ifdef __VMS
392 // Silence compiler warning
393 int chunkLen_;
394 chunkLen_ = chunkLen;
395 if (chunkLen_ < 0) { // format error?
396 #else
397 if (chunkLen < 0) { // format error?
398 #endif
399 break;
400 }
401 bool truncated = (dataptr + 8 + chunkLen > dataend);
402
403 if (strncmp((char *)dataptr, "BMHD", 4) == 0) { // BMHD chunk?
404 if (chunkLen < 12 + 2 || truncated) {
405 break;
406 }
407 bmhd_width = iff_getword(dataptr + 8); // width of picture
408 bmhd_height= iff_getword(dataptr + 8 + 2); // height of picture
409 bmhd_bitplanes = *(dataptr + 8 + 8); // # of bitplanes
410 bmhd_masking = *(dataptr + 8 + 9);
411 bmhd_compression = *(dataptr + 8 + 10); // get compression
412 bmhd_transcol = iff_getword(dataptr + 8 + 12);
413 BMHDok = TRUE; // got BMHD
414 dataptr += 8 + chunkLen; // to next chunk
415 }
416 else if (strncmp((char *)dataptr, "CMAP", 4) == 0) { // CMAP ?
417 if (truncated) {
418 break;
419 }
420 const byte *cmapptr = dataptr + 8;
421 colors = chunkLen / 3; // calc no of colors
422
423 delete m_image->pal;
424 m_image->pal = 0;
425 m_image->colors = colors;
426 if (colors > 0) {
427 m_image->pal = new byte[3*colors];
428 if (!m_image->pal) {
429 Destroy();
430 return wxIFF_MEMERR;
431 }
432
433 // copy colors to color map
434 for (int i=0; i < colors; i++) {
435 m_image->pal[3*i + 0] = *cmapptr++;
436 m_image->pal[3*i + 1] = *cmapptr++;
437 m_image->pal[3*i + 2] = *cmapptr++;
438 }
439 }
440
441 wxLogTrace(_T("iff"), _T("Read %d colors from IFF file."),
442 colors);
443
444 CMAPok = TRUE; // got CMAP
445 dataptr += 8 + chunkLen; // to next chunk
446 } else if (strncmp((char *)dataptr, "CAMG", 4) == 0) { // CAMG ?
447 if (chunkLen < 4 || truncated) {
448 break;
449 }
450 camg_viewmode = iff_getlong(dataptr + 8); // get viewmodes
451 CAMGok = TRUE; // got CAMG
452 dataptr += 8 + chunkLen; // to next chunk
453 }
454 else if (strncmp((char *)dataptr, "BODY", 4) == 0) { // BODY ?
455 if (!BMHDok) { // BMHD found?
456 break;
457 }
458 const byte *bodyptr = dataptr + 8; // -> BODY data
459
460 if (truncated) {
461 chunkLen = dataend - dataptr;
462 }
463
464 //
465 // if BODY is compressed, allocate buffer for decrunched BODY
466 // and decompress it (run length encoding)
467 //
468 if (bmhd_compression == 1) {
469 // calc size of decrunch buffer - (size of the actual pic.
470 // decompressed in interleaved Amiga bitplane format)
471
472 size_t decomp_bufsize = (((bmhd_width + 15) >> 4) << 1)
473 * bmhd_height * bmhd_bitplanes;
474
475 if ((decomp_mem = new byte[decomp_bufsize]) == 0) {
476 Destroy();
477 return wxIFF_MEMERR;
478 }
479
480 decomprle(bodyptr, decomp_mem, chunkLen, decomp_bufsize);
481 bodyptr = decomp_mem; // -> uncompressed BODY
482 chunkLen = decomp_bufsize;
483 delete [] databuf;
484 databuf = 0;
485 }
486
487 // the following determines the type of the ILBM file.
488 // it's either NORMAL, EHB, HAM, HAM8 or 24BIT
489
490 int fmt = ILBM_NORMAL; // assume normal ILBM
491 if (bmhd_bitplanes == 24) {
492 fmt = ILBM_24BIT;
493 } else if (bmhd_bitplanes == 8) {
494 if (CAMGok && (camg_viewmode & 0x800)) {
495 fmt = ILBM_HAM8;
496 }
497 } else if ((bmhd_bitplanes > 5) && CAMGok) {
498 if (camg_viewmode & 0x80) {
499 fmt = ILBM_EHB;
500 } else if (camg_viewmode & 0x800) {
501 fmt = ILBM_HAM;
502 }
503 }
504
505 wxLogTrace(_T("iff"),
506 _T("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"),
507 (fmt==ILBM_NORMAL) ? "Normal ILBM" :
508 (fmt==ILBM_HAM) ? "HAM ILBM" :
509 (fmt==ILBM_HAM8) ? "HAM8 ILBM" :
510 (fmt==ILBM_EHB) ? "EHB ILBM" :
511 (fmt==ILBM_24BIT) ? "24BIT ILBM" : "unknown ILBM",
512 bmhd_width, bmhd_height, bmhd_bitplanes,
513 1<<bmhd_bitplanes, bmhd_compression);
514
515 if ((fmt==ILBM_NORMAL) || (fmt==ILBM_EHB) || (fmt==ILBM_HAM)) {
516 wxLogTrace(_T("iff"),
517 _T("Converting CMAP from normal ILBM CMAP"));
518
519 switch(fmt) {
520 case ILBM_NORMAL: colors = 1 << bmhd_bitplanes; break;
521 case ILBM_EHB: colors = 32*2; break;
522 case ILBM_HAM: colors = 16; break;
523 }
524
525 if (colors > m_image->colors) {
526 byte *pal = new byte[colors*3];
527 if (!pal) {
528 Destroy();
529 return wxIFF_MEMERR;
530 }
531 int i;
532 for (i = 0; i < m_image->colors; i++) {
533 pal[3*i + 0] = m_image->pal[3*i + 0];
534 pal[3*i + 1] = m_image->pal[3*i + 1];
535 pal[3*i + 2] = m_image->pal[3*i + 2];
536 }
537 for (; i < colors; i++) {
538 pal[3*i + 0] = 0;
539 pal[3*i + 1] = 0;
540 pal[3*i + 2] = 0;
541 }
542 delete m_image->pal;
543 m_image->pal = pal;
544 m_image->colors = colors;
545 }
546
547 for (int i=0; i < colors; i++) {
548 m_image->pal[3*i + 0] = (m_image->pal[3*i + 0] >> 4) * 17;
549 m_image->pal[3*i + 1] = (m_image->pal[3*i + 1] >> 4) * 17;
550 m_image->pal[3*i + 2] = (m_image->pal[3*i + 2] >> 4) * 17;
551 }
552 }
553
554 m_image->p = new byte[bmhd_width * bmhd_height * 3];
555 byte *picptr = m_image->p;
556 if (!picptr) {
557 Destroy();
558 return wxIFF_MEMERR;
559 }
560
561 byte *pal = m_image->pal;
562 int lineskip = ((bmhd_width + 15) >> 4) << 1;
563 int height = chunkLen / (lineskip * bmhd_bitplanes);
564
565 if (bmhd_height < height) {
566 height = bmhd_height;
567 }
568
569 if (fmt == ILBM_HAM || fmt == ILBM_HAM8 || fmt == ILBM_24BIT) {
570 byte *pic = picptr;
571 const byte *workptr = bodyptr;
572
573 for (int i=0; i < height; i++) {
574 byte bitmsk = 0x80;
575 const byte *workptr2 = workptr;
576
577 // at start of each line, init RGB values to background
578 byte rval = pal[0];
579 byte gval = pal[1];
580 byte bval = pal[2];
581
582 for (int j=0; j < bmhd_width; j++) {
583 long col = 0;
584 long colbit = 1;
585 const byte *workptr3 = workptr2;
586 for (int k=0; k < bmhd_bitplanes; k++) {
587 if (*workptr3 & bitmsk) {
588 col += colbit;
589 }
590 workptr3 += lineskip;
591 colbit <<= 1;
592 }
593
594 if (fmt==ILBM_HAM) {
595 int c = (col & 0x0f);
596 switch (col & 0x30) {
597 case 0x00: if (c >= 0 && c < colors) {
598 rval = pal[3*c + 0];
599 gval = pal[3*c + 1];
600 bval = pal[3*c + 2];
601 }
602 break;
603
604 case 0x10: bval = c * 17;
605 break;
606
607 case 0x20: rval = c * 17;
608 break;
609
610 case 0x30: gval = c * 17;
611 break;
612 }
613 } else if (fmt == ILBM_HAM8) {
614 int c = (col & 0x3f);
615 switch(col & 0xc0) {
616 case 0x00: if (c >= 0 && c < colors) {
617 rval = pal[3*c + 0];
618 gval = pal[3*c + 1];
619 bval = pal[3*c + 2];
620 }
621 break;
622
623 case 0x40: bval = (bval & 3) | (c << 2);
624 break;
625
626 case 0x80: rval = (rval & 3) | (c << 2);
627 break;
628
629 case 0xc0: gval = (rval & 3) | (c << 2);
630 }
631 } else {
632 rval = col & 0xff;
633 gval = (col >> 8) & 0xff;
634 bval = (col >> 16) & 0xff;
635 }
636
637 *pic++ = rval;
638 *pic++ = gval;
639 *pic++ = bval;
640
641 bitmsk = bitmsk >> 1;
642 if (bitmsk == 0) {
643 bitmsk = 0x80;
644 workptr2++;
645 }
646 }
647 workptr += lineskip * bmhd_bitplanes;
648 }
649 } else if ((fmt == ILBM_NORMAL) || (fmt == ILBM_EHB)) {
650 if (fmt == ILBM_EHB) {
651 wxLogTrace(_T("iff"), _T("Doubling CMAP for EHB mode"));
652
653 for (int i=0; i<32; i++) {
654 pal[3*(i + 32) + 0] = pal[3*i + 0] >> 1;
655 pal[3*(i + 32) + 1] = pal[3*i + 1] >> 1;
656 pal[3*(i + 32) + 2] = pal[3*i + 2] >> 1;
657 }
658 }
659
660 byte *pic = picptr; // ptr to buffer
661 const byte *workptr = bodyptr; // ptr to pic, planar format
662
663 if (bmhd_height < height) {
664 height = bmhd_height;
665 }
666
667 for (int i=0; i < height; i++) {
668 byte bitmsk = 0x80; // left most bit (mask)
669 const byte *workptr2 = workptr; // work ptr to source
670 for (int j=0; j < bmhd_width; j++) {
671 long col = 0;
672 long colbit = 1;
673 const byte *workptr3 = workptr2; // 1st byte in 1st pln
674
675 for (int k=0; k < bmhd_bitplanes; k++) {
676 if (*workptr3 & bitmsk) { // if bit set in this pln
677 col = col + colbit; // add bit to chunky byte
678 }
679 workptr3 += lineskip; // go to next line
680 colbit <<= 1; // shift color bit
681 }
682
683 if (col >= 0 && col < colors) {
684 pic[0] = pal[3*col + 0];
685 pic[1] = pal[3*col + 1];
686 pic[2] = pal[3*col + 2];
687 } else {
688 pic[0] = pic[1] = pic[2] = 0;
689 }
690 pic += 3;
691 bitmsk = bitmsk >> 1; // shift mask to next bit
692 if (bitmsk == 0) { // if mask is zero
693 bitmsk = 0x80; // reset mask
694 workptr2++; // mv ptr to next byte
695 }
696 }
697
698 workptr += lineskip * bmhd_bitplanes; // to next line
699 }
700 } else {
701 break; // unknown format
702 }
703
704 m_image->w = bmhd_width;
705 m_image->h = height;
706 m_image->transparent = bmhd_transcol;
707
708 wxLogTrace(_T("iff"), _T("Loaded IFF picture %s"),
709 truncated? "truncated" : "completely");
710
711 return (truncated? wxIFF_TRUNCATED : wxIFF_OK);
712 } else {
713 wxLogTrace(_T("iff"), _T("Skipping unknown chunk '%c%c%c%c'"),
714 *dataptr, *(dataptr+1), *(dataptr+2), *(dataptr+3));
715
716 dataptr = dataptr + 8 + chunkLen; // skip unknown chunk
717 }
718 }
719
720 Destroy();
721 return wxIFF_INVFORMAT;
722 }
723
724
725
726 //-----------------------------------------------------------------------------
727 // wxIFFHandler
728 //-----------------------------------------------------------------------------
729
730 IMPLEMENT_DYNAMIC_CLASS(wxIFFHandler, wxImageHandler)
731
732 #if wxUSE_STREAMS
733
734 bool wxIFFHandler::LoadFile(wxImage *image, wxInputStream& stream,
735 bool verbose, int WXUNUSED(index))
736 {
737 wxIFFDecoder *decod;
738 int error;
739 bool ok;
740
741 decod = new wxIFFDecoder(&stream);
742 error = decod->ReadIFF();
743
744 if ((error != wxIFF_OK) && (error != wxIFF_TRUNCATED))
745 {
746 if (verbose)
747 {
748 switch (error)
749 {
750 case wxIFF_INVFORMAT:
751 wxLogError(_("IFF: error in IFF image format."));
752 break;
753 case wxIFF_MEMERR:
754 wxLogError(_("IFF: not enough memory."));
755 break;
756 default:
757 wxLogError(_("IFF: unknown error!!!"));
758 break;
759 }
760 }
761 delete decod;
762 return FALSE;
763 }
764
765 if ((error == wxIFF_TRUNCATED) && verbose)
766 {
767 wxLogError(_("IFF: data stream seems to be truncated."));
768 /* go on; image data is OK */
769 }
770
771 ok = decod->ConvertToImage(image);
772 delete decod;
773
774 return ok;
775 }
776
777 bool wxIFFHandler::SaveFile(wxImage * WXUNUSED(image),
778 wxOutputStream& WXUNUSED(stream), bool verbose)
779 {
780 if (verbose)
781 wxLogDebug(wxT("IFF: the handler is read-only!!"));
782
783 return FALSE;
784 }
785
786 bool wxIFFHandler::DoCanRead(wxInputStream& stream)
787 {
788 wxIFFDecoder *decod;
789 bool ok;
790
791 decod = new wxIFFDecoder(&stream);
792 ok = decod->CanRead();
793 delete decod;
794
795 return ok;
796 }
797
798 #endif // wxUSE_STREAMS
799
800 #endif // wxUSE_IFF