home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / gbmsrc.zip / gbmlbm.c < prev    next >
C/C++ Source or Header  |  1996-12-04  |  27KB  |  1,305 lines

  1. /*
  2.  
  3. gbmlbm.c - Amiga IFF / ILBM format
  4.  
  5. BEWARE: This code at present assumes that the red,green and blue planes are
  6. stored in that order within a true 24 bpp IFF file. I have no testcase or
  7. documentation to independantly verify this.
  8.  
  9. */
  10.  
  11. /*...sincludes:0:*/
  12. #include <stdio.h>
  13. #include <ctype.h>
  14. #include <stddef.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <memory.h>
  18. #include <malloc.h>
  19. #include "gbm.h"
  20. #include "gbmhelp.h"
  21.  
  22. /*...vgbm\46\h:0:*/
  23. /*...vgbmhelp\46\h:0:*/
  24. /*...e*/
  25.  
  26. /*...smapping:0:*/
  27. /*...sget_dword:0:*/
  28. static dword get_dword(byte *b)
  29.     {
  30.     return    (dword) b[3]         +
  31.             (((dword) b[2]) <<  8) +
  32.             (((dword) b[1]) << 16) +
  33.             (((dword) b[0]) << 24) ;
  34.     }
  35. /*...e*/
  36. /*...sget_word:0:*/
  37. static word get_word(byte *b)
  38.     {
  39.     return    (word) b[1]        +
  40.             (((word) b[0]) << 8) ;
  41.     }
  42. /*...e*/
  43. /*...sput_dword:0:*/
  44. static void put_dword(byte *b, dword n)
  45.     {
  46.     b[3] = (byte) n;
  47.     n >>= 8;
  48.     b[2] = (byte) n;
  49.     n >>= 8;
  50.     b[1] = (byte) n;
  51.     n >>= 8;
  52.     b[0] = (byte) n;
  53.     }
  54. /*...e*/
  55. /*...sput_word:0:*/
  56. static void put_word(byte *b, word n)
  57.     {
  58.     b[1] = (byte) n;
  59.     n >>= 8;
  60.     b[0] = (byte) n;
  61.     }
  62. /*...e*/
  63. /*...e*/
  64.  
  65. static GBMFT lbm_gbmft =
  66.     {
  67.     "ILBM",
  68.     "Amiga IFF / ILBM Interleaved bitmap",
  69.     "IFF LBM",
  70.     GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|GBM_FT_R24|
  71.     GBM_FT_W1|GBM_FT_W4|GBM_FT_W8|GBM_FT_W24,
  72.     };
  73.  
  74. #define    GBM_ERR_LBM_FORM    ((GBM_ERR) 900)
  75. #define    GBM_ERR_LBM_ILBM    ((GBM_ERR) 901)
  76. #define    GBM_ERR_LBM_BMHD_2    ((GBM_ERR) 902)
  77. #define    GBM_ERR_LBM_BMHD_0    ((GBM_ERR) 903)
  78. #define    GBM_ERR_LBM_BMHD_SIZE    ((GBM_ERR) 904)
  79. #define    GBM_ERR_LBM_BPP        ((GBM_ERR) 905)
  80. #define    GBM_ERR_LBM_CMAP_SIZE    ((GBM_ERR) 906)
  81. #define    GBM_ERR_LBM_COMP    ((GBM_ERR) 907)
  82. #define    GBM_ERR_LBM_CAMG_SIZE    ((GBM_ERR) 908)
  83. #define    GBM_ERR_LBM_SHAM_VER    ((GBM_ERR) 909)
  84.  
  85. typedef struct
  86.     {
  87.     byte pal[0x100 * 3];
  88.     dword body, size_body;
  89.     byte actual_bpp, comp;
  90.     long sham;
  91.     } LBM_PRIV;
  92.  
  93. #define    CAMG_LACE    0x00000004
  94. #define    CAMG_EHB    0x00000080
  95. #define    CAMG_HAM    0x00000800
  96. #define    CAMG_1000    0x00001000    /* Meaning unknown */
  97. #define    CAMG_4000    0x00004000    /* Meaning unknown */
  98. #define    CAMG_HIRES    0x00008000
  99. #define    CAMG_20000    0x00020000    /* Meaning unknown */
  100.  
  101. /*...slbm_qft:0:*/
  102. GBM_ERR lbm_qft(GBMFT *gbmft)
  103.     {
  104.     *gbmft = lbm_gbmft;
  105.     return GBM_ERR_OK;
  106.     }
  107. /*...e*/
  108. /*...slbm_rhdr:0:*/
  109. GBM_ERR lbm_rhdr(const char *fn, int fd, GBM *gbm, const char *opt)
  110.     {
  111.     LBM_PRIV *priv = (LBM_PRIV *) gbm->priv;
  112.     byte b[20];
  113.     int w, h, bpp, actual_size_cmap = 0;
  114.     BOOLEAN    had_bmhd = FALSE, had_cmap = FALSE, had_body = FALSE;
  115.     dword camg = 0;
  116.  
  117.     fn=fn; opt=opt; /* Suppress 'unref arg' compiler warnings */
  118.  
  119.     if ( gbm_file_read(fd, b, 12) != 12 )
  120.         return GBM_ERR_READ;
  121.     
  122.     if ( memcmp(b, "FORM", 4) )
  123.         return GBM_ERR_LBM_FORM;
  124.  
  125.     if ( memcmp(b + 8, "ILBM", 4) )
  126.         return GBM_ERR_LBM_ILBM;
  127.  
  128.     priv->sham = -1L;
  129.  
  130.     while ( !had_bmhd || !had_cmap || !had_body )
  131.         {
  132.         dword size;
  133.  
  134.         if ( gbm_file_read(fd, b, 8) != 8 )
  135.             return GBM_ERR_READ;
  136.         size = get_dword(b + 4);
  137.         if ( !memcmp(b, "BMHD", 4) )
  138. /*...sbitmap header:24:*/
  139. {
  140. if ( had_bmhd )
  141.     return GBM_ERR_LBM_BMHD_2;
  142.  
  143. if ( size != 20 )
  144.     return GBM_ERR_LBM_BMHD_SIZE;
  145.  
  146. if ( gbm_file_read(fd, b, 20) != 20 )
  147.     return GBM_ERR_READ;
  148.  
  149. priv->comp = b[10];
  150. if ( priv->comp != 0 && priv->comp != 1 )
  151.     /* Expect compression type to be uncomp or RLE */
  152.     return GBM_ERR_LBM_COMP;
  153.  
  154. w = get_word(b);
  155. h = get_word(b + 2);
  156.  
  157. if ( w < 0 || w > 10000 || h < 0 || h > 10000 )
  158.     return GBM_ERR_BAD_SIZE;
  159.  
  160. priv->actual_bpp = b[8];
  161.  
  162. switch ( priv->actual_bpp )
  163.     {
  164.     case 1:
  165.         bpp = 1; break;
  166.     case 2: case 3: case 4:
  167.         bpp = 4; break;
  168.     case 5: case 6: case 7: case 8:
  169.         bpp = 8; break;
  170.     case 24:
  171.         bpp = 24; had_cmap = TRUE; break;
  172.     default:
  173.         return GBM_ERR_LBM_BPP;
  174.     }
  175.  
  176. if ( priv->actual_bpp == 6 )
  177.     /* In case no CAMG chunk present */
  178.     /* Assume HAM6, and will probably be right */
  179.     camg = CAMG_HAM;
  180.  
  181. had_bmhd = TRUE;
  182. }
  183. /*...e*/
  184.         else if ( !memcmp(b, "CAMG", 4) )
  185. /*...sC\61\ Amiga mode info:24:*/
  186. {
  187. if ( !had_bmhd )
  188.     return GBM_ERR_LBM_BMHD_0;
  189.  
  190. if ( size != 4 )
  191.     return GBM_ERR_LBM_CAMG_SIZE;
  192.  
  193. if ( gbm_file_read(fd, b, 4) != 4 )
  194.     return GBM_ERR_READ;
  195.  
  196. camg = get_dword(b);
  197. }
  198. /*...e*/
  199.         else if ( !memcmp(b, "CMAP", 4) )
  200. /*...scolour map:24:*/
  201. {
  202. if ( !had_bmhd )
  203.     return GBM_ERR_LBM_BMHD_0;
  204. actual_size_cmap = size;
  205. if ( (dword) gbm_file_read(fd, priv->pal, size) != size )
  206.     return GBM_ERR_READ;
  207. had_cmap = TRUE;
  208. }
  209. /*...e*/
  210.         else if ( !memcmp(b, "SHAM", 4) )
  211. /*...ssham:24:*/
  212. {
  213. if ( gbm_file_read(fd, b, 2) != 2 )
  214.     return GBM_ERR_READ;
  215.  
  216. if ( get_word(b) != 0 )
  217.     return GBM_ERR_LBM_SHAM_VER;
  218.  
  219. priv->sham = gbm_file_lseek(fd, 0L, SEEK_CUR);
  220.  
  221. gbm_file_lseek(fd, ((size - 2 + 1) & ~1), SEEK_CUR);
  222. }
  223. /*...e*/
  224.         else if ( !memcmp(b, "BODY", 4) )
  225. /*...sbody of data:24:*/
  226. {
  227. if ( !had_bmhd )
  228.     return GBM_ERR_LBM_BMHD_0;
  229.  
  230. priv->body = (dword) gbm_file_lseek(fd, 0L, SEEK_CUR);
  231. priv->size_body = size;
  232. had_body = TRUE;
  233. }
  234. /*...e*/
  235.         else
  236.             gbm_file_lseek(fd, ((size + 1) & ~1), SEEK_CUR);
  237.         }
  238.  
  239. /*...saccount for ehb\44\ ham6 and ham8:8:*/
  240. {
  241. int entrys = ( 1 << priv->actual_bpp );
  242. int size_cmap = entrys * 3;
  243. BOOLEAN ehb = FALSE, sham = FALSE, ham6 = FALSE, ham8 = FALSE;
  244.  
  245. if ( priv->sham != -1L )
  246.     sham = TRUE; /* Allow Sliced HAM mode */
  247. if ( (camg & CAMG_EHB) != 0 && actual_size_cmap * 2 == size_cmap )
  248.     ehb = TRUE; /* Allow Extra-HalfBrite mode */
  249. else if ( (camg & CAMG_HAM) != 0 && actual_size_cmap == 0x10*3 && size_cmap == 0x40*3 )
  250.     ham6 = TRUE; /* Allow HAM6 mode */
  251. else if ( (camg & CAMG_HAM) != 0 && actual_size_cmap == 0x40*3 && size_cmap == 0x100*3 )
  252.     ham8 = TRUE; /* Allow HAM8 mode */
  253. else if ( priv->actual_bpp == 24 )
  254.     ; /* Is a real 24 bpp mode */
  255. else if ( actual_size_cmap != size_cmap )
  256.     return GBM_ERR_LBM_CMAP_SIZE;
  257. if ( ehb )
  258. /*...sreplicate palette:16:*/
  259. {
  260. int i;
  261. for ( i = 0; i < actual_size_cmap; i++ )
  262.     priv->pal[actual_size_cmap + i] = (priv->pal[i] >> 1);
  263. }
  264. /*...e*/
  265. else if ( ham6 )
  266. /*...snobble all but top 4 bits of palette entries:16:*/
  267. {
  268. int i;
  269. for ( i = 0; i < 0x10 * 3; i++ )
  270.     priv->pal[i] &= 0xf0;
  271. bpp = 24;
  272. }
  273. /*...e*/
  274. else if ( ham8 || sham )
  275.     bpp = 24;
  276. }
  277. /*...e*/
  278.  
  279.     gbm->w   = w;
  280.     gbm->h   = h;
  281.     gbm->bpp = bpp;
  282.  
  283.     return GBM_ERR_OK;
  284.     }
  285. /*...e*/
  286. /*...slbm_rpal:0:*/
  287. GBM_ERR lbm_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
  288.     {
  289.     LBM_PRIV *priv = (LBM_PRIV *) gbm->priv;
  290.     byte *p = priv->pal;
  291.     int i, entrys = ( 1 << priv->actual_bpp );
  292.  
  293.     fd=fd; /* Suppress 'unref arg' compiler warning */
  294.  
  295.     if ( gbm->bpp == 24 )
  296.         return GBM_ERR_OK;
  297.  
  298.     for ( i = 0; i < entrys; i++ )
  299.         {
  300.         gbmrgb[i].r = *p++;
  301.         gbmrgb[i].g = *p++;
  302.         gbmrgb[i].b = *p++;
  303.         }
  304.  
  305.     return GBM_ERR_OK;
  306.     }
  307. /*...e*/
  308. /*...slbm_rdata:0:*/
  309. /*...sget_line:0:*/
  310. /*...sread_line   \45\ compression type 0 \45\ uncompressed:0:*/
  311. static BOOLEAN read_line(AHEAD *ahead, byte *dest, int w)
  312.     {
  313.     while ( w-- )
  314.         {
  315.         int b = gbm_read_ahead(ahead);
  316.         if ( b == -1 )
  317.             return FALSE;
  318.         *dest++ = b;
  319.         }
  320.     return TRUE;
  321.     }
  322. /*...e*/
  323. /*...sdecode_line \45\ compression type 1 \45\ RLE:0:*/
  324. static BOOLEAN decode_line(AHEAD *ahead, byte *dest, int w)
  325.     {
  326.     int x = 0;
  327.  
  328.     while ( x < w )
  329.         {
  330.         int c = gbm_read_ahead(ahead);
  331.  
  332.         if ( c == -1 )
  333.             return FALSE;
  334.  
  335.         if ( c & 0x80 )
  336.             {
  337.             int cnt = (0x100 - c + 1);
  338.  
  339.             memset(dest, (byte) gbm_read_ahead(ahead), cnt);
  340.             x += cnt;
  341.             dest += cnt;
  342.             }
  343.         else
  344.             {
  345.             int cnt = (c + 1);
  346.  
  347.             x += cnt;
  348.             while ( cnt-- )
  349.                 {
  350.                 int b = gbm_read_ahead(ahead);
  351.                 if ( b == -1 )
  352.                     return FALSE;
  353.                 *dest++ = (byte) b;
  354.                 }
  355.             }
  356.         }
  357.     return TRUE;
  358.     }
  359. /*...e*/
  360.  
  361. static BOOLEAN get_line(LBM_PRIV *priv, AHEAD *ahead, byte *dest, int w)
  362.     {
  363.     switch ( priv->comp )
  364.         {
  365.         case 0:
  366.             return read_line(ahead, dest, w);
  367.         case 1:
  368.             return decode_line(ahead, dest, w);
  369.         }
  370.     return FALSE; /* Shouldn't get here */
  371.     }
  372. /*...e*/
  373. /*...sget_planes_8:0:*/
  374. static BOOLEAN get_planes_8(
  375.     AHEAD *ahead,
  376.     LBM_PRIV *priv,
  377.     byte *buf,
  378.     byte *data,
  379.     int w,
  380.     int n_planes
  381.     )
  382.     {
  383.     int plane, p;
  384.     int scan = (((((unsigned)w + 7) >> 3)+1)/2)*2;
  385.  
  386.     memset(data, 0, w);
  387.     for ( plane = 0, p = 0x01; plane < n_planes; plane++, p <<= 1 )
  388.         {
  389.         int i;
  390.  
  391.         if ( !get_line(priv, ahead, buf, scan) )
  392.             return FALSE;
  393.         for ( i = 0; i < w; i++ )
  394.             if ( buf[(unsigned)i >> 3] & (0x80U >> ((unsigned)i & 7U)) )
  395.                 data[i] |= p;
  396.         }
  397.     return TRUE;
  398.     }
  399. /*...e*/
  400. /*...sget_planes_24:0:*/
  401. static BOOLEAN get_planes_24(
  402.     AHEAD *ahead,
  403.     LBM_PRIV *priv,
  404.     byte *buf,
  405.     byte *data,
  406.     int w
  407.     )
  408.     {
  409.     int plane, p, c, i;
  410.     int scan = (((((unsigned)w + 7) >> 3)+1)/2)*2;
  411.  
  412.     memset(data, 0, w*3);
  413.     for ( c = 2; c >= 0; c-- )
  414.         for ( plane = 0, p = 0x01; plane < 8; plane++, p <<= 1 )
  415.             {
  416.             if ( !get_line(priv, ahead, buf, scan) )
  417.                 return FALSE;
  418.             for ( i = 0; i < w; i++ )
  419.                 if ( buf[(unsigned)i >> 3] & (0x80U >> ((unsigned)i & 7U)) )
  420.                     data[c+i*3] |= p;
  421.             }
  422.     return TRUE;
  423.     }
  424. /*...e*/
  425.  
  426. GBM_ERR lbm_rdata(int fd, GBM *gbm, byte *data)
  427.     {
  428.     LBM_PRIV *priv = (LBM_PRIV *) gbm->priv;
  429.     AHEAD *ahead;
  430.     int stride = ((gbm->w * gbm->bpp + 31) / 32) * 4;
  431.     int scan = ((((unsigned)(gbm->w + 7) >> 3)+1)/2)*2;
  432.     gbm_file_lseek(fd, priv->body, SEEK_SET);
  433.  
  434.     if ( (ahead = gbm_create_ahead(fd)) == NULL )
  435.         return GBM_ERR_MEM;
  436.  
  437.     data += ((gbm->h - 1) * stride);
  438.  
  439.     switch ( gbm->bpp )
  440.         {
  441. /*...s24:16:*/
  442. case 24:
  443.     {
  444.     byte *buf;
  445.     int y;
  446.  
  447.     if ( (buf = malloc((size_t) scan)) == NULL )
  448.         {
  449.         gbm_destroy_ahead(ahead);
  450.         return GBM_ERR_MEM;
  451.         }
  452.  
  453.     if ( priv->actual_bpp == 24 )
  454. /*...sreal 24 bpp data case:32:*/
  455. {
  456. for ( y = 0; y < gbm->h; y++, data -= stride )
  457.     if ( !get_planes_24(ahead, priv, buf, data, gbm->w) )
  458.         {
  459.         free(buf);
  460.         gbm_destroy_ahead(ahead);
  461.         return GBM_ERR_READ;
  462.         }
  463. }
  464. /*...e*/
  465.     else
  466. /*...sHAM6\44\ HAM8 or SHAM6:32:*/
  467. {
  468. byte *ham, *sham_pals;
  469. int n_sham_pals, sham_inx = 0;
  470.  
  471. if ( (ham = malloc((size_t) gbm->w)) == NULL )
  472.     {
  473.     free(buf);
  474.     gbm_destroy_ahead(ahead);
  475.     return GBM_ERR_MEM;
  476.     }
  477.  
  478. if ( priv->sham != -1L )
  479. /*...sread SHAM palettes:40:*/
  480. /* SHAM holds 200 lines of 16 words each with a 0rgb palette entry */
  481. /* If <= 200 lines then one line per palette */
  482. /* Else two lines per palette */
  483.  
  484. {
  485. n_sham_pals = ( gbm->h < 200 ) ? gbm->h : 200;
  486. if ( (sham_pals = malloc((size_t) (n_sham_pals * 16 * 2))) == NULL )
  487.     {
  488.     free(ham);
  489.     free(buf);
  490.     gbm_destroy_ahead(ahead);
  491.     return GBM_ERR_MEM;
  492.     }
  493.  
  494. gbm_file_lseek(fd, priv->sham, SEEK_SET);
  495. if ( gbm_file_read(fd, sham_pals, n_sham_pals * 16 * 2) != n_sham_pals * 16 * 2 )
  496.     {
  497.     free(sham_pals);
  498.     free(ham);
  499.     free(buf);
  500.     gbm_destroy_ahead(ahead);
  501.     return GBM_ERR_READ;
  502.     }
  503. gbm_file_lseek(fd, priv->body, SEEK_SET);
  504. }
  505. /*...e*/
  506.  
  507. for ( y = 0; y < gbm->h; y++, data -= stride )
  508.     {
  509.     if ( !get_planes_8(ahead, priv, buf, ham, gbm->w, priv->actual_bpp) )
  510.         {
  511.          if ( priv->sham != -1L )
  512.             free(sham_pals);
  513.         free(buf);
  514.         free(ham);
  515.         gbm_destroy_ahead(ahead);
  516.         return GBM_ERR_READ;
  517.         }
  518.  
  519.     if ( priv->sham != -1L )
  520. /*...sconvert from SHAM6 to 24 bit rgb:48:*/
  521. {
  522. byte r = 0, g = 0, b = 0;
  523. int i;
  524. for ( i = 0; i < gbm->w; i++ )
  525.     {
  526.     byte val = (ham[i] & 0x0f);
  527.     switch ( ham[i] & 0x30 )
  528.         {
  529.         case 0x00:
  530.             {
  531.             word pal = get_word(sham_pals + ((sham_inx * 16 + val) * 2));
  532.             r = (byte) ((pal & 0x0f00U) >> 4);
  533.             g = (byte)  (pal & 0x00f0U)      ;
  534.             b = (byte) ((pal & 0x000fU) << 4);
  535.             }
  536.             break;
  537.         case 0x10:
  538.             b = (val << 4);
  539.             break;
  540.         case 0x20:
  541.             r = (val << 4);
  542.             break;
  543.         case 0x30:
  544.             g = (val << 4);
  545.             break;
  546.         }
  547.     data[i * 3    ] = b;
  548.     data[i * 3 + 1] = g;
  549.     data[i * 3 + 2] = r;
  550.     }
  551. if ( gbm->h <= 200 || (y & 1) != 0 )
  552.     if ( ++sham_inx == n_sham_pals )
  553.         sham_inx = 0;
  554. }
  555. /*...e*/
  556.     else if ( priv->actual_bpp == 6 )
  557. /*...sconvert from HAM6 to 24 bit rgb:48:*/
  558. {
  559. byte r = 0, g = 0, b = 0;
  560. int i;
  561. for ( i = 0; i < gbm->w; i++ )
  562.     {
  563.     byte val = (ham[i] & 0x0f);
  564.     switch ( ham[i] & 0x30 )
  565.         {
  566.         case 0x00:
  567.             r = priv->pal[val * 3    ];
  568.             g = priv->pal[val * 3 + 1];
  569.             b = priv->pal[val * 3 + 2];
  570.             break;
  571.         case 0x10:
  572.             b = (val << 4);
  573.             break;
  574.         case 0x20:
  575.             r = (val << 4);
  576.             break;
  577.         case 0x30:
  578.             g = (val << 4);
  579.             break;
  580.         }
  581.     data[i * 3    ] = b;
  582.     data[i * 3 + 1] = g;
  583.     data[i * 3 + 2] = r;
  584.     }
  585. }
  586. /*...e*/
  587.     else
  588. /*...sconvert from HAM8 to 24 bit rgb:48:*/
  589. {
  590. byte r = 0, g = 0, b = 0;
  591. int i;
  592. for ( i = 0; i < gbm->w; i++ )
  593.     {
  594.     byte val = (ham[i] & 0x3f);
  595.     switch ( ham[i] & 0xc0 )
  596.         {
  597.         case 0x00:
  598.             r = priv->pal[val * 3    ];
  599.             g = priv->pal[val * 3 + 1];
  600.             b = priv->pal[val * 3 + 2];
  601.             break;
  602.         case 0x40:
  603.             b = ((r & 0x03) | (val << 2));
  604.             break;
  605.         case 0x80:
  606.             r = ((b & 0x03) | (val << 2));
  607.             break;
  608.         case 0xc0:
  609.             g = ((g & 0x03) | (val << 2));
  610.             break;
  611.         }
  612.     data[i * 3    ] = b;
  613.     data[i * 3 + 1] = g;
  614.     data[i * 3 + 2] = r;
  615.     }
  616. }
  617. /*...e*/
  618.     }
  619.  
  620. if ( priv->sham != -1L )
  621.     free(sham_pals);
  622. free(ham);
  623. }
  624. /*...e*/
  625.  
  626.     free(buf);
  627.     }
  628.     break;
  629. /*...e*/
  630. /*...s8:16:*/
  631. case 8:
  632.     {
  633.     byte *buf;
  634.     int y;
  635.  
  636.     if ( (buf = malloc((size_t) scan)) == NULL )
  637.         {
  638.         gbm_destroy_ahead(ahead);
  639.         return GBM_ERR_MEM;
  640.         }
  641.  
  642.     for ( y = 0; y < gbm->h; y++, data -= stride )
  643.         if ( !get_planes_8(ahead, priv, buf, data, gbm->w, priv->actual_bpp) )
  644.             {
  645.             free(buf);
  646.             gbm_destroy_ahead(ahead);
  647.             return GBM_ERR_READ;
  648.             }
  649.  
  650.     free(buf);
  651.     }
  652.     break;
  653. /*...e*/
  654. /*...s4:16:*/
  655. case 4:
  656.     {
  657.     byte *buf;
  658.     int y;
  659.  
  660.     if ( (buf = malloc((size_t) scan)) == NULL )
  661.         {
  662.         gbm_destroy_ahead(ahead);
  663.         return GBM_ERR_MEM;
  664.         }
  665.  
  666.     for ( y = 0; y < gbm->h; y++, data -= stride )
  667.         {
  668.         int plane, p;
  669.  
  670.         memset(data, 0, stride);
  671.         for ( plane = 0, p = 0x11; plane < priv->actual_bpp; plane++,p <<= 1 )
  672.             {
  673.             int i, mask;
  674.  
  675.             if ( !get_line(priv, ahead, buf, scan) )
  676.                 {
  677.                 free(buf);
  678.                 gbm_destroy_ahead(ahead);
  679.                 return GBM_ERR_READ;
  680.                 }
  681.             for ( i = 0, mask = 0xf0; i < gbm->w; i++, mask ^= 0xff )
  682.                 if ( buf[(unsigned)i >> 3] & (0x80U >> ((unsigned)i & 7U)) )
  683.                     data[(unsigned)i >> 1] |= ((unsigned)p & (unsigned)mask);
  684.             }
  685.         }
  686.  
  687.     free(buf);
  688.     }
  689.     break;
  690. /*...e*/
  691. /*...s1:16:*/
  692. case 1:
  693.     {
  694.     int y;
  695.  
  696.     for ( y = 0; y < gbm->h; y++, data -= stride )
  697.         if ( !get_line(priv, ahead, data, scan) )
  698.             {
  699.             gbm_destroy_ahead(ahead);
  700.             return GBM_ERR_READ;
  701.             }
  702.     }
  703.     break;
  704. /*...e*/
  705.         }
  706.  
  707.     gbm_destroy_ahead(ahead);
  708.  
  709.     return GBM_ERR_OK;
  710.     }
  711. /*...e*/
  712. /*...slbm_w:0:*/
  713. /*...swrite_bmhd:0:*/
  714. static GBM_ERR write_bmhd(int fd, const GBM *gbm, int bpp, const char *opt)
  715.     {
  716.     byte bmhd[8+20];
  717.     int xpos = 0, ypos = 0, transcol = 0, xaspect = 1, yaspect = 1;
  718.     int xscreen = gbm->w, yscreen = gbm->h;
  719.  
  720. /*...soutput options:8:*/
  721. {
  722. const char *s;
  723.  
  724. if ( (s = gbm_find_word_prefix(opt, "xpos=")) != NULL )
  725.     sscanf(s + 5, "%d", &xpos);
  726.  
  727. if ( (s = gbm_find_word_prefix(opt, "ypos=")) != NULL )
  728.     sscanf(s + 5, "%d", &ypos);
  729.  
  730. if ( (s = gbm_find_word_prefix(opt, "transcol=")) != NULL )
  731.     sscanf(s + 9, "%d", &transcol);
  732.  
  733. if ( (s = gbm_find_word_prefix(opt, "xaspect=")) != NULL )
  734.     sscanf(s + 8, "%d", &xaspect);
  735.  
  736. if ( (s = gbm_find_word_prefix(opt, "yaspect=")) != NULL )
  737.     sscanf(s + 8, "%d", &yaspect);
  738.  
  739. if ( (s = gbm_find_word_prefix(opt, "xscreen=")) != NULL )
  740.     sscanf(s + 8, "%d", &xscreen);
  741.  
  742. if ( (s = gbm_find_word_prefix(opt, "yscreen=")) != NULL )
  743.     sscanf(s + 8, "%d", &yscreen);
  744. }
  745. /*...e*/
  746.  
  747.     memcpy(bmhd, "BMHD", 4);
  748.     put_dword(bmhd+4, (dword) 20);
  749.     put_word(bmhd+8, (word) gbm->w);
  750.     put_word(bmhd+8+2, (word) gbm->h);
  751.     put_word(bmhd+8+4, (word) xpos);
  752.     put_word(bmhd+8+6, (word) ypos);
  753.     bmhd[8+8] = (byte) bpp;
  754.  
  755.     bmhd[8+9] = 0;            /* Masking 0=None, 1=Mask, 2=Transparent, 3=Lasso */
  756.     bmhd[8+10] = 1;            /* Compression, 0=None, 1=RLE */
  757.     bmhd[8+11] = 0;            /* Unused */
  758.     put_word(bmhd+8+12, (word) transcol); /* Transparent colour */
  759.     bmhd[8+14] = (byte) xaspect;    /* X Aspect (often 10) */
  760.     bmhd[8+15] = (byte) yaspect;    /* Y Aspect (often 11) */
  761.  
  762.     put_word(bmhd+8+16, (word) xscreen);    /* Screen width */
  763.     put_word(bmhd+8+18, (word) yscreen);    /* Screen height */
  764.  
  765.     if ( gbm_file_write(fd, bmhd, 8+20) != 8+20 )
  766.         return GBM_ERR_WRITE;
  767.  
  768.     return GBM_ERR_OK;
  769.     }
  770. /*...e*/
  771. /*...swrite_camg:0:*/
  772. static GBM_ERR write_camg(int fd, dword camg_value)
  773.     {
  774.     byte camg[8+4];
  775.  
  776.     memcpy(camg, "CAMG", 4);
  777.     put_dword(camg+4, (dword) 4);
  778.     put_dword(camg+8, camg_value);
  779.  
  780.     if ( gbm_file_write(fd, camg, 8+4) != 8+4 )
  781.         return GBM_ERR_WRITE;
  782.  
  783.     return GBM_ERR_OK;
  784.     }
  785. /*...e*/
  786. /*...swrite_cmap:0:*/
  787. static GBM_ERR write_cmap(int fd, const GBMRGB *gbmrgb, int bpp)
  788.     {
  789.     byte cmap[8+0x100*3];
  790.     int i, entrys = ( 1 << bpp );
  791.     int size_cmap = 3 * entrys;
  792.  
  793.     memcpy(cmap, "CMAP", 4);
  794.     put_dword(cmap+4, (dword) size_cmap);
  795.     for ( i = 0; i < entrys; i++ )
  796.         {
  797.         cmap[8+i*3+0] = gbmrgb[i].r;
  798.         cmap[8+i*3+1] = gbmrgb[i].g;
  799.         cmap[8+i*3+2] = gbmrgb[i].b;
  800.         }
  801.  
  802.     if ( gbm_file_write(fd, cmap, 8 + size_cmap) != 8 + size_cmap )
  803.         return GBM_ERR_WRITE;
  804.  
  805.     return GBM_ERR_OK;
  806.     }
  807. /*...e*/
  808. /*...swrite_body:0:*/
  809. /*...slbm_rle:0:*/
  810. /*...slbm_run:0:*/
  811. static byte lbm_run(const byte *src, int n_src)
  812.     {
  813.     byte cnt = 1;
  814.     byte b = *src++;
  815.  
  816.     --n_src;
  817.     while ( cnt < 0x81 && n_src > 0 && *src == b )
  818.         { cnt++; n_src--; src++; }
  819.  
  820.     return cnt;
  821.     }
  822. /*...e*/
  823. /*...slbm_lit:0:*/
  824. static byte lbm_lit(const byte *src, int n_src)
  825.     {
  826.     byte cnt = 1;
  827.  
  828.     ++src; --n_src;
  829.     while ( cnt < 0x80 && n_src > 0 && *src != src[-1] )
  830.         { cnt++; n_src--; src++; }
  831.  
  832.     return cnt;
  833.     }
  834. /*...e*/
  835.  
  836. static void lbm_rle(const byte *src, int n_src, byte *dst, int *n_dst)
  837.     {
  838.     *n_dst = 0;    
  839.     while ( n_src )
  840.         {
  841.         byte    len;
  842.  
  843.         if ( (len = lbm_run(src, n_src)) > 1 )
  844.             {
  845.             *dst++ = (byte) (0x100 - (len - 1));
  846.             *dst++ = *src;
  847.             (*n_dst) += 2;
  848.             }
  849.         else
  850.             {
  851.             len = lbm_lit(src, n_src);
  852.             *dst++ = (byte) (len - 1);
  853.             memcpy(dst, src, len);
  854.             dst += len;
  855.             (*n_dst) += ( 1 + len );
  856.             }
  857.         src += len;
  858.         n_src -= len;
  859.         }
  860.     }
  861. /*...e*/
  862.  
  863. static GBM_ERR write_body(int fd, const GBM *gbm, int bpp, int n_planes, const byte *data, long *end)
  864.     {
  865.     int scan = ((((gbm->w + 7) / 8)+1)/2)*2;
  866.     int stride = ((gbm->w * bpp + 31) / 32) * 4;
  867.     byte *comp;
  868.     int n_comp;
  869.     byte body[8];
  870.     long offset_body, offset_end;
  871.  
  872.     memcpy(body, "BODY", 4);
  873.     /* body[4..7] will be filled in later */
  874.  
  875.     if ( gbm_file_write(fd, body, 8) != 8 )
  876.         return GBM_ERR_WRITE;
  877.  
  878.     offset_body = gbm_file_lseek(fd, 0L, SEEK_CUR);
  879.  
  880.     data += ( gbm->h - 1 ) * stride;
  881.  
  882.     if ( (comp = malloc((size_t) (scan * 3))) == NULL )
  883.         return GBM_ERR_MEM;
  884.  
  885.     switch ( bpp )
  886.         {
  887. /*...s24:16:*/
  888. case 24:
  889.     {
  890.     int y, c, p, plane, j;
  891.     byte *buf;
  892.  
  893.     if ( (buf = malloc((size_t) scan)) == NULL )
  894.         {
  895.         free(comp);
  896.         return GBM_ERR_MEM;
  897.         }
  898.  
  899.     for ( y = 0; y < gbm->h; y++, data -= stride )
  900.         for ( c = 2; c >= 0; c-- )
  901.             for ( plane = 0, p = 0x01; plane < 8; plane++, p <<= 1 )
  902.                 {
  903.                 memset(buf, 0, scan);
  904.                 for ( j = 0; j < gbm->w; j++ )
  905.                     if ( data[c+j*3] & p )
  906.                         buf[(unsigned)j >> 3] |= (0x80U >> ((unsigned)j & 7U));
  907.                 lbm_rle(buf, scan, comp, &n_comp);
  908.                 if ( gbm_file_write(fd, comp, n_comp) != n_comp )
  909.                     {
  910.                     free(buf);
  911.                     free(comp);
  912.                     return GBM_ERR_WRITE;
  913.                     }
  914.                 }
  915.     free(buf);
  916.     }
  917.     break;
  918. /*...e*/
  919. /*...s8:16:*/
  920. case 8:
  921.     {
  922.     int y, p, plane, j;
  923.     byte *buf;
  924.  
  925.     if ( (buf = malloc((size_t) scan)) == NULL )
  926.         {
  927.         free(comp);
  928.         return GBM_ERR_MEM;
  929.         }
  930.  
  931.     for ( y = 0; y < gbm->h; y++, data -= stride )
  932.         for ( plane = 0, p = 0x01; plane < n_planes; plane++, p <<= 1 )
  933.             {
  934.             memset(buf, 0, scan);
  935.             for ( j = 0; j < gbm->w; j++ )
  936.                 if ( data[j] & p )
  937.                     buf[(unsigned)j >> 3] |= (0x80U >> ((unsigned)j & 7U));
  938.             lbm_rle(buf, scan, comp, &n_comp);
  939.             if ( gbm_file_write(fd, comp, n_comp) != n_comp )
  940.                 {
  941.                 free(buf);
  942.                 free(comp);
  943.                 return GBM_ERR_WRITE;
  944.                 }
  945.             }
  946.     free(buf);
  947.     }
  948.     break;
  949. /*...e*/
  950. /*...s4:16:*/
  951. case 4:
  952.     {
  953.     int y, p, j, mask;
  954.     byte *buf;
  955.  
  956.     if ( (buf = malloc((size_t) scan)) == NULL )
  957.         {
  958.         free(comp);
  959.         return GBM_ERR_MEM;
  960.         }
  961.  
  962.     for ( y = 0; y < gbm->h; y++, data -= stride )
  963.         for ( p = 0x11; p <= 0x88; p <<= 1 )
  964.             {
  965.             memset(buf, 0, scan);
  966.             for ( j = 0, mask = 0xf0; j < gbm->w; j++, mask ^= 0xff )
  967.                 if ( data[(unsigned)j >> 1] & ((unsigned)p & (unsigned)mask) )
  968.                     buf[(unsigned)j >> 3] |= (0x80U >> ((unsigned)j & 7U));
  969.             lbm_rle(buf, scan, comp, &n_comp);
  970.             if ( gbm_file_write(fd, comp, n_comp) != n_comp )
  971.                 {
  972.                 free(buf);
  973.                 free(comp);
  974.                 return GBM_ERR_WRITE;
  975.                 }
  976.             }
  977.     free(buf);
  978.     }
  979.     break;
  980. /*...e*/
  981. /*...s1:16:*/
  982. case 1:
  983.     {
  984.     int y;
  985.  
  986.     for ( y = 0; y < gbm->h; y++, data -= stride )
  987.         {
  988.         lbm_rle(data, scan, comp, &n_comp);
  989.         if ( gbm_file_write(fd, comp, n_comp) != n_comp )
  990.             {
  991.             free(comp);
  992.             return GBM_ERR_WRITE;
  993.             }
  994.         }
  995.     }
  996.     break;
  997. /*...e*/
  998.         }
  999.  
  1000.     free(comp);
  1001.  
  1002.     offset_end = gbm_file_lseek(fd, 0L, SEEK_CUR);
  1003.  
  1004.     if ( (offset_end - offset_body) & 1 )
  1005.         /* BODY is an odd # of bytes long! oops, better 'fix' this */
  1006.         {
  1007.         byte b = 0; /* Pad byte must be zero */
  1008.         if ( gbm_file_write(fd, &b, 1) != 1 )
  1009.             return GBM_ERR_WRITE;
  1010.         offset_end++;
  1011.         }
  1012.  
  1013.     put_dword(body + 4, offset_end - offset_body);
  1014.     gbm_file_lseek(fd, offset_body - 4L, SEEK_SET);
  1015.     if ( gbm_file_write(fd, body + 4, 4) != 4 )
  1016.         return GBM_ERR_WRITE;
  1017.  
  1018.     *end = offset_end;
  1019.  
  1020.     return GBM_ERR_OK;
  1021.     }
  1022. /*...e*/
  1023.  
  1024. static byte posdiff[0x100];
  1025. #define    absdiff(a,b) posdiff[(byte)((a)-(b))]
  1026. /*...slbm_build_abstab:0:*/
  1027. static void lbm_build_abstab(void)
  1028.     {
  1029.     int i;
  1030.  
  1031.     for ( i = 0; i < 0x80; i++ )
  1032.         posdiff[i] = (byte) i;
  1033.     for ( i = 1; i <= 0x80; i++ )
  1034.         posdiff[0x100 - i] = (byte) i;
  1035.     }
  1036. /*...e*/
  1037. /*...slbm_ham6:0:*/
  1038. /*
  1039. We will assume a simple greyscale palette, to make life easy.
  1040. Palette entries 0 to 15 will be 00, 11, 22, 33, ... ff.
  1041. Start the line with a close grey.
  1042. Try to get as many components right first time.
  1043. Then for each pixel, pick colours to get as many components right each go.
  1044. */
  1045.  
  1046. static void lbm_ham6(const byte *data, byte *ham, int n)
  1047.     {
  1048.     if ( n-- > 0 )
  1049.         {
  1050.         byte cb = (*data++ >> 4);
  1051.         byte cg = (*data++ >> 4);
  1052.         byte cr = (*data++ >> 4);
  1053.  
  1054.         switch ( (cr==cg?4:0) + (cg==cb?2:0) + (cb==cr?1:0) )
  1055.             {
  1056. /*...s0 \45\ none same:24:*/
  1057. case 0:
  1058.     *ham++ = cr = cg = cb = ( cr + cg + cb ) / 3;
  1059.     break;
  1060. /*...e*/
  1061. /*...s1 \45\ r\61\b:24:*/
  1062. case 1:
  1063.     *ham++ = cg = cr;
  1064.     break;
  1065. /*...e*/
  1066. /*...s2 \45\ g\61\b:24:*/
  1067. case 2:
  1068.     *ham++ = cr = cg;
  1069.     break;
  1070. /*...e*/
  1071. /*...s4 \45\ r\61\g:24:*/
  1072. case 4:
  1073.     *ham++ = cb = cr;
  1074.     break;
  1075. /*...e*/
  1076. /*...s7 \45\ r\61\g\61\b:24:*/
  1077. case 7:
  1078.     *ham++ = cr;
  1079.     break;
  1080. /*...e*/
  1081.             }
  1082.  
  1083.         while ( n-- > 0 )
  1084.             {
  1085.             byte b = (*data++ >> 4);
  1086.             byte g = (*data++ >> 4);
  1087.             byte r = (*data++ >> 4);
  1088.  
  1089.             switch ( ((cr==r)?4:0) + ((cg==g)?2:0) + ((cb==b)?1:0) )
  1090.                 {
  1091. /*...s0 \45\ none same:32:*/
  1092. /*
  1093. 3 colour components need modifying.
  1094. Can take upto 3 pixels to get the desired colour.
  1095. Picking a grey might fix up 2 or more colour components.
  1096. Pick r,g or b modify to get as close as possible.
  1097. */
  1098.  
  1099. case 0:
  1100.     if ( ((r==g)?1:0) + ((g==b)?1:0) + ((b==r)?1:0) > 0 )
  1101.         { *ham++ = cr = cg = cb = ( (r==g) ? r : b ); }
  1102.     else if ( absdiff(cr,r) >= absdiff(cg,g) && absdiff(cr,r) >= absdiff(cb,b) )
  1103.         { *ham++ = (0x20 | r); cr = r; }
  1104.     else if ( absdiff(cg,g) >= absdiff(cr,r) && absdiff(cg,g) >= absdiff(cb,b) )
  1105.          { *ham++ = (0x30 | g); cg = g; }
  1106.     else
  1107.         { *ham++ = (0x10 | b); cb = b; }
  1108.     break;
  1109. /*...e*/
  1110. /*...s1 \45\ b same:32:*/
  1111. /*
  1112. 2 colour components need modifying.
  1113. Can take upto 2 pixels to get the desired colour.
  1114. Picking a grey might fix up both colour components.
  1115. Pick r or g modify to get as close as possible.
  1116. After this, we expect to have <= 1 colour components in error.
  1117. */
  1118.  
  1119. case 1:
  1120.     if ( r == g && g == b )
  1121.         { *ham++ = cr = cg = b; }
  1122.     else if ( absdiff(cr,r) >= absdiff(cg,g) )
  1123.         { *ham++ = (0x20 | r); cr = r; }
  1124.     else
  1125.         { *ham++ = (0x30 | g); cg = g; }
  1126.     break;
  1127. /*...e*/
  1128. /*...s2 \45\ g same:32:*/
  1129. /*
  1130. 2 colour components need modifying.
  1131. Can take upto 2 pixels to get the desired colour.
  1132. Picking a grey might fix up both colour components.
  1133. Pick r or b modify to get as close as possible.
  1134. After this, we expect to have <= 1 colour components in error.
  1135. */
  1136.  
  1137. case 2:
  1138.     if ( r == g && g == b )
  1139.         { *ham++ = cr = cb = g; }
  1140.     else if ( absdiff(cr,r) >= absdiff(cb,b) )
  1141.         { *ham++ = (0x20 | r); cr = r; }
  1142.     else
  1143.         { *ham++ = (0x10 | b); cb = b; }
  1144.     break;
  1145. /*...e*/
  1146. /*...s3 \45\ g\44\b same:32:*/
  1147. case 3:
  1148.     *ham++ = (0x20 | r); cr = r;
  1149.     break;
  1150. /*...e*/
  1151. /*...s4 \45\ r same:32:*/
  1152. /*
  1153. 2 colour components need modifying.
  1154. Can take upto 2 pixels to get the desired colour.
  1155. Picking a grey might fix up both colour components.
  1156. Pick g or b modify to get as close as possible.
  1157. After this, we expect to have <= 1 colour components in error.
  1158. */
  1159.  
  1160. case 4:
  1161.     if ( r == g && g == b )
  1162.         { *ham++ = cg = cb = r; }
  1163.     else if ( absdiff(cg,g) >= absdiff(cb,b) )
  1164.         { *ham++ = (0x30 | g); cg = g; }
  1165.     else
  1166.         { *ham++ = (0x10 | b); cb = b; }
  1167.     break;
  1168. /*...e*/
  1169. /*...s5 \45\ r\44\b same:32:*/
  1170. case 5:
  1171.     *ham++ = (0x30 | g); cg = g;
  1172.     break;
  1173. /*...e*/
  1174. /*...s6 \45\ r\44\g same:32:*/
  1175. case 6:
  1176.     *ham++ = (0x10 | b); cb = b;
  1177.     break;
  1178. /*...e*/
  1179. /*...s7 \45\ r\44\g\44\b same:32:*/
  1180. case 7:
  1181.     *ham++ = (0x10 | b);
  1182.     break;
  1183. /*...e*/
  1184.                 }
  1185.             }
  1186.         }
  1187.     }
  1188. /*...e*/
  1189.  
  1190. GBM_ERR lbm_w(const char *fn, int fd, const GBM *gbm, const GBMRGB *gbmrgb, const byte *data, const char *opt)
  1191.     {
  1192.     byte formilbm[8+4];
  1193.     long end;
  1194.     GBM_ERR    rc;
  1195.     BOOLEAN ham6 = ( gbm_find_word(opt, "ham6") != NULL );
  1196.  
  1197.     fn=fn; /* Suppress 'unref args' compiler warning */
  1198.  
  1199.     memcpy(formilbm, "FORM", 4);
  1200.     /* formilbm[4..7] will be filled in later */
  1201.     memcpy(formilbm+8, "ILBM", 4);
  1202.     if ( gbm_file_write(fd, formilbm, 8+4) != 8+4 )
  1203.         return GBM_ERR_WRITE;
  1204.  
  1205.     if ( gbm->bpp == 24 )
  1206.         {
  1207.         if ( ham6 )
  1208. /*...smap to ham6 write bmhd\44\ camg\44\ cmap and body:24:*/
  1209. {
  1210. byte *ham;
  1211. GBMRGB gbmrgb_grey[0x10];
  1212. int stride8 = ((gbm->w + 3) & ~3);
  1213. int stride24 = ((gbm->w * 3 + 3) & ~3);
  1214. int i;
  1215.  
  1216. if ( (rc = write_bmhd(fd, gbm, 6, opt)) != GBM_ERR_OK )
  1217.     return rc;
  1218.  
  1219. if ( (rc = write_camg(fd, CAMG_HAM)) != GBM_ERR_OK )
  1220.     return rc;
  1221.  
  1222. for ( i = 0; i <= 0x10; i++ )
  1223.     gbmrgb_grey[i].r = gbmrgb_grey[i].g = gbmrgb_grey[i].b = (byte) (i * 0x11);
  1224.  
  1225. if ( (rc = write_cmap(fd, gbmrgb_grey, 4)) != GBM_ERR_OK )
  1226.     return rc;
  1227.  
  1228. if ( (ham = malloc((size_t) (stride8 * gbm->h))) == NULL )
  1229.     return GBM_ERR_MEM;
  1230.  
  1231. lbm_build_abstab();
  1232. for ( i = 0; i < gbm->h; i++ )
  1233.     lbm_ham6(data + i * stride24, ham + i * stride8, gbm->w);
  1234.  
  1235. if ( (rc = write_body(fd, gbm, 8, 6, ham, &end)) != GBM_ERR_OK )
  1236.     {
  1237.     free(ham);
  1238.     return rc;
  1239.     }
  1240.  
  1241. free(ham);
  1242. }
  1243. /*...e*/
  1244.         else
  1245. /*...swrite bmhd and body:24:*/
  1246. {
  1247. if ( (rc = write_bmhd(fd, gbm, gbm->bpp, opt)) != GBM_ERR_OK )
  1248.     return rc;
  1249. if ( (rc = write_body(fd, gbm, gbm->bpp, gbm->bpp, data, &end)) != GBM_ERR_OK )
  1250.     return rc;
  1251. }
  1252. /*...e*/
  1253.         }
  1254.     else
  1255. /*...swrite bmhd\44\ cmap and body:16:*/
  1256. {
  1257. if ( (rc = write_bmhd(fd, gbm, gbm->bpp, opt)) != GBM_ERR_OK )
  1258.     return rc;
  1259.  
  1260. if ( (rc = write_cmap(fd, gbmrgb, gbm->bpp)) != GBM_ERR_OK )
  1261.     return rc;
  1262.  
  1263. if ( (rc = write_body(fd, gbm, gbm->bpp, gbm->bpp, data, &end)) != GBM_ERR_OK )
  1264.     return rc;
  1265. }
  1266. /*...e*/
  1267.  
  1268.     put_dword(formilbm + 4, end - 8L);
  1269.     gbm_file_lseek(fd, 4L, SEEK_SET);
  1270.     if ( gbm_file_write(fd, formilbm + 4, 4) != 4 )
  1271.         return GBM_ERR_WRITE;
  1272.  
  1273.     return GBM_ERR_OK;
  1274.     }
  1275. /*...e*/
  1276. /*...slbm_err:0:*/
  1277. const char *lbm_err(GBM_ERR rc)
  1278.     {
  1279.     switch ( (int) rc )
  1280.         {
  1281.         case GBM_ERR_LBM_FORM:
  1282.             return "no FORM signiture";
  1283.         case GBM_ERR_LBM_ILBM:
  1284.             return "no ILBM signiture";
  1285.         case GBM_ERR_LBM_BMHD_2:
  1286.             return "multiple BMHD bitmap headers";
  1287.         case GBM_ERR_LBM_BMHD_0:
  1288.             return "no BMHD bitmap header";
  1289.         case GBM_ERR_LBM_BMHD_SIZE:
  1290.             return "bad size of BMHD bitmap header";
  1291.         case GBM_ERR_LBM_BPP:
  1292.             return "unsupported/bad bits per pixel";
  1293.         case GBM_ERR_LBM_CMAP_SIZE:
  1294.             return "CMAP colour map is the wrong size";
  1295.         case GBM_ERR_LBM_COMP:
  1296.             return "compression type not uncompressed nor RLE";
  1297.         case GBM_ERR_LBM_CAMG_SIZE:
  1298.             return "CAMG chunk is the wrong size";
  1299.         case GBM_ERR_LBM_SHAM_VER:
  1300.             return "Unsupported version of SHAM (not 0)";
  1301.         }
  1302.     return NULL;
  1303.     }
  1304. /*...e*/
  1305.