home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / imagiff.cpp < prev    next >
C/C++ Source or Header  |  2002-05-23  |  24KB  |  796 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        imagiff.h
  3. // Purpose:     wxImage handler for Amiga IFF images
  4. // Author:      Steffen Gutmann, Thomas Meyer
  5. // RCS-ID:      $Id: imagiff.cpp,v 1.6 2002/05/22 23:14:47 VZ Exp $
  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(-(off_t)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(&stream);
  789.  
  790.     return decod.CanRead();
  791. }
  792.  
  793. #endif // wxUSE_STREAMS
  794.  
  795. #endif // wxUSE_IFF
  796.