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