home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / rexx / library2 / gbmrexx / gbm / gbmbmp.c < prev    next >
C/C++ Source or Header  |  1993-09-12  |  18KB  |  873 lines

  1. /*
  2.  
  3. GBMBMP.C  OS/2 1.1, 1.2, 2.0 and Windows 3.0 support
  4.  
  5. Reads and writes any OS/2 1.x bitmap.
  6. Will also read uncompressed, RLE4 and RLE8 Windows 3.x bitmaps too.
  7. There are horrific file structure alignment considerations hence each
  8. word,dword is read individually.
  9. Input options: index=# (default: 0)
  10.  
  11. */
  12.  
  13. /*...sincludes:0:*/
  14. #include <stdio.h>
  15. #include <ctype.h>
  16. #include <stddef.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <memory.h>
  20. #include <malloc.h>
  21. #ifdef AIX
  22. #include <unistd.h>
  23. #else
  24. #include <io.h>
  25. #endif
  26. #include <fcntl.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include "standard.h"
  30. #include "gbm.h"
  31.  
  32. /*...vgbm\46\h:0:*/
  33.  
  34. #ifndef min
  35. #define    min(a,b)    (((a)<(b))?(a):(b))
  36. #endif
  37. /*...e*/
  38.  
  39. /*...suseful:0:*/
  40. #define    low_byte(w)    ((byte)  ((w)&0x00ff)    )
  41. #define    high_byte(w)    ((byte) (((w)&0xff00)>>8))
  42. #define    make_word(a,b)    (((word)a) + (((word)b) << 8))
  43. /*...e*/
  44. /*...ssame:0:*/
  45. static BOOLEAN same(char *s1, char *s2, int n)
  46.     {
  47.     for ( ; n--; s1++, s2++ )
  48.         if ( tolower(*s1) != tolower(*s2) )
  49.             return ( FALSE );
  50.     return ( TRUE );
  51.     }
  52. /*...e*/
  53. /*...sfind_word:0:*/
  54. static char *find_word(char *str, char *substr)
  55.     {
  56.     char    buf [100+1], *s;
  57.     int    len = strlen(substr);
  58.  
  59.     for ( s  = strtok(strcpy(buf, str), " \t,");
  60.           s != NULL;
  61.           s  = strtok(NULL, " \t,") )
  62.         if ( same(s, substr, len) && s [len] == '\0' )
  63.             return ( str + (s - buf) );
  64.     return ( NULL );
  65.     }
  66. /*...e*/
  67. /*...sfind_word_prefix:0:*/
  68. static char *find_word_prefix(char *str, char *substr)
  69.     {
  70.     char    buf [100+1], *s;
  71.     int    len = strlen(substr);
  72.  
  73.     for ( s  = strtok(strcpy(buf, str), " \t,");
  74.           s != NULL;
  75.           s  = strtok(NULL, " \t,") )
  76.         if ( same(s, substr, len) )
  77.             return ( str + (s - buf) );
  78.     return ( NULL );
  79.     }
  80. /*...e*/
  81.  
  82. /*...sread_word:0:*/
  83. static BOOLEAN read_word(int fd, word *w)
  84.     {
  85.     byte    low = 0, high = 0;
  86.  
  87.     read(fd, (char *) &low, 1);
  88.     read(fd, (char *) &high, 1);
  89.     *w = (word) (low + ((word) high << 8));
  90.     return ( TRUE );
  91.     }
  92. /*...e*/
  93. /*...sread_dword:0:*/
  94. static BOOLEAN read_dword(int fd, dword *d)
  95.     {
  96.     word    low, high;
  97.  
  98.     read_word(fd, &low);
  99.     read_word(fd, &high);
  100.     *d = low + ((dword) high << 16);
  101.     return ( TRUE );
  102.     }
  103. /*...e*/
  104. /*...swrite_word:0:*/
  105. static BOOLEAN write_word(int fd, word w)
  106.     {
  107.     byte    low  = (byte) w;
  108.     byte    high = (byte) (w >> 8);
  109.  
  110.     write(fd, &low, 1);
  111.     write(fd, &high, 1);
  112.     return ( TRUE );
  113.     }
  114. /*...e*/
  115. /*...swrite_dword:0:*/
  116. static BOOLEAN write_dword(int fd, dword d)
  117.     {
  118.     write_word(fd, (word) d);
  119.     write_word(fd, (word) (d >> 16));
  120.     return ( TRUE );
  121.     }
  122. /*...e*/
  123. /*...sreading ahead:0:*/
  124. #define    AHEAD_BUF    0x4000
  125.  
  126. typedef struct
  127.     {
  128.     byte    buf [AHEAD_BUF];
  129.     int    inx, cnt;
  130.     int    fd;
  131.     } AHEAD;
  132.  
  133. static AHEAD *create_ahead(int fd)
  134.     {
  135.     AHEAD *ahead;
  136.  
  137.     if ( (ahead = malloc(sizeof(AHEAD))) == NULL )
  138.         return ( NULL );
  139.  
  140.     ahead -> inx = 0;
  141.     ahead -> cnt = 0;
  142.     ahead -> fd  = fd;
  143.  
  144.     return ( ahead );
  145.     }
  146.  
  147. static void destroy_ahead(AHEAD *ahead)
  148.     {
  149.     free(ahead);
  150.     }    
  151.  
  152. static byte next(AHEAD *ahead)
  153.     {
  154.     if ( ahead -> inx >= ahead -> cnt )
  155.         {
  156.         ahead -> cnt = read(ahead -> fd, (char *) ahead -> buf, AHEAD_BUF);
  157.         ahead -> inx = 0;
  158.         }
  159.     return ( ahead -> buf [ahead -> inx++] );
  160.     }
  161. /*...e*/
  162.  
  163. static GBMFT bmp_gbmft =
  164.     {
  165.     "Bitmap",
  166.     "OS/2 1.1, 1.2, 2.0 / Windows 3.0 bitmap",
  167.     "BMP VGA BGA RLE DIB RL4 RL8",
  168.     GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|GBM_FT_R24|
  169.     GBM_FT_W1|GBM_FT_W4|GBM_FT_W8|GBM_FT_W24,
  170.     };
  171.  
  172. #define    GBM_ERR_BMP_PLANES    ((GBM_ERR) 300)
  173. #define    GBM_ERR_BMP_BITCOUNT    ((GBM_ERR) 301)
  174. #define    GBM_ERR_BMP_CBFIX    ((GBM_ERR) 302)
  175. #define    GBM_ERR_BMP_COMP    ((GBM_ERR) 303)
  176. #define    GBM_ERR_BMP_OFFSET    ((GBM_ERR) 304)
  177.  
  178. typedef struct
  179.     {
  180.     dword    base;
  181.     BOOLEAN    windows;
  182.     dword    cbFix;
  183.     dword    ulCompression;
  184.     dword    cclrUsed;
  185.     dword    offBits;
  186.     BOOLEAN    inv, invb;
  187.     } BMP_PRIV;
  188.  
  189. #define    BFT_BMAP    0x4d42
  190. #define    BFT_BITMAPARRAY    0x4142
  191. #define    BCA_UNCOMP    0x00000000L
  192. #define    BCA_RLE8    0x00000001L
  193. #define    BCA_RLE4    0x00000002L
  194. #define    BCA_HUFFFMAN1D    0x00000003L
  195. #define    BCA_RLE24    0x00000004L
  196. #define    MSWCC_EOL    0
  197. #define    MSWCC_EOB    1
  198. #define    MSWCC_DELTA    2
  199.  
  200. /*...sinvert:0:*/
  201. static void invert(byte *buffer, unsigned count)
  202.     {
  203.     while ( count-- )
  204.         *buffer++ ^= (byte) 0xff;
  205.     }
  206. /*...e*/
  207. /*...sswap_pal:0:*/
  208. static void swap_pal(GBMRGB *gbmrgb)
  209.     {
  210.     GBMRGB tmp = gbmrgb [0];
  211.     gbmrgb [0] = gbmrgb [1];
  212.     gbmrgb [1] = tmp;
  213.     }
  214. /*...e*/
  215.  
  216. /*...sbmp_qft:0:*/
  217. GBM_ERR bmp_qft(GBMFT *gbmft)
  218.     {
  219.     *gbmft = bmp_gbmft;
  220.     return ( GBM_ERR_OK );
  221.     }
  222. /*...e*/
  223. /*...sbmp_rhdr:0:*/
  224. GBM_ERR bmp_rhdr(char *fn, int fd, GBM *gbm, char *opt)
  225.     {
  226.     word    usType, xHotspot, yHotspot;
  227.     dword    cbSize, offBits, cbFix;
  228.     BMP_PRIV *bmp_priv = (BMP_PRIV *) gbm -> priv;
  229.     bmp_priv -> inv  = ( find_word(opt, "inv" ) != NULL );
  230.     bmp_priv -> invb = ( find_word(opt, "invb") != NULL );
  231.  
  232.     fn=fn; /* Suppress 'unref arg' compiler warnings */
  233.  
  234.     lseek(fd, 0L, SEEK_SET);
  235.  
  236.     read_word(fd, &usType);
  237.     if ( usType == BFT_BITMAPARRAY )
  238. /*...shandle bitmap arrays:16:*/
  239. {
  240. char    *index;
  241. int    i;
  242.  
  243. if ( (index = find_word_prefix(opt, "index=")) != NULL )
  244.     sscanf(index + 6, "%d", &i);
  245. else
  246.     i = 0;
  247.  
  248. while ( i-- > 0 )
  249.     {
  250.     dword    cbSize2, offNext;
  251.  
  252.     read_dword(fd, &cbSize2);
  253.     read_dword(fd, &offNext);
  254.     if ( offNext == 0L )
  255.         return ( GBM_ERR_BMP_OFFSET );
  256.     lseek(fd, (long) offNext, SEEK_SET);
  257.     read_word(fd, &usType);
  258.     if ( usType != BFT_BITMAPARRAY )
  259.         return ( GBM_ERR_BAD_MAGIC );
  260.     }
  261. lseek(fd, 4L + 4L + 2L + 2L, SEEK_CUR);
  262. read_word(fd, &usType);
  263. }
  264. /*...e*/
  265.  
  266.     if ( usType != BFT_BMAP )
  267.         return ( GBM_ERR_BAD_MAGIC );
  268.  
  269.     bmp_priv -> base = lseek(fd, 0L, SEEK_CUR) - 2L;
  270.  
  271.     read_dword(fd, &cbSize);
  272.     read_word(fd, &xHotspot);
  273.     read_word(fd, &yHotspot);
  274.     read_dword(fd, &offBits);
  275.     read_dword(fd, &cbFix);
  276.  
  277.     bmp_priv -> offBits = offBits;
  278.  
  279.     if ( cbFix == 12 )
  280. /*...sOS\47\2 1\46\1\44\ 1\46\2:16:*/
  281. /* OS/2 1.x uncompressed bitmap */
  282. {
  283. word    cx, cy, cPlanes, cBitCount;
  284.  
  285. read_word(fd, &cx);
  286. read_word(fd, &cy);
  287. read_word(fd, &cPlanes);
  288. read_word(fd, &cBitCount);
  289.  
  290. if ( cx == 0 || cy == 0 )
  291.     return ( GBM_ERR_BAD_SIZE );
  292. if ( cPlanes != 1 )
  293.     return ( GBM_ERR_BMP_PLANES );
  294. if ( cBitCount != 1 && cBitCount != 4 && cBitCount != 8 && cBitCount != 24 )
  295.     return ( GBM_ERR_BMP_BITCOUNT );
  296.  
  297. gbm -> w   = (int) cx;
  298. gbm -> h   = (int) cy;
  299. gbm -> bpp = (int) cBitCount;
  300.  
  301. bmp_priv -> windows = FALSE;
  302. }
  303. /*...e*/
  304.     else if ( cbFix >= 16 && cbFix <= 64 &&
  305.               ((cbFix & 3) == 0 || cbFix == 42 || cbFix == 46) )
  306. /*...sOS\47\2 2\46\0 and Windows 3\46\0:16:*/
  307. {
  308. word    cPlanes, cBitCount, usUnits, usReserved, usRecording, usRendering;
  309. dword    ulWidth, ulHeight, ulCompression;
  310. dword    ulSizeImage, ulXPelsPerMeter, ulYPelsPerMeter;
  311. dword    cclrUsed, cclrImportant, cSize1, cSize2, ulColorEncoding, ulIdentifier;
  312.  
  313. read_dword(fd, &ulWidth);
  314. read_dword(fd, &ulHeight);
  315. read_word(fd, &cPlanes);
  316. read_word(fd, &cBitCount);
  317. if ( cbFix > 16 )
  318.     read_dword(fd, &ulCompression);
  319. else
  320.     ulCompression = BCA_UNCOMP;
  321. if ( cbFix > 20 )
  322.     read_dword(fd, &ulSizeImage);
  323. if ( cbFix > 24 )
  324.     read_dword(fd, &ulXPelsPerMeter);
  325. if ( cbFix > 28 )
  326.     read_dword(fd, &ulYPelsPerMeter);
  327. if ( cbFix > 32 )
  328.     read_dword(fd, &cclrUsed);
  329. else
  330.     cclrUsed = ( 1 << cBitCount );
  331. if ( cBitCount != 24 && cclrUsed == 0 )
  332.     cclrUsed = ( 1 << cBitCount );
  333. if ( cbFix > 36 )
  334.     read_dword(fd, &cclrImportant);
  335. if ( cbFix > 40 )
  336.     read_word(fd, &usUnits);
  337. if ( cbFix > 42 )
  338.     read_word(fd, &usReserved);
  339. if ( cbFix > 44 )
  340.     read_word(fd, &usRecording);
  341. if ( cbFix > 46 )
  342.     read_word(fd, &usRendering);
  343. if ( cbFix > 48 )
  344.     read_dword(fd, &cSize1);
  345. if ( cbFix > 52 )
  346.     read_dword(fd, &cSize2);
  347. if ( cbFix > 56 )
  348.     read_dword(fd, &ulColorEncoding);
  349. if ( cbFix > 60 )
  350.     read_dword(fd, &ulIdentifier);
  351.  
  352. if ( ulWidth == 0L || ulHeight == 0L )
  353.     return ( GBM_ERR_BAD_SIZE );
  354. if ( cPlanes != 1 )
  355.     return ( GBM_ERR_BMP_PLANES );
  356. if ( cBitCount != 1 && cBitCount != 4 && cBitCount != 8 && cBitCount != 24 )
  357.     return ( GBM_ERR_BMP_BITCOUNT );
  358.  
  359. gbm -> w   = (int) ulWidth;
  360. gbm -> h   = (int) ulHeight;
  361. gbm -> bpp = (int) cBitCount;
  362.  
  363. bmp_priv -> windows       = TRUE;
  364. bmp_priv -> cbFix         = cbFix;
  365. bmp_priv -> ulCompression = ulCompression;
  366. bmp_priv -> cclrUsed      = cclrUsed;
  367. }
  368. /*...e*/
  369.     else
  370.         return ( GBM_ERR_BMP_CBFIX );
  371.  
  372.     return ( GBM_ERR_OK );
  373.     }
  374. /*...e*/
  375. /*...sbmp_rpal:0:*/
  376. GBM_ERR bmp_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
  377.     {
  378.     BMP_PRIV *bmp_priv = (BMP_PRIV *) gbm -> priv;
  379.  
  380.     if ( gbm -> bpp != 24 )
  381.         {
  382.         int i;
  383.         byte b [4];
  384.  
  385.         if ( bmp_priv -> windows )
  386. /*...sOS\47\2 2\46\0 and Windows 3\46\0:24:*/
  387. {
  388. lseek(fd, bmp_priv -> base + 14L + bmp_priv -> cbFix, SEEK_SET);
  389. for ( i = 0; i < (int) bmp_priv -> cclrUsed; i++ )
  390.     {
  391.     read(fd, b, 4);
  392.     gbmrgb [i].b = b [0];
  393.     gbmrgb [i].g = b [1];
  394.     gbmrgb [i].r = b [2];
  395.     }
  396. }
  397. /*...e*/
  398.         else
  399. /*...sOS\47\2 1\46\1\44\ 1\46\2:24:*/
  400. {
  401. lseek(fd, bmp_priv -> base + 26L, SEEK_SET);
  402. for ( i = 0; i < (1 << gbm -> bpp); i++ )
  403.     {
  404.     read(fd, b, 3);
  405.     gbmrgb [i].b = b [0];
  406.     gbmrgb [i].g = b [1];
  407.     gbmrgb [i].r = b [2];
  408.     }
  409. }
  410. /*...e*/
  411.         }
  412.  
  413.     if ( gbm -> bpp == 1 && !bmp_priv -> inv )
  414.         swap_pal(gbmrgb);
  415.  
  416.     return ( GBM_ERR_OK );
  417.     }
  418. /*...e*/
  419. /*...sbmp_rdata:0:*/
  420. GBM_ERR bmp_rdata(int fd, GBM *gbm, byte *data)
  421.     {
  422.     BMP_PRIV *bmp_priv = (BMP_PRIV *) gbm -> priv;
  423.     int    cLinesWorth = ((gbm -> bpp * gbm -> w + 31) / 32) * 4;
  424.  
  425.     if ( bmp_priv -> windows )
  426. /*...sOS\47\2 2\46\0 and Windows 3\46\0:16:*/
  427. {
  428. lseek(fd, bmp_priv -> offBits, SEEK_SET);
  429.  
  430. switch ( (int) bmp_priv -> ulCompression )
  431.     {
  432. /*...sBCA_UNCOMP:24:*/
  433. case BCA_UNCOMP:
  434.     read(fd, data, gbm -> h * cLinesWorth);
  435.     break;
  436. /*...e*/
  437. /*...sBCA_RLE8:24:*/
  438. case BCA_RLE8:
  439.     {
  440.     AHEAD    *ahead;
  441.     int    stride = ((gbm -> w + 3) & ~3);
  442.     int    x = 0, y = 0;
  443.     BOOLEAN    eof8 = FALSE;
  444.  
  445.     if ( (ahead = create_ahead(fd)) == NULL )
  446.         return ( GBM_ERR_MEM );
  447.  
  448.     while ( !eof8 )
  449.         {
  450.         byte    c = next(ahead);
  451.         byte    d = next(ahead);
  452.  
  453.         if ( c )
  454.             {
  455.             memset(data, d, c);
  456.             x += c;
  457.             data += c;
  458.             }
  459.         else
  460.             switch ( d )
  461.                 {
  462. /*...sMSWCC_EOL:56:*/
  463. case MSWCC_EOL:
  464.     {
  465.     int    to_eol = stride - x;
  466.  
  467.     memset(data, 0, to_eol);
  468.     x = 0; y++;
  469.     data += to_eol;
  470.     }
  471.     break;
  472. /*...e*/
  473. /*...sMSWCC_EOB:56:*/
  474. case MSWCC_EOB:
  475.     if ( y < gbm -> h )
  476.         {
  477.         int    to_eol = stride - x;
  478.  
  479.         memset(data, 0, to_eol);
  480.         x = 0; y++;
  481.         data += to_eol;
  482.         while ( y < gbm -> h )
  483.             {
  484.             memset(data, 0, stride);
  485.             data += stride;
  486.             y++;
  487.             }
  488.         }
  489.     eof8 = TRUE;
  490.     break;
  491. /*...e*/
  492. /*...sMSWCC_DELTA:56:*/
  493. case MSWCC_DELTA:
  494.     {
  495.     byte    dx = next(ahead);
  496.     byte    dy = next(ahead);
  497.     int    fill = dx + dy * stride;
  498.  
  499.     x += dx; y += dy;
  500.  
  501.     memset(data, 0, fill);
  502.     data += fill;
  503.     }
  504.     break;
  505. /*...e*/
  506. /*...sdefault:56:*/
  507. default:
  508.     {
  509.     int    n = (int) d;
  510.  
  511.     while ( n-- > 0 )
  512.         *data++ = next(ahead);
  513.     x += d;
  514.     if ( d & 1 )
  515.         next(ahead); /* Align */
  516.     }
  517.     break;
  518. /*...e*/
  519.                 }
  520.         }
  521.  
  522.     destroy_ahead(ahead);
  523.     }
  524.     break;
  525. /*...e*/
  526. /*...sBCA_RLE4:24:*/
  527. case BCA_RLE4:
  528.     {
  529.     AHEAD    *ahead;
  530.     int    x = 0, y = 0;
  531.     BOOLEAN    eof4 = FALSE;
  532.     int    inx = 0;
  533.  
  534.     if ( (ahead = create_ahead(fd)) == NULL )
  535.         return ( GBM_ERR_MEM );
  536.  
  537.     memset(data, 0, gbm -> h * cLinesWorth);
  538.  
  539.     while ( !eof4 )
  540.         {
  541.         byte    c = next(ahead);
  542.         byte    d = next(ahead);
  543.  
  544.         if ( c )
  545.             {
  546.             byte    h, l;
  547.             int    i;
  548.  
  549.             if ( x & 1 )
  550.                 {
  551.                 h = (byte) (d >> 4); l = (byte) (d << 4);
  552.                 }
  553.             else
  554.                 {
  555.                 h = (byte) (d & 0xf0); l = (byte) (d & 0x0f);
  556.                 }
  557.             for ( i = 0; i < (int) c; i++, x++ )
  558.                 if ( x & 1 )
  559.                     data [inx++] |= l;
  560.                 else
  561.                     data [inx]   |= h;                    
  562.             }
  563.         else
  564.             switch ( d )
  565.                 {
  566. /*...sMSWCC_EOL:56:*/
  567. case MSWCC_EOL:
  568.     for ( ; x < gbm -> w; x++ )
  569.         if ( x & 1 )
  570.             inx++;
  571.     x = 0; y++;
  572.     inx = ((inx + 3) & ~3); /* Align output */
  573.     break;
  574. /*...e*/
  575. /*...sMSWCC_EOB:56:*/
  576. case MSWCC_EOB:
  577.     eof4 = TRUE;
  578.     break;
  579. /*...e*/
  580. /*...sMSWCC_DELTA:56:*/
  581. case MSWCC_DELTA:
  582.     {
  583.     byte    dx = next(ahead);
  584.     byte    dy = next(ahead);
  585.  
  586.     y   += dy;
  587.     inx += dy * cLinesWorth;
  588.  
  589.     if ( dx > 0 )
  590.         {
  591.         if ( x & 1 )
  592.             {
  593.             inx++;
  594.             x++;
  595.             dx--;
  596.             }
  597.  
  598.         inx += (dx / 2);
  599.         x += dx;
  600.         }
  601.         
  602.     }
  603.     break;
  604. /*...e*/
  605. /*...sdefault:56:*/
  606. default:
  607.     {
  608.     int    i, nr = 0;
  609.  
  610.     if ( x & 1 )
  611.         {
  612.         for ( i = 0; i < (int) d; i += 2 )
  613.             {
  614.             byte    b = next(ahead);
  615.  
  616.             data [inx++] |= (b >> 4);
  617.             data [inx  ] |= (b << 4);
  618.             nr++;
  619.             }
  620.         if ( i < (int) d )
  621.             {
  622.             data [inx++] |= (next(ahead) >> 4);
  623.             nr++;
  624.             }
  625.         }
  626.  
  627.     else
  628.         {
  629.         for ( i = 0; i < (int) d; i += 2 )
  630.             {
  631.             data [inx++] = next(ahead);
  632.             nr++;
  633.             }
  634.         if ( i < (int) d )
  635.             {
  636.             data [inx] = next(ahead);
  637.             nr++;
  638.             }
  639.         }
  640.     x += d;
  641.  
  642.     if ( nr & 1 )
  643.         next(ahead); /* Align input stream to next word */
  644.     }
  645.     break;
  646. /*...e*/
  647.                 }
  648.         }
  649.  
  650.     destroy_ahead(ahead);
  651.     }
  652.     break;
  653. /*...e*/
  654. /*...sdefault:24:*/
  655. default:
  656.     return ( GBM_ERR_BMP_COMP );
  657. /*...e*/
  658.     }
  659. }
  660. /*...e*/
  661.     else
  662. /*...sOS\47\2 1\46\1\44\ 1\46\2:16:*/
  663. {
  664. lseek(fd, bmp_priv -> offBits, SEEK_SET);
  665. read(fd, data, cLinesWorth * gbm -> h);
  666. }
  667. /*...e*/
  668.  
  669.     if ( bmp_priv -> invb )
  670.         invert(data, cLinesWorth * gbm -> h);
  671.  
  672.     return ( GBM_ERR_OK );
  673.     }
  674. /*...e*/
  675. /*...sbmp_w:0:*/
  676. /*...swrite_inv:0:*/
  677. static unsigned write_inv(int fd, char *buffer, unsigned count)
  678.     {
  679.     char small_buf [1024];
  680.     unsigned so_far = 0, this_go, written;
  681.  
  682.     while ( so_far < count )
  683.         {
  684.         this_go = min(count - so_far, 1024);
  685.         memcpy(small_buf, buffer + so_far, this_go);
  686.         invert(small_buf, this_go);
  687.         if ( (written = write(fd, small_buf, this_go)) != this_go )
  688.             return ( so_far + written );
  689.         so_far += written;
  690.         }
  691.  
  692.     return ( so_far );
  693.     }
  694. /*...e*/
  695.  
  696. GBM_ERR bmp_w(char *fn, int fd, GBM *gbm, GBMRGB *gbmrgb, byte *data, char *opt)
  697.     {
  698.     BOOLEAN    pm11 = ( find_word(opt, "1.1" ) != NULL );
  699.     BOOLEAN    win  = ( find_word(opt, "win" ) != NULL ||
  700.                      find_word(opt, "2.0" ) != NULL );
  701.     BOOLEAN inv  = ( find_word(opt, "inv" ) != NULL );
  702.     BOOLEAN invb = ( find_word(opt, "invb") != NULL );
  703.     int cRGB;
  704.     GBMRGB gbmrgb_1bpp [2];
  705.  
  706.     if ( pm11 && win )
  707.         return ( GBM_ERR_BAD_OPTION );
  708.  
  709.     fn=fn; /* Suppress 'unref arg' compiler warning */
  710.  
  711.     cRGB = ( (1 << gbm -> bpp) & 0x1ff );
  712.         /* 1 -> 2, 4 -> 16, 8 -> 256, 24 -> 0 */
  713.  
  714.     if ( cRGB == 2 )
  715. /*...shandle messy 1bpp case:16:*/
  716. {
  717. /*
  718. The palette entries inside a 1bpp PM bitmap are not honored, or handled
  719. correctly by most programs. Current thinking is that they have no actual
  720. meaning. Under OS/2 PM, bitmap 1's re fg and 0's are bg, and it is the job of
  721. the displayer to pick fg and bg. We will pick fg=black, bg=white in the bitmap
  722. file we save. If we do not write black and white, we find that most programs
  723. will incorrectly honor these entries giving unpredicatable (and often black on
  724. a black background!) results.
  725. */
  726.  
  727. gbmrgb_1bpp [0].r = gbmrgb_1bpp [0].g = gbmrgb_1bpp [0].b = 0xff;
  728. gbmrgb_1bpp [1].r = gbmrgb_1bpp [1].g = gbmrgb_1bpp [1].b = 0x00;
  729.  
  730. /*
  731. We observe these values must be the wrong way around to keep most PM
  732. programs happy, such as WorkPlace Shell WPFolder backgrounds.
  733. */
  734.  
  735. if ( !inv )
  736.     swap_pal(gbmrgb_1bpp);
  737.  
  738. gbmrgb = gbmrgb_1bpp;
  739. }
  740. /*...e*/
  741.  
  742.     if ( pm11 )
  743. /*...sOS\47\2 1\46\1:16:*/
  744. {
  745. word usType, xHotspot, yHotspot, cx, cy, cPlanes, cBitCount;
  746. dword cbSize, offBits, cbFix;
  747. int cLinesWorth, i;
  748.  
  749. usType      = BFT_BMAP;
  750. xHotspot    = 0;
  751. yHotspot    = 0;
  752. cbFix       = 12L;
  753. cx          = gbm -> w;
  754. cy          = gbm -> h;
  755. cPlanes     = 1;
  756. cBitCount   = gbm -> bpp;
  757. cLinesWorth = (((cBitCount * cx + 31) / 32) * cPlanes) * 4;
  758. offBits     = 26L + cRGB * 3L;
  759. cbSize      = offBits + (dword) cy * (dword) cLinesWorth;
  760.  
  761. write_word(fd, usType);
  762. write_dword(fd, cbSize);
  763. write_word(fd, xHotspot);
  764. write_word(fd, yHotspot);
  765. write_dword(fd, offBits);
  766. write_dword(fd, cbFix);
  767. write_word(fd, cx);
  768. write_word(fd, cy);
  769. write_word(fd, cPlanes);
  770. write_word(fd, cBitCount);
  771.  
  772. for ( i = 0; i < cRGB; i++ )
  773.     {
  774.     byte b [3];
  775.  
  776.     b [0] = gbmrgb [i].b;
  777.     b [1] = gbmrgb [i].g;
  778.     b [2] = gbmrgb [i].r;
  779.     write(fd, b, 3);
  780.     }
  781.  
  782. if ( invb )
  783.     write_inv(fd, data, gbm -> h * cLinesWorth);
  784. else
  785.     write(fd, data, gbm -> h * cLinesWorth);
  786. }
  787. /*...e*/
  788.     else
  789. /*...sOS\47\2 2\46\0 and Windows 3\46\0:16:*/
  790. {
  791. word usType, xHotspot, yHotspot, cPlanes, cBitCount;
  792. dword cx, cy, cbSize, offBits, cbFix, ulCompression, cbImage;
  793. dword cxResolution, cyResolution, cclrUsed, cclrImportant;
  794. int cLinesWorth, i;
  795.  
  796. usType      = BFT_BMAP;
  797. xHotspot    = 0;
  798. yHotspot    = 0;
  799. cbFix       = 40L;
  800. cx          = gbm -> w;
  801. cy          = gbm -> h;
  802. cPlanes     = 1;
  803. cBitCount   = gbm -> bpp;
  804. cLinesWorth = (((cBitCount * (int) cx + 31) / 32) * cPlanes) * 4;
  805. offBits     = 54L + cRGB * 4L;
  806. cbSize      = offBits + (dword) cy * (dword) cLinesWorth;
  807.  
  808. ulCompression = BCA_UNCOMP;
  809. cbImage       = cLinesWorth * gbm -> h;
  810. cxResolution  = 0;
  811. cyResolution  = 0;
  812. cclrUsed      = 0;
  813. cclrImportant = 0;
  814.  
  815. write_word(fd, usType);
  816. write_dword(fd, cbSize);
  817. write_word(fd, xHotspot);
  818. write_word(fd, yHotspot);
  819. write_dword(fd, offBits);
  820.  
  821. write_dword(fd, cbFix);
  822. write_dword(fd, cx);
  823. write_dword(fd, cy);
  824. write_word(fd, cPlanes);
  825. write_word(fd, cBitCount);
  826. write_dword(fd, ulCompression);
  827. write_dword(fd, cbImage);
  828. write_dword(fd, cxResolution);
  829. write_dword(fd, cyResolution);
  830. write_dword(fd, cclrUsed);
  831. write_dword(fd, cclrImportant);
  832.  
  833. for ( i = 0; i < cRGB; i++ )
  834.     {
  835.     byte b [4];
  836.  
  837.     b [0] = gbmrgb [i].b;
  838.     b [1] = gbmrgb [i].g;
  839.     b [2] = gbmrgb [i].r;
  840.     b [3] = 0;
  841.     write(fd, b, 4);
  842.     }
  843.  
  844. if ( invb )
  845.     write_inv(fd, data, gbm -> h * cLinesWorth);
  846. else
  847.     write(fd, data, gbm -> h * cLinesWorth);
  848. }
  849. /*...e*/
  850.  
  851.     return ( GBM_ERR_OK );
  852.     }
  853. /*...e*/
  854. /*...sbmp_err:0:*/
  855. char *bmp_err(GBM_ERR rc)
  856.     {
  857.     switch ( (int) rc )
  858.         {
  859.         case GBM_ERR_BMP_PLANES:
  860.             return ( "number of bitmap planes is not 1" );
  861.         case GBM_ERR_BMP_BITCOUNT:
  862.             return ( "bit count not 1, 4, 8 or 24" );
  863.         case GBM_ERR_BMP_CBFIX:
  864.             return ( "cbFix bad" );
  865.         case GBM_ERR_BMP_COMP:
  866.             return ( "compression type not uncompressed, RLE4 or RLE8" );
  867.         case GBM_ERR_BMP_OFFSET:
  868.             return ( "less bitmaps in file than index requested" );
  869.         }
  870.     return ( NULL );
  871.     }
  872. /*...e*/
  873.