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