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