Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Routines for reading and writing IFF files
  23.  *
  24.  */
  25.  
  26. #define COMPRESS                1       //do the RLE or not? (for debugging mostly)
  27. #define WRITE_TINY      0       //should we write a TINY chunk?
  28.  
  29. #define MIN_COMPRESS_WIDTH      65      //don't compress if less than this wide
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34.  
  35. #include "u_mem.h"
  36. #include "iff.h"
  37. #include "dxxerror.h"
  38. #include "makesig.h"
  39. #include "physfsx.h"
  40. #include "gr.h"
  41.  
  42. #include "dxxsconf.h"
  43. #include "compiler-range_for.h"
  44. #include "partial_range.h"
  45. #include <memory>
  46.  
  47. //Internal constants and structures for this library
  48.  
  49. //Type values for bitmaps
  50. #define TYPE_PBM                0
  51. #define TYPE_ILBM               1
  52.  
  53. //Compression types
  54. #define cmpNone 0
  55. #define cmpByteRun1     1
  56.  
  57. //Masking types
  58. #define mskNone 0
  59. #define mskHasMask      1
  60. #define mskHasTransparentColor 2
  61.  
  62. //structure of the header in the file
  63. struct iff_bitmap_header : prohibit_void_ptr<iff_bitmap_header>
  64. {
  65.         short w,h;                                              //width and height of this bitmap
  66.         short x,y;                                              //generally unused
  67.         short type;                                             //see types above
  68.         short transparentcolor;         //which color is transparent (if any)
  69.         short pagewidth,pageheight; //width & height of source screen
  70.         sbyte nplanes;              //number of planes (8 for 256 color image)
  71.         sbyte masking,compression;  //see constants above
  72.         sbyte xaspect,yaspect;      //aspect ratio (usually 5/6)
  73.         palette_array_t palette;                //the palette for this bitmap
  74.         short row_size;                         //offset to next row
  75.         RAIIdmem<uint8_t[]> raw_data;                           //ptr to array of data
  76. };
  77.  
  78. ubyte iff_transparent_color;
  79. ubyte iff_has_transparency;     // 0=no transparency, 1=iff_transparent_color is valid
  80.  
  81. #define form_sig MAKE_SIG('F','O','R','M')
  82. #define ilbm_sig MAKE_SIG('I','L','B','M')
  83. #define body_sig MAKE_SIG('B','O','D','Y')
  84. #define pbm_sig  MAKE_SIG('P','B','M',' ')
  85. #define bmhd_sig MAKE_SIG('B','M','H','D')
  86. #define anhd_sig MAKE_SIG('A','N','H','D')
  87. #define cmap_sig MAKE_SIG('C','M','A','P')
  88. #define tiny_sig MAKE_SIG('T','I','N','Y')
  89. #define anim_sig MAKE_SIG('A','N','I','M')
  90. #define dlta_sig MAKE_SIG('D','L','T','A')
  91.  
  92. static int32_t get_sig(PHYSFS_File *f)
  93. {
  94.         int s;
  95.  
  96.         PHYSFS_readSBE32(f, &s);
  97.         return s;
  98. }
  99.  
  100. #define put_sig(sig, f) PHYSFS_writeSBE32(f, sig)
  101.  
  102. static int parse_bmhd(PHYSFS_File *ifile,long len,iff_bitmap_header *bmheader)
  103. {
  104.         len++;  /* so no "parm not used" warning */
  105.  
  106. //  debug("parsing bmhd len=%ld\n",len);
  107.  
  108.         PHYSFS_readSBE16(ifile, &bmheader->w);
  109.         PHYSFS_readSBE16(ifile, &bmheader->h);
  110.         PHYSFS_readSBE16(ifile, &bmheader->x);
  111.         PHYSFS_readSBE16(ifile, &bmheader->y);
  112.        
  113.         bmheader->nplanes = PHYSFSX_readByte(ifile);
  114.         bmheader->masking = PHYSFSX_readByte(ifile);
  115.         bmheader->compression = PHYSFSX_readByte(ifile);
  116.         PHYSFSX_readByte(ifile);        /* skip pad */
  117.        
  118.         PHYSFS_readSBE16(ifile, &bmheader->transparentcolor);
  119.         bmheader->xaspect = PHYSFSX_readByte(ifile);
  120.         bmheader->yaspect = PHYSFSX_readByte(ifile);
  121.        
  122.         PHYSFS_readSBE16(ifile, &bmheader->pagewidth);
  123.         PHYSFS_readSBE16(ifile, &bmheader->pageheight);
  124.  
  125.         iff_transparent_color = bmheader->transparentcolor;
  126.  
  127.         iff_has_transparency = 0;
  128.  
  129.         if (bmheader->masking == mskHasTransparentColor)
  130.                 iff_has_transparency = 1;
  131.  
  132.         else if (bmheader->masking != mskNone && bmheader->masking != mskHasMask)
  133.                 return IFF_UNKNOWN_MASK;
  134.  
  135. //  debug("w,h=%d,%d x,y=%d,%d\n",w,h,x,y);
  136. //  debug("nplanes=%d, masking=%d ,compression=%d, transcolor=%d\n",nplanes,masking,compression,transparentcolor);
  137.  
  138.         return IFF_NO_ERROR;
  139. }
  140.  
  141.  
  142. //  the buffer pointed to by raw_data is stuffed with a pointer to decompressed pixel data
  143. namespace dsx {
  144. static int parse_body(PHYSFS_File *ifile,long len,iff_bitmap_header *bmheader)
  145. {
  146.         auto p = bmheader->raw_data.get();
  147.         int width,depth;
  148.         signed char n;
  149.         int nn,wid_cnt,end_cnt,plane;
  150.         unsigned char *data_end;
  151.         int end_pos;
  152.         #ifndef NDEBUG
  153.         int row_count=0;
  154.         #endif
  155.  
  156.         width=0;
  157.         depth=0;
  158.  
  159.         end_pos = PHYSFS_tell(ifile) + len;
  160.         if (len&1)
  161.                 end_pos++;
  162.  
  163.         if (bmheader->type == TYPE_PBM) {
  164.                 width=bmheader->w;
  165.                 depth=1;
  166.         } else if (bmheader->type == TYPE_ILBM) {
  167.                 width = (bmheader->w+7)/8;
  168.                 depth=bmheader->nplanes;
  169.         }
  170.  
  171.         end_cnt = (width&1)?-1:0;
  172.  
  173.         data_end = p + width*bmheader->h*depth;
  174.  
  175.         if (bmheader->compression == cmpNone) {        /* no compression */
  176.                 int y;
  177.  
  178.                 for (y=bmheader->h;y;y--) {
  179.                         PHYSFS_read(ifile, p, width, depth);
  180.                         p += bmheader->w;
  181.  
  182.                         if (bmheader->masking == mskHasMask)
  183.                                 PHYSFSX_fseek(ifile, width, SEEK_CUR);                          //skip mask!
  184.  
  185.                         if (bmheader->w & 1) PHYSFSX_fgetc(ifile);
  186.                 }
  187.  
  188.                 //cnt = len - bmheader->h * ((bmheader->w+1)&~1);
  189.  
  190.         }
  191.         else if (bmheader->compression == cmpByteRun1)
  192.                 for (wid_cnt=width,plane=0; PHYSFS_tell(ifile) < end_pos && p<data_end;) {
  193.                         unsigned char c;
  194.  
  195.                         if (wid_cnt == end_cnt) {
  196.                                 wid_cnt = width;
  197.                                 plane++;
  198.                                 if ((bmheader->masking == mskHasMask && plane==depth+1) ||
  199.                                     (bmheader->masking != mskHasMask && plane==depth))
  200.                                         plane=0;
  201.                         }
  202.  
  203.                         Assert(wid_cnt > end_cnt);
  204.  
  205.                         n=PHYSFSX_fgetc(ifile);
  206.  
  207.                         if (n >= 0) {                       // copy next n+1 bytes from source, they are not compressed
  208.                                 nn = static_cast<int>(n)+1;
  209.                                 wid_cnt -= nn;
  210.                                 if (wid_cnt==-1) {--nn; Assert(width&1);}
  211.                                 if (plane==depth)       //masking row
  212.                                         PHYSFSX_fseek(ifile, nn, SEEK_CUR);
  213.                                 else
  214.                                 {
  215.                                         PHYSFS_read(ifile, p, nn, 1);
  216.                                         p += nn;
  217.                                 }
  218.                                 if (wid_cnt==-1) PHYSFSX_fseek(ifile, 1, SEEK_CUR);
  219.                         }
  220.                         else if (n>=-127) {             // next -n + 1 bytes are following byte
  221.                                 c=PHYSFSX_fgetc(ifile);
  222.                                 const int negative_n = -n;
  223.                                 nn = negative_n + 1;
  224.                                 wid_cnt -= nn;
  225.                                 if (wid_cnt==-1) {--nn; Assert(width&1);}
  226.                                 if (plane!=depth)       //not masking row
  227.                                         {memset(p,c,nn); p+=nn;}
  228.                         }
  229.  
  230.                         #ifndef NDEBUG
  231.                         if ((p - bmheader->raw_data.get()) % width == 0)
  232.                                         row_count++;
  233.  
  234.                         Assert((p - bmheader->raw_data.get()) - (width*row_count) < width);
  235.                         #endif
  236.  
  237.                 }
  238.  
  239. #if defined(DXX_BUILD_DESCENT_I)
  240.         if (bmheader->masking==mskHasMask && p==data_end && PHYSFS_tell(ifile)==end_pos-2)              //I don't know why...
  241.                 PHYSFSX_fseek(ifile, 1, SEEK_CUR);              //...but if I do this it works
  242.  
  243.         if (p==data_end && PHYSFS_tell(ifile)==end_pos-1)               //must be a pad byte
  244.                 //ignore = PHYSFSX_fgetc(ifile);                //get pad byte
  245.                 PHYSFSX_fseek(ifile, 1, SEEK_CUR);
  246.         else
  247.                 if (PHYSFS_tell(ifile)!=end_pos || p!=data_end) {
  248. //                      debug("IFF Error: p=%x, data_end=%x, cnt=%d\n",p,data_end,cnt);
  249.                         return IFF_CORRUPT;
  250.                 }
  251. #elif defined(DXX_BUILD_DESCENT_II)
  252.         if (p!=data_end)                                //if we don't have the whole bitmap...
  253.                 return IFF_CORRUPT;             //...the give an error
  254.  
  255.         //Pretend we read the whole chuck, because if we didn't, it's because
  256.         //we didn't read the last mask like or the last rle record for padding
  257.         //or whatever and it's not important, because we check to make sure
  258.         //we got the while bitmap, and that's what really counts.
  259. #endif
  260.  
  261.         return IFF_NO_ERROR;
  262. }
  263. }
  264.  
  265. //modify passed bitmap
  266. static int parse_delta(PHYSFS_File *ifile,long len,iff_bitmap_header *bmheader)
  267. {
  268.         auto p = bmheader->raw_data.get();
  269.         long chunk_end = PHYSFS_tell(ifile) + len;
  270.  
  271.         PHYSFSX_fseek(ifile, 4, SEEK_CUR);              //longword, seems to be equal to 4.  Don't know what it is
  272.  
  273.         for (int y=0;y<bmheader->h;y++) {
  274.                 ubyte n_items;
  275.                 int cnt = bmheader->w;
  276.                 ubyte code;
  277.  
  278.                 n_items = PHYSFSX_readByte(ifile);
  279.  
  280.                 while (n_items--) {
  281.  
  282.                         code = PHYSFSX_readByte(ifile);
  283.  
  284.                         if (code==0) {                          //repeat
  285.                                 ubyte rep,val;
  286.  
  287.                                 rep = PHYSFSX_readByte(ifile);
  288.                                 val = PHYSFSX_readByte(ifile);
  289.  
  290.                                 cnt -= rep;
  291.                                 if (cnt==-1)
  292.                                         rep--;
  293.                                 while (rep--)
  294.                                         *p++ = val;
  295.                         }
  296.                         else if (code > 0x80) { //skip
  297.                                 cnt -= (code-0x80);
  298.                                 p += (code-0x80);
  299.                                 if (cnt==-1)
  300.                                         p--;
  301.                         }
  302.                         else {                                          //literal
  303.                                 cnt -= code;
  304.                                 if (cnt==-1)
  305.                                         code--;
  306.  
  307.                                 while (code--)
  308.                                         *p++ = PHYSFSX_readByte(ifile);
  309.  
  310.                                 if (cnt==-1)
  311.                                         PHYSFSX_readByte(ifile);
  312.                         }
  313.  
  314.                 }
  315.  
  316.                 if (cnt == -1) {
  317.                         if (!bmheader->w)
  318.                                 return IFF_CORRUPT;
  319.                 }
  320.                 else if (cnt)
  321.                         return IFF_CORRUPT;
  322.         }
  323.  
  324.         if (PHYSFS_tell(ifile) == chunk_end-1)          //pad
  325.                 PHYSFSX_fseek(ifile, 1, SEEK_CUR);
  326.  
  327.         if (PHYSFS_tell(ifile) != chunk_end)
  328.                 return IFF_CORRUPT;
  329.         else
  330.                 return IFF_NO_ERROR;
  331. }
  332.  
  333. //  the buffer pointed to by raw_data is stuffed with a pointer to bitplane pixel data
  334. static void skip_chunk(PHYSFS_File *ifile,long len)
  335. {
  336.         int ilen;
  337.         ilen = (len+1) & ~1;
  338.  
  339.         PHYSFSX_fseek(ifile,ilen,SEEK_CUR);
  340. }
  341.  
  342. //read an ILBM or PBM file
  343. // Pass pointer to opened file, and to empty bitmap_header structure, and form length
  344. static int iff_parse_ilbm_pbm(PHYSFS_File *ifile,long form_type,iff_bitmap_header *bmheader,int form_len,grs_bitmap *prev_bm)
  345. {
  346.         int sig,len;
  347.         long start_pos,end_pos;
  348.  
  349.         start_pos = PHYSFS_tell(ifile);
  350.         end_pos = start_pos-4+form_len;
  351.  
  352.                         if (form_type == pbm_sig)
  353.                                 bmheader->type = TYPE_PBM;
  354.                         else
  355.                                 bmheader->type = TYPE_ILBM;
  356.  
  357.                         while ((PHYSFS_tell(ifile) < end_pos) && (sig=get_sig(ifile)) != EOF) {
  358.  
  359.                                 PHYSFS_readSBE32(ifile, &len);
  360.  
  361.                                 switch (sig) {
  362.  
  363.                                         case bmhd_sig: {
  364.                                                 int ret;
  365.                                                 int save_w=bmheader->w,save_h=bmheader->h;
  366.  
  367.                                                 ret = parse_bmhd(ifile,len,bmheader);
  368.  
  369.                                                 if (ret != IFF_NO_ERROR)
  370.                                                         return ret;
  371.  
  372.                                                 if (bmheader->raw_data) {
  373.  
  374.                                                         if (save_w != bmheader->w  ||  save_h != bmheader->h)
  375.                                                                 return IFF_BM_MISMATCH;
  376.  
  377.                                                 }
  378.                                                 else {
  379.                                                         MALLOC(bmheader->raw_data, uint8_t[], bmheader->w * bmheader->h);
  380.                                                         if (!bmheader->raw_data)
  381.                                                                 return IFF_NO_MEM;
  382.                                                 }
  383.  
  384.                                                 break;
  385.  
  386.                                         }
  387.  
  388.                                         case anhd_sig:
  389.  
  390.                                                 if (!prev_bm) return IFF_CORRUPT;
  391.  
  392.                                                 bmheader->w = prev_bm->bm_w;
  393.                                                 bmheader->h = prev_bm->bm_h;
  394.                                                 bmheader->type = prev_bm->get_type();
  395.  
  396.                                                 MALLOC(bmheader->raw_data, uint8_t[], bmheader->w * bmheader->h);
  397.  
  398.                                                 memcpy(bmheader->raw_data.get(), prev_bm->bm_data, bmheader->w * bmheader->h);
  399.                                                 skip_chunk(ifile,len);
  400.  
  401.                                                 break;
  402.  
  403.                                         case cmap_sig:
  404.                                         {
  405.                                                 unsigned ncolors=(len/3);
  406.  
  407.                                                 range_for (auto &p, partial_range(bmheader->palette, ncolors))
  408.                                                 {
  409.                                                         p.r = static_cast<unsigned char>(PHYSFSX_fgetc(ifile)) >> 2;
  410.                                                         p.g = static_cast<unsigned char>(PHYSFSX_fgetc(ifile)) >> 2;
  411.                                                         p.b = static_cast<unsigned char>(PHYSFSX_fgetc(ifile)) >> 2;
  412.                                                 }
  413.                                                 if (len & 1) PHYSFSX_fgetc(ifile);
  414.  
  415.                                                 break;
  416.                                         }
  417.  
  418.                                         case body_sig:
  419.                                         {
  420.                                                 int r;
  421.                                                 if ((r=parse_body(ifile,len,bmheader))!=IFF_NO_ERROR)
  422.                                                         return r;
  423.                                                 break;
  424.                                         }
  425.                                         case dlta_sig:
  426.                                         {
  427.                                                 int r;
  428.                                                 if ((r=parse_delta(ifile,len,bmheader))!=IFF_NO_ERROR)
  429.                                                         return r;
  430.                                                 break;
  431.                                         }
  432.                                         default:
  433.                                                 skip_chunk(ifile,len);
  434.                                                 break;
  435.                                 }
  436.                         }
  437.  
  438.         if (PHYSFS_tell(ifile) != start_pos-4+form_len)
  439.                 return IFF_CORRUPT;
  440.  
  441.         return IFF_NO_ERROR;    /* ok! */
  442. }
  443.  
  444. //convert an ILBM file to a PBM file
  445. static int convert_ilbm_to_pbm(iff_bitmap_header *bmheader)
  446. {
  447.         int x,p;
  448.         int bytes_per_row,byteofs;
  449.         ubyte checkmask,newbyte,setbit;
  450.  
  451.         RAIIdmem<uint8_t[]> new_data;
  452.         MALLOC(new_data, uint8_t[], bmheader->w * bmheader->h);
  453.         if (new_data == NULL) return IFF_NO_MEM;
  454.  
  455.         auto destptr = new_data.get();
  456.  
  457.         bytes_per_row = 2*((bmheader->w+15)/16);
  458.  
  459.         for (int y=0;y<bmheader->h;y++) {
  460.  
  461.                 const auto rowptr = reinterpret_cast<int8_t *>(&bmheader->raw_data[y * bytes_per_row * bmheader->nplanes]);
  462.  
  463.                 for (x=0,checkmask=0x80;x<bmheader->w;x++) {
  464.  
  465.                         byteofs = x >> 3;
  466.  
  467.                         for (p=newbyte=0,setbit=1;p<bmheader->nplanes;p++) {
  468.  
  469.                                 if (rowptr[bytes_per_row * p + byteofs] & checkmask)
  470.                                         newbyte |= setbit;
  471.  
  472.                                 setbit <<= 1;
  473.                         }
  474.  
  475.                         *destptr++ = newbyte;
  476.  
  477.                         if ((checkmask >>= 1) == 0) checkmask=0x80;
  478.                 }
  479.  
  480.         }
  481.  
  482.         bmheader->raw_data = std::move(new_data);
  483.  
  484.         bmheader->type = TYPE_PBM;
  485.  
  486.         return IFF_NO_ERROR;
  487. }
  488.  
  489. #define INDEX_TO_15BPP(i) (static_cast<short>((((palptr[(i)].r/2)&31)<<10)+(((palptr[(i)].g/2)&31)<<5)+((palptr[(i)].b/2 )&31)))
  490.  
  491. namespace dsx {
  492. static int convert_rgb15(grs_bitmap &bm,iff_bitmap_header &bmheader)
  493. {
  494.         palette_array_t::iterator palptr = begin(bmheader.palette);
  495.  
  496. #if defined(DXX_BUILD_DESCENT_I)
  497.         for (int y=0; y < bm.bm_h; y++) {
  498.                 for (int x=0; x < bmheader.w; x++)
  499.                         gr_bm_pixel(*grd_curcanv, bm, x, y, INDEX_TO_15BPP(bm.get_bitmap_data()[y * bmheader.w + x]));
  500.         }
  501. #elif defined(DXX_BUILD_DESCENT_II)
  502.         uint16_t *new_data;
  503.         MALLOC(new_data, ushort, bm.bm_w * bm.bm_h * 2);
  504.         if (new_data == NULL)
  505.                 return IFF_NO_MEM;
  506.  
  507.         unsigned newptr = 0;
  508.         for (int y=0; y < bm.bm_h; y++) {
  509.  
  510.                 for (int x=0; x < bmheader.w; x++)
  511.                         new_data[newptr++] = INDEX_TO_15BPP(bm.get_bitmap_data()[y * bmheader.w + x]);
  512.  
  513.         }
  514.  
  515.         d_free(bm.bm_mdata);                            //get rid of old-style data
  516.         bm.bm_mdata = reinterpret_cast<uint8_t *>(new_data);                    //..and point to new data
  517.  
  518.         bm.bm_rowsize *= 2;                             //two bytes per row
  519. #endif
  520.         return IFF_NO_ERROR;
  521.  
  522. }
  523. }
  524.  
  525. //copy an iff header structure to a grs_bitmap structure
  526. static void copy_iff_to_grs(grs_bitmap &bm,iff_bitmap_header &bmheader)
  527. {
  528.         gr_init_bitmap(bm, static_cast<bm_mode>(bmheader.type), 0, 0, bmheader.w, bmheader.h, bmheader.w, bmheader.raw_data.release());
  529. }
  530.  
  531. //if bm->bm_data is set, use it (making sure w & h are correct), else
  532. //allocate the memory
  533. static int iff_parse_bitmap(PHYSFS_File *ifile, grs_bitmap &bm, int bitmap_type, palette_array_t *palette, grs_bitmap *prev_bm)
  534. {
  535.         int ret;                        //return code
  536.         iff_bitmap_header bmheader;
  537.         int sig,form_len;
  538.         long form_type;
  539.  
  540.         bmheader.raw_data.reset(bm.get_bitmap_data());
  541.  
  542.         if (bmheader.raw_data) {
  543.                 bmheader.w = bm.bm_w;
  544.                 bmheader.h = bm.bm_h;
  545.         }//added 05/17/99 Matt Mueller - don't just leave them unitialized
  546.         else{
  547.                 bmheader.w=bmheader.h=0;
  548.         }
  549.  
  550.         sig=get_sig(ifile);
  551.  
  552.         if (sig != form_sig) {
  553.                 return IFF_NOT_IFF;
  554.         }
  555.  
  556.         PHYSFS_readSBE32(ifile, &form_len);
  557.  
  558.         form_type = get_sig(ifile);
  559.  
  560.         if (form_type == anim_sig)
  561.                 ret = IFF_FORM_ANIM;
  562.         else if ((form_type == pbm_sig) || (form_type == ilbm_sig))
  563.                 ret = iff_parse_ilbm_pbm(ifile,form_type,&bmheader,form_len,prev_bm);
  564.         else
  565.                 ret = IFF_UNKNOWN_FORM;
  566.  
  567.         if (ret != IFF_NO_ERROR) {              //got an error parsing
  568.                 return ret;
  569.         }
  570.  
  571.         //If IFF file is ILBM, convert to PPB
  572.         if (bmheader.type == TYPE_ILBM) {
  573.  
  574.                 ret = convert_ilbm_to_pbm(&bmheader);
  575.  
  576.                 if (ret != IFF_NO_ERROR)
  577.                         return ret;
  578.         }
  579.  
  580.         //Copy data from iff_bitmap_header structure into grs_bitmap structure
  581.  
  582.         copy_iff_to_grs(bm,bmheader);
  583.  
  584.         if (palette)
  585.                 *palette = bmheader.palette;
  586.  
  587.         //Now do post-process if required
  588.  
  589.         if (bitmap_type == bm_mode::rgb15) {
  590.                 ret = convert_rgb15(bm, bmheader);
  591.                 if (ret != IFF_NO_ERROR)
  592.                         return ret;
  593.         }
  594.  
  595.         return ret;
  596.  
  597. }
  598.  
  599. //returns error codes - see IFF.H.  see GR.H for bitmap_type
  600. int iff_read_bitmap(const char *const ifilename, grs_bitmap &bm, palette_array_t *const palette)
  601. {
  602.         int ret;                        //return code
  603.         auto ifile = PHYSFSX_openReadBuffered(ifilename);
  604.         if (!ifile)
  605.                 return IFF_NO_FILE;
  606.  
  607.         bm.bm_data = nullptr;
  608.         ret = iff_parse_bitmap(ifile, bm, bm_mode::linear, palette, nullptr);
  609.         return ret;
  610. }
  611.  
  612. #define BMHD_SIZE 20
  613.  
  614. #if 0
  615. static int write_bmhd(PHYSFS_File *ofile,iff_bitmap_header *bitmap_header)
  616. {
  617.         put_sig(bmhd_sig,ofile);
  618.         PHYSFS_writeSBE32(ofile, BMHD_SIZE);
  619.  
  620.         PHYSFS_writeSBE16(ofile, bitmap_header->w);
  621.         PHYSFS_writeSBE16(ofile, bitmap_header->h);
  622.         PHYSFS_writeSBE16(ofile, bitmap_header->x);
  623.         PHYSFS_writeSBE16(ofile, bitmap_header->y);
  624.  
  625.         PHYSFSX_writeU8(ofile, bitmap_header->nplanes);
  626.         PHYSFSX_writeU8(ofile, bitmap_header->masking);
  627.         PHYSFSX_writeU8(ofile, bitmap_header->compression);
  628.         PHYSFSX_writeU8(ofile, 0);      /* pad */
  629.  
  630.         PHYSFS_writeSBE16(ofile, bitmap_header->transparentcolor);
  631.         PHYSFSX_writeU8(ofile, bitmap_header->xaspect);
  632.         PHYSFSX_writeU8(ofile, bitmap_header->yaspect);
  633.  
  634.         PHYSFS_writeSBE16(ofile, bitmap_header->pagewidth);
  635.         PHYSFS_writeSBE16(ofile, bitmap_header->pageheight);
  636.  
  637.         return IFF_NO_ERROR;
  638.  
  639. }
  640.  
  641. static int write_pal(PHYSFS_File *ofile,iff_bitmap_header *bitmap_header)
  642. {
  643.         int n_colors = 1<<bitmap_header->nplanes;
  644.  
  645.         put_sig(cmap_sig,ofile);
  646. //      PHYSFS_writeSBE32(sizeof(pal_entry) * n_colors,ofile);
  647.         PHYSFS_writeSBE32(ofile, 3 * n_colors);
  648.  
  649.         range_for (auto &c, bitmap_header->palette)
  650.         {
  651.                 unsigned char r,g,b;
  652.                 r = c.r * 4 + (c.r?3:0);
  653.                 g = c.g * 4 + (c.g?3:0);
  654.                 b = c.b * 4 + (c.b?3:0);
  655.                 PHYSFSX_writeU8(ofile, r);
  656.                 PHYSFSX_writeU8(ofile, g);
  657.                 PHYSFSX_writeU8(ofile, b);
  658.         }
  659.  
  660.         return IFF_NO_ERROR;
  661. }
  662.  
  663. static int rle_span(ubyte *dest,ubyte *src,int len)
  664. {
  665.         int lit_cnt,rep_cnt;
  666.         ubyte last,*cnt_ptr,*dptr;
  667.  
  668.         cnt_ptr=0;
  669.  
  670.         dptr = dest;
  671.  
  672.         last=src[0]; lit_cnt=1;
  673.  
  674.         for (int n=1;n<len;n++) {
  675.  
  676.                 if (src[n] == last) {
  677.  
  678.                         rep_cnt = 2;
  679.  
  680.                         n++;
  681.                         while (n<len && rep_cnt<128 && src[n]==last) {n++; rep_cnt++;}
  682.  
  683.                         if (rep_cnt > 2 || lit_cnt < 2) {
  684.  
  685.                                 if (lit_cnt > 1) {*cnt_ptr = lit_cnt-2; --dptr;}                //save old lit count
  686.                                 *dptr++ = -(rep_cnt-1);
  687.                                 *dptr++ = last;
  688.                                 last = src[n];
  689.                                 lit_cnt = (n<len)?1:0;
  690.  
  691.                                 continue;               //go to next char
  692.                         } else n--;
  693.  
  694.                 }
  695.  
  696.                 {
  697.  
  698.                         if (lit_cnt==1) {
  699.                                 cnt_ptr = dptr++;               //save place for count
  700.                                 *dptr++=last;                   //store first char
  701.                         }
  702.  
  703.                         *dptr++ = last = src[n];
  704.  
  705.                         if (lit_cnt == 127) {
  706.                                 *cnt_ptr = lit_cnt;
  707.                                 //cnt_ptr = dptr++;
  708.                                 lit_cnt = 1;
  709.                                 last = src[++n];
  710.                         }
  711.                         else lit_cnt++;
  712.                 }
  713.  
  714.  
  715.         }
  716.  
  717.         if (lit_cnt==1) {
  718.                 *dptr++ = 0;
  719.                 *dptr++=last;                   //store first char
  720.         }
  721.         else if (lit_cnt > 1)
  722.                 *cnt_ptr = lit_cnt-1;
  723.  
  724.         return dptr-dest;
  725. }
  726.  
  727. #define EVEN(a) ((a+1)&0xfffffffel)
  728.  
  729. //returns length of chunk
  730. static int write_body(PHYSFS_File *ofile,iff_bitmap_header *bitmap_header,int compression_on)
  731. {
  732.         int w=bitmap_header->w,h=bitmap_header->h;
  733.         int y,odd=w&1;
  734.         long len = EVEN(w) * h,newlen,total_len=0;
  735.         uint8_t *p=bitmap_header->raw_data;
  736.         long save_pos;
  737.  
  738.         put_sig(body_sig,ofile);
  739.         save_pos = PHYSFS_tell(ofile);
  740.         PHYSFS_writeSBE32(ofile, len);
  741.  
  742.         RAIIdmem<uint8_t[]> new_span;
  743.         MALLOC( new_span, uint8_t[], bitmap_header->w + (bitmap_header->w/128+2)*2);
  744.         if (!new_span) return IFF_NO_MEM;
  745.  
  746.         for (y=bitmap_header->h;y--;) {
  747.  
  748.                 if (compression_on) {
  749.                         total_len += newlen = rle_span(new_span,p,bitmap_header->w+odd);
  750.                         PHYSFS_write(ofile,new_span,newlen,1);
  751.                 }
  752.                 else
  753.                         PHYSFS_write(ofile,p,bitmap_header->w+odd,1);
  754.  
  755.                 p+=bitmap_header->row_size;     //bitmap_header->w;
  756.         }
  757.  
  758.         if (compression_on) {           //write actual data length
  759.                 Assert(PHYSFSX_fseek(ofile,save_pos,SEEK_SET)==0);
  760.                 (void)save_pos;
  761.                 PHYSFS_writeSBE32(ofile, total_len);
  762.                 Assert(PHYSFSX_fseek(ofile,total_len,SEEK_CUR)==0);
  763.                 if (total_len&1) PHYSFSX_writeU8(ofile, 0);             //pad to even
  764.         }
  765.         return ((compression_on) ? (EVEN(total_len)+8) : (len+8));
  766.  
  767. }
  768.  
  769. #if WRITE_TINY
  770. //write a small representation of a bitmap. returns size
  771. int write_tiny(PHYSFS_File *ofile,iff_bitmap_header *bitmap_header,int compression_on)
  772. {
  773.         int skip;
  774.         int new_w,new_h;
  775.         int len,total_len=0,newlen;
  776.         int x,xofs,odd;
  777.         uint8_t *p = bitmap_header->raw_data;
  778.         ubyte tspan[80],new_span[80*2];
  779.         long save_pos;
  780.  
  781.         skip = max((bitmap_header->w+79)/80,(bitmap_header->h+63)/64);
  782.  
  783.         new_w = bitmap_header->w / skip;
  784.         new_h = bitmap_header->h / skip;
  785.  
  786.         odd = new_w & 1;
  787.  
  788.         len = new_w * new_h + 4;
  789.  
  790.         put_sig(tiny_sig,ofile);
  791.         save_pos = PHYSFS_tell(ofile);
  792.         PHYSFS_writeSBE32(ofile, EVEN(len));
  793.  
  794.         PHYSFS_writeSBE16(ofile, new_w);
  795.         PHYSFS_writeSBE16(ofile, new_h);
  796.  
  797.         for (int y=0;y<new_h;y++) {
  798.                 for (x=xofs=0;x<new_w;x++,xofs+=skip)
  799.                         tspan[x] = p[xofs];
  800.  
  801.                 if (compression_on) {
  802.                         total_len += newlen = rle_span(new_span,tspan,new_w+odd);
  803.                         PHYSFS_write(ofile,new_span,newlen,1);
  804.                 }
  805.                 else
  806.                         PHYSFS_write(ofile,p,new_w+odd,1);
  807.  
  808.                 p += skip * bitmap_header->row_size;            //bitmap_header->w;
  809.  
  810.         }
  811.  
  812.         if (compression_on) {
  813.                 Assert(PHYSFSX_fseek(ofile,save_pos,SEEK_SET)==0);
  814.                 (void)save_pos;
  815.                 PHYSFS_writeSBE32(ofile, 4+total_len);
  816.                 Assert(PHYSFSX_fseek(ofile,4+total_len,SEEK_CUR)==0);
  817.                 if (total_len&1) PHYSFSX_writeU8(ofile, 0);             //pad to even
  818.         }
  819.  
  820.         return ((compression_on) ? (EVEN(total_len)+8+4) : (len+8));
  821. }
  822. #endif
  823.  
  824. static int write_pbm(PHYSFS_File *ofile,iff_bitmap_header *bitmap_header,int compression_on)                    /* writes a pbm iff file */
  825. {
  826.         int ret;
  827.         long raw_size = EVEN(bitmap_header->w) * bitmap_header->h;
  828.         long body_size,tiny_size,pbm_size = 4 + BMHD_SIZE + 8 + EVEN(raw_size) + sizeof(rgb_t)*(1<<bitmap_header->nplanes)+8;
  829.         long save_pos;
  830.  
  831.         put_sig(form_sig,ofile);
  832.         save_pos = PHYSFS_tell(ofile);
  833.         PHYSFS_writeSBE32(ofile, pbm_size+8);
  834.         put_sig(pbm_sig,ofile);
  835.  
  836.         ret = write_bmhd(ofile,bitmap_header);
  837.         if (ret != IFF_NO_ERROR) return ret;
  838.  
  839.         ret = write_pal(ofile,bitmap_header);
  840.         if (ret != IFF_NO_ERROR) return ret;
  841.  
  842. #if WRITE_TINY
  843.         tiny_size = write_tiny(ofile,bitmap_header,compression_on);
  844. #else
  845.         tiny_size = 0;
  846. #endif
  847.  
  848.         body_size = write_body(ofile,bitmap_header,compression_on);
  849.  
  850.         pbm_size = 4 + BMHD_SIZE + body_size + tiny_size + sizeof(rgb_t)*(1<<bitmap_header->nplanes)+8;
  851.  
  852.         Assert(PHYSFSX_fseek(ofile,save_pos,SEEK_SET)==0);
  853.         (void)save_pos;
  854.         PHYSFS_writeSBE32(ofile, pbm_size+8);
  855.         Assert(PHYSFSX_fseek(ofile,pbm_size+8,SEEK_CUR)==0);
  856.  
  857.         return ret;
  858.  
  859. }
  860.  
  861. //writes an IFF file from a grs_bitmap structure. writes palette if not null
  862. //returns error codes - see IFF.H.
  863. int iff_write_bitmap(const char *ofilename,grs_bitmap *bm,palette_array_t *palette)
  864. {
  865.         iff_bitmap_header bmheader;
  866.         int ret;
  867.         int compression_on;
  868.  
  869.         if (bm->bm_type == bm_mode::rgb15) return IFF_BAD_BM_TYPE;
  870.  
  871. #if COMPRESS
  872.         compression_on = (bm->bm_w>=MIN_COMPRESS_WIDTH);
  873. #else
  874.         compression_on = 0;
  875. #endif
  876.  
  877.         //fill in values in bmheader
  878.  
  879.         bmheader.x = bmheader.y = 0;
  880.         bmheader.w = bm->bm_w;
  881.         bmheader.h = bm->bm_h;
  882.         bmheader.type = TYPE_PBM;
  883.         bmheader.transparentcolor = iff_transparent_color;
  884.         bmheader.pagewidth = bm->bm_w;  //I don't think it matters what I write
  885.         bmheader.pageheight = bm->bm_h;
  886.         bmheader.nplanes = 8;
  887.         bmheader.masking = mskNone;
  888.         if (iff_has_transparency)       {
  889.                  bmheader.masking |= mskHasTransparentColor;
  890.         }
  891.         bmheader.compression = (compression_on?cmpByteRun1:cmpNone);
  892.  
  893.         bmheader.xaspect = bmheader.yaspect = 1;        //I don't think it matters what I write
  894.         bmheader.raw_data = bm->get_bitmap_data();
  895.         bmheader.row_size = bm->bm_rowsize;
  896.  
  897.         if (palette)
  898.                 bmheader.palette = *palette;
  899.  
  900.         //open file and write
  901.  
  902.         RAIIPHYSFS_File ofile{PHYSFS_openWrite(ofilename)};
  903.         if (!ofile)
  904.                 return IFF_NO_FILE;
  905.  
  906.         ret = write_pbm(ofile,&bmheader,compression_on);
  907.         return ret;
  908. }
  909. #endif
  910.  
  911. //read in many brushes.  fills in array of pointers, and n_bitmaps.
  912. //returns iff error codes
  913. int iff_read_animbrush(const char *ifilename,std::array<std::unique_ptr<grs_main_bitmap>, MAX_BITMAPS_PER_BRUSH> &bm_list,unsigned *n_bitmaps,palette_array_t &palette)
  914. {
  915.         int ret = IFF_NO_ERROR;                 //return code
  916.         int sig,form_len;
  917.         long form_type;
  918.  
  919.         *n_bitmaps=0;
  920.  
  921.         auto ifile = PHYSFSX_openReadBuffered(ifilename);
  922.         if (!ifile)
  923.                 return IFF_NO_FILE;
  924.  
  925.         sig=get_sig(ifile);
  926.         PHYSFS_readSBE32(ifile, &form_len);
  927.  
  928.         if (sig != form_sig) {
  929.                 ret = IFF_NOT_IFF;
  930.                 goto done;
  931.         }
  932.  
  933.         form_type = get_sig(ifile);
  934.  
  935.         if ((form_type == pbm_sig) || (form_type == ilbm_sig))
  936.                 ret = IFF_FORM_BITMAP;
  937.         else if (form_type == anim_sig) {
  938.                 int anim_end = PHYSFS_tell(ifile) + form_len - 4;
  939.  
  940.                 while (PHYSFS_tell(ifile) < anim_end && *n_bitmaps < bm_list.size()) {
  941.  
  942.                         grs_bitmap *prev_bm;
  943.  
  944.                         prev_bm = *n_bitmaps>0?bm_list[*n_bitmaps-1].get() : nullptr;
  945.  
  946.                         auto &n = bm_list[*n_bitmaps];
  947.                         n = std::make_unique<grs_main_bitmap>();
  948.  
  949.                         ret = iff_parse_bitmap(ifile, *n.get(), form_type, *n_bitmaps > 0 ? nullptr : &palette, prev_bm);
  950.  
  951.                         if (ret != IFF_NO_ERROR)
  952.                                 goto done;
  953.  
  954.                         (*n_bitmaps)++;
  955.                 }
  956.  
  957.                 if (PHYSFS_tell(ifile) < anim_end)      //ran out of room
  958.                         ret = IFF_TOO_MANY_BMS;
  959.  
  960.         }
  961.         else
  962.                 ret = IFF_UNKNOWN_FORM;
  963.  
  964. done:
  965.         return ret;
  966. }
  967.  
  968. //text for error messges
  969. constexpr char error_messages[] = {
  970.         "No error.\0"
  971.         "Not enough mem for loading or processing bitmap.\0"
  972.         "IFF file has unknown FORM type.\0"
  973.         "Not an IFF file.\0"
  974.         "Cannot open file.\0"
  975.         "Tried to save invalid type, like bm_mode::rgb15.\0"
  976.         "Bad data in file.\0"
  977.         "ANIM file cannot be loaded with normal bitmap loader.\0"
  978.         "Normal bitmap file cannot be loaded with anim loader.\0"
  979.         "Array not big enough on anim brush read.\0"
  980.         "Unknown mask type in bitmap header.\0"
  981.         "Error reading file.\0"
  982. };
  983.  
  984.  
  985. //function to return pointer to error message
  986. const char *iff_errormsg(int error_number)
  987. {
  988.         const char *p = error_messages;
  989.  
  990.         while (error_number--) {
  991.  
  992.                 if (!p) return NULL;
  993.  
  994.                 p += strlen(p)+1;
  995.  
  996.         }
  997.  
  998.         return p;
  999.  
  1000. }
  1001.  
  1002.  
  1003.