home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / rexx / library2 / gbmrexx / gbm / gbmlbm.c < prev    next >
C/C++ Source or Header  |  1993-09-27  |  27KB  |  1,296 lines

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