home *** CD-ROM | disk | FTP | other *** search
/ MACD 9 / MACD9.iso / Datatypes / BMPdt / source / dispatch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-19  |  27.3 KB  |  1,132 lines

  1. /*
  2. ** our include
  3. */
  4.  
  5. #include "classbase.h"
  6.  
  7. /*
  8. ** structure(s)
  9. */
  10.  
  11. struct ReadData {
  12.   ULONG width,
  13.         height,
  14.         depth,
  15.         padwidth,
  16.         mode,
  17.         gray,
  18.         comp,
  19.         fmt,
  20.         ham;
  21.   APTR  obj,
  22.         pool,
  23.         bmhd,
  24.         handle;
  25.   ULONG title;
  26.   union {
  27.     struct RastPort rp[2];
  28.     UBYTE  buf[64];
  29.     ULONG  p[2];
  30.   } u;
  31. };
  32.  
  33. #define r_fh  0
  34. #define r_src 1
  35. #define r_lev 0
  36. #define r_num 1
  37. #define r_col 0
  38. #define r_crg 1
  39.  
  40. struct SaveData {
  41.   ULONG width,
  42.         height,
  43.         depth,
  44.         padwidth,
  45.         numcolors,
  46.         fmt;
  47.   APTR  bm,
  48.         pool,
  49.         handle,
  50.         cmap;
  51.   BYTE  isHAM,
  52.         isEHB,
  53.         pad[2];
  54. };
  55.  
  56. struct hamData {
  57.   UBYTE *cmap;
  58.   ULONG  bits,
  59.          mask,
  60.          shift;
  61. };
  62.  
  63. #define HD ((struct hamData *)outbuf)[-1]
  64.  
  65. /*
  66. ** functions for asynchronous file I/O
  67. */
  68.  
  69. #if !defined(ALL_IN_ONE)
  70.  
  71. APTR OpenFFR(APTR,APTR,LONG,BPTR);
  72. LONG FFRGetC(APTR);
  73. LONG FFRRead(APTR,APTR,LONG);
  74. LONG FFRWrite(APTR,APTR,LONG);
  75. LONG CloseFFR(APTR);
  76.  
  77. /*
  78. ** functions for HAM encoding
  79. */
  80.  
  81. VOID CreateHAM6Line(UBYTE *,UBYTE *,UBYTE *,UBYTE *,LONG,ULONG);
  82. VOID CreateHAM8Line(UBYTE *,UBYTE *,UBYTE *,UBYTE *,LONG,ULONG);
  83.  
  84. #endif
  85.  
  86. /*
  87. ** cybergfx defines for picture.datatype V43
  88. */
  89.  
  90. #define RECTFMT_RGB  0
  91. #define RECTFMT_LUT8 3
  92.  
  93. /*
  94. ** easy access of a char-array as a "structure" (IJG sources 5.0b)
  95. */
  96.  
  97. #define UCH(x) \
  98.   ((ULONG) (x))
  99.  
  100. #define GET_2B(array,offset) \
  101.   ((ULONG) (UCH(array[offset]) | (UCH(array[offset+1])<<8)))
  102.  
  103. #define GET_4B(array,offset) \
  104.   ((ULONG) (GET_2B(array,offset) | (GET_2B(array,offset+2)<<16)))
  105.  
  106. #define PUT_1B(array,offset,value) \
  107.    array[offset] = (UBYTE)((value) & 0xff);
  108.  
  109. #define PUT_2B(array,offset,value) \
  110.   { UWORD v = value; \
  111.     PUT_1B(array,offset,v); PUT_1B(array,offset+1,v>>=8); }
  112.  
  113. #define PUT_4B(array,offset,value) \
  114.   { ULONG v = value; \
  115.     PUT_1B(array,offset+0,v>>=0); PUT_1B(array,offset+1,v>>=8); \
  116.     PUT_1B(array,offset+2,v>>=8); PUT_1B(array,offset+3,v>>=8); }
  117.  
  118. /*
  119. ** compression types for BMPs
  120. */
  121.  
  122. enum { BI_RGB=0,BI_RLE8=1,BI_RLE4=2 };
  123.  
  124. /*
  125. ** redirect library bases
  126. */
  127.  
  128. #define SysBase       cb->SysBase
  129. #define DOSBase       cb->DOSBase
  130. #define GfxBase       cb->GfxBase
  131. #define IntuitionBase cb->IntuitionBase
  132. #define DataTypesBase cb->DataTypesBase
  133. #define PictureClass  cb->PictureClass
  134.  
  135. #if defined(__GNUC__)
  136.  
  137. /*
  138. ** set dt attribute(s)
  139. */
  140.  
  141. STATIC ULONG set_dt_attrs(struct ClassBase *cb,Object *obj,Tag tag,...)
  142. {
  143.   return SetDTAttrsA(obj,NULL,NULL,(struct TagItem *)&tag);
  144. }
  145.  
  146. #define SetDTAttrs(a,b,c,d...) set_dt_attrs(cb,a,d)
  147.  
  148. /*
  149. ** get dt attribute(s)
  150. */
  151.  
  152. STATIC ULONG get_dt_attrs(struct ClassBase *cb,Object *obj,Tag tag,...)
  153. {
  154.   return GetDTAttrsA(obj,(struct TagItem *)&tag);
  155. }
  156.  
  157. #define GetDTAttrs(a...) get_dt_attrs(cb,a)
  158.  
  159. #endif /* __GNUC__ */
  160.  
  161. /*
  162. ** get and parse user settings then start decoder/encoder
  163. */
  164.  
  165. #define PREFSFILE (STRPTR)"classes/datatypes/bmp.prefs"
  166.  
  167. enum {
  168.   RD_V42MODE=0,RD_GRAY,RD_HAM,ARG_LAST
  169. };
  170.  
  171. #define TEMPLATE "V42MODE/S,GRAY/S,HAM/K/N"
  172.  
  173. STATIC LONG startup(struct ClassBase *cb,APTR data,LONG (*start)(struct ClassBase *,LONG *,APTR),APTR pool)
  174. { LONG prefs[ARG_LAST],result,len;
  175.   struct RDArgs *rdarg;
  176.   UBYTE p[4],*buf;
  177.  
  178.   /* clear argument vector */
  179.   { ULONG *m=(ULONG *)prefs,l=sizeof(prefs)/sizeof(prefs[0]);
  180.     do;while(*m++=0,--l); }
  181.  
  182.   /* get && parse prefs file */
  183.   if (rdarg=NULL,GetVar(PREFSFILE,&p[0],1,0) >= 0)
  184.     if ((buf=AllocPooled(pool,len=1+IoErr())) != NULL)
  185.       if ((len=GetVar(PREFSFILE,buf,len,0)) >= 0)
  186.         if (buf[len++]='\n',(rdarg=AllocDosObject(DOS_RDARGS,NULL)) != NULL) {
  187.           rdarg->RDA_Source.CS_Buffer = buf;
  188.           rdarg->RDA_Source.CS_Length = len;
  189.           rdarg->RDA_Flags = RDAF_NOPROMPT;
  190.           ReadArgs((STRPTR)TEMPLATE,&prefs[0],rdarg);
  191.         }
  192.   
  193.   /* start decoder/encoder */
  194.   result = (*start)(cb,&prefs[0],data);
  195.  
  196.   /* free args */
  197.   if (rdarg) {
  198.     FreeArgs(rdarg); FreeDosObject(DOS_RDARGS,rdarg);
  199.   }
  200.  
  201.   /* status */
  202.   return result;
  203. }
  204.  
  205. /*
  206. ** do nothing
  207. */
  208.  
  209. STATIC VOID convert_stub(VOID)
  210. {
  211.   /* no work */
  212. }
  213.  
  214. /*
  215. ** change color order (BGR -> RGB / RGB -> BGR)
  216. */
  217.  
  218. STATIC VOID convert_24bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
  219. {
  220.   do {
  221.     UBYTE c = pixelbuf[0]; pixelbuf[0] = pixelbuf[2]; pixelbuf[2] = c; pixelbuf += 3;
  222.   } while (--width);
  223. }
  224.  
  225. /*
  226. ** reduce 24bit data to 8bit grayscale
  227. */
  228.  
  229. STATIC VOID grayscale(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
  230. { ULONG r,c;
  231.  
  232.   do {
  233.     c = *pixelbuf++; c *= 5; r = *pixelbuf++; c += 16*r; r = *pixelbuf++; c += 11*r; c >>= 5;
  234.   } while (*outbuf++=c,--width);
  235. }
  236.  
  237. /*
  238. ** RGB -> HAM8 encoding
  239. */
  240.  
  241. STATIC VOID RGBtoHAM8(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
  242. {
  243.   CreateHAM8Line(pixelbuf+2,pixelbuf+1,pixelbuf+0,outbuf,3,width);
  244. }
  245.  
  246. /*
  247. ** RGB -> HAM6 encoding
  248. */
  249.  
  250. STATIC VOID RGBtoHAM6(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
  251. {
  252.   CreateHAM6Line(pixelbuf+2,pixelbuf+1,pixelbuf+0,outbuf,3,width);
  253. }
  254.  
  255. /*
  256. ** perform a simple copy (outbuf is WritePixelLine8() aware...)
  257. */
  258.  
  259. STATIC VOID convert_8bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
  260. {
  261.   do;while(*outbuf++=*pixelbuf++,--width);
  262. }
  263.  
  264. /*
  265. ** expand every 4 bits to a byte
  266. */
  267.  
  268. STATIC VOID decode_4bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
  269. { ULONG i;
  270.   UBYTE c;
  271.  
  272.   for(i=width/2; i!=0; i--) {
  273.     c = *pixelbuf++; *outbuf++ = (c >> 4); *outbuf++ = (c & 0xf);
  274.   }
  275.   if (width&1) {
  276.     c = *pixelbuf; c >>= 4; *outbuf = c;
  277.   }
  278. }
  279.  
  280. /*
  281. ** expand every bit to a byte
  282. */
  283.  
  284. STATIC VOID decode_1bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
  285. { ULONG i,j;
  286.   UBYTE c;
  287.  
  288.   for(i=width/8; i!=0; i--)
  289.     for(c=*pixelbuf++,j=8; j!=0; c<<=1,j--)
  290.       *outbuf++ = ((c & 0x80) ? 1 : 0);
  291.   if ((i=width&7))
  292.     for(c=*pixelbuf; i!=0; c<<=1,i--)
  293.       *outbuf++ = ((c & 0x80) ? 1 : 0);
  294. }
  295.  
  296. /*
  297. ** handle 8 bit compression
  298. */
  299.  
  300. STATIC LONG decompress_8bit(APTR handle,UBYTE *buffer,ULONG width,ULONG height)
  301. { LONG (*get)(),xpos,a,c,i;
  302.   UBYTE *end;
  303.  
  304.   end = buffer + width * height; xpos = 0; get = FFRGetC;
  305.  
  306.   do {
  307.  
  308.     if ((c=(*get)(handle)) < 0) return c;
  309.  
  310.     if (!c) {
  311.  
  312.       if ((c=(*get)(handle)) < 0) return c;
  313.  
  314.       if (!c) {
  315.         buffer += (width-xpos); height--; xpos = 0;
  316.       }
  317.       else if (!--c) {
  318.         break;
  319.       }
  320.       else if (!--c) {
  321.         a = (*get)(handle); xpos += a; buffer += a;
  322.         if ((c=(*get)(handle)) < 0) return c;
  323.         height -= c; buffer += width * c;
  324.       }
  325.       else {
  326.         c += 2; i = c;
  327.         do {
  328.           *buffer++ = (*get)(handle);
  329.         } while (--i);
  330.         if (c&1) (*get)(handle);
  331.         xpos += c;
  332.       }
  333.     }
  334.     else {
  335.       i = c; a = (*get)(handle);
  336.       do {
  337.         *buffer++ = a;
  338.       } while (--i);
  339.       xpos += c;
  340.     }
  341.   } while (height && buffer < end);
  342.  
  343.   return 0;
  344. }
  345.  
  346. /*
  347. ** handle 4 bit compression
  348. */
  349.  
  350. STATIC LONG decompress_4bit(APTR handle,UBYTE *buffer,ULONG width,ULONG height)
  351. { LONG (*get)(),xpos,a,b,c,i;
  352.   UBYTE *end;
  353.  
  354.   end = buffer + width * height; xpos = 0; get = FFRGetC;
  355.  
  356.   do {
  357.  
  358.     if ((c=(*get)(handle)) < 0) return c;
  359.  
  360.     if (!c) {
  361.  
  362.       if ((c=(*get)(handle)) < 0) return c;
  363.  
  364.       if (!c) {
  365.         buffer += (width-xpos); height--; xpos = 0;
  366.       }
  367.       else if (!--c) {
  368.         break;
  369.       }
  370.       else if (!--c) {
  371.         a = (*get)(handle); xpos += a; buffer += a;
  372.         if ((c=(*get)(handle)) < 0) return c;
  373.         height -= c; buffer += width * c;
  374.       }
  375.       else {
  376.         c += 2; i = 0;
  377.         do {
  378.           a = (*get)(handle); b = a & 0x0f; a >>= 4;
  379.           *buffer++ = a; *buffer++ = b;
  380.           i += 2;
  381.         } while (i < c);
  382.         if (((c&3) == 1) || ((c&3) == 2)) (*get)(handle);
  383.         xpos += c; if (i > c) --buffer;
  384.       }
  385.     }
  386.     else {
  387.       i = 0; b = (*get)(handle); a = b & 0xf; b >>= 4;
  388.       do {
  389.         *buffer++ = b; *buffer++ = a; i += 2;
  390.       } while (i < c);
  391.       xpos += c; if (i > c) --buffer;
  392.     }
  393.   } while (height && buffer < end);
  394.  
  395.   return 0;
  396. }
  397.  
  398. /*
  399. ** compressed image (4 or 8 bit)
  400. */
  401.  
  402. STATIC LONG decode_rle_v42(struct ClassBase *cb,struct ReadData *rd,APTR lbuf)
  403. { LONG (*decode)(APTR,UBYTE *,ULONG,ULONG);
  404.   UBYTE *buffer;
  405.   ULONG height;
  406.   LONG ret;
  407.  
  408.   if ((buffer=AllocPooled(rd->pool,(height=rd->height)*rd->width+260)) != NULL) {
  409.  
  410.     decode = decompress_4bit; if (rd->depth != 4) decode = decompress_8bit;
  411.  
  412.     if ((ret=(*decode)(rd->handle,buffer,rd->width,height)) == 0)
  413.       do {
  414.         convert_8bit(buffer,lbuf,rd->width);
  415.         WritePixelLine8(&rd->u.rp[0],0,--height,rd->width,lbuf,&rd->u.rp[1]);
  416.         buffer += rd->width;
  417.       } while ((ret=height));
  418.  
  419.     return ret;
  420.   }
  421.  
  422.   return ERROR_NO_FREE_STORE;
  423. }
  424.  
  425. /*
  426. ** uncompressed image (1, 4 or 8 bit)
  427. */
  428.  
  429. STATIC LONG decode_normal_v42(struct ClassBase *cb,struct ReadData *rd,APTR lbuf)
  430. { VOID (*convert)(UBYTE *,UBYTE *,ULONG);
  431.   ULONG padwidth,height;
  432.   UBYTE *buffer;
  433.   LONG ret;
  434.  
  435.   if (buffer=lbuf,padwidth=rd->padwidth,convert=grayscale,!rd->gray)
  436.     if (convert=RGBtoHAM6,rd->ham != 6)
  437.       if (convert=RGBtoHAM8,rd->ham != 8)
  438.         if (convert=(VOID (*)())convert_stub,rd->depth != 8) {
  439.           buffer += rd->width; buffer -= padwidth; buffer += 8;
  440.           if (convert=decode_4bit,rd->depth != 4)
  441.             convert = decode_1bit;
  442.         }
  443.  
  444.   height = rd->height;
  445.   do {
  446.     if (FFRRead(rd->handle,buffer,padwidth) != padwidth)
  447.       break;
  448.     (*convert)(buffer,lbuf,rd->width);
  449.     WritePixelLine8(&rd->u.rp[0],0,--height,rd->width,lbuf,&rd->u.rp[1]);
  450.   } while (height);
  451.  
  452.   if ((ret=height)) ret = -1; return ret;
  453. }
  454.  
  455. /*
  456. ** obtain best modeID
  457. */
  458.  
  459. INLINE ULONG GetBestModeID(struct ClassBase *cb,struct ReadData *rd,ULONG w,ULONG h)
  460. { UWORD id = LORES_KEY;
  461.  
  462.   if ((UWORD)w > 362)
  463.     id = HIRES;
  464.   if ((UWORD)h > 283)
  465.     id |= LACE;
  466.   if (rd->ham && ModeNotAvailable(id|=HAM))
  467.     id &= ~HIRES;
  468.   return id;
  469. }
  470.  
  471. /*
  472. ** decode picture (V42 interface)
  473. */
  474.  
  475. STATIC LONG decode_picture_v42(struct ClassBase *cb,Object *obj,struct ReadData *rd)
  476. { LONG (*decode)(struct ClassBase *,struct ReadData *,APTR);
  477.   ULONG height,size;
  478.   UBYTE *lbuf;
  479.   LONG ret = ERROR_NO_FREE_STORE;
  480.  
  481.   InitRastPort(&rd->u.rp[0]);
  482.  
  483.   if ((rd->u.rp[0].BitMap=AllocBitMap(rd->width,height=rd->height,rd->depth,BMF_CLEAR|BMF_DISPLAYABLE|BMF_MINPLANES,NULL)) != NULL) {
  484.  
  485.     InitRastPort(&rd->u.rp[1]);
  486.  
  487.     if ((rd->u.rp[1].BitMap=AllocBitMap(rd->width,1,rd->depth,BMF_CLEAR|BMF_MINPLANES,NULL)) != NULL) {
  488.  
  489.       if ((size=rd->width) < rd->padwidth)
  490.         size = rd->padwidth;
  491.  
  492.       if ((lbuf=AllocPooled(rd->pool,(size+8+15)&~15)) != NULL) {
  493.  
  494.         if (decode=decode_normal_v42,rd->comp)
  495.           decode = decode_rle_v42;
  496.  
  497.         if ((ret=(*decode)(cb,rd,lbuf)) == 0) {
  498.  
  499.           SetDTAttrs(rd->obj, NULL, NULL,
  500.                      PDTA_ModeID,      GetBestModeID(cb,rd,rd->width,height),
  501.                      PDTA_BitMap,      rd->u.rp[0].BitMap,
  502.                      DTA_NominalHoriz, rd->width,
  503.                      DTA_NominalVert,  height,
  504.                      DTA_ObjName,      rd->title,
  505.                      TAG_DONE);
  506.  
  507.           rd->u.rp[0].BitMap = NULL;
  508.         }
  509.       }
  510.       FreeBitMap(rd->u.rp[1].BitMap);
  511.     }
  512.     FreeBitMap(rd->u.rp[0].BitMap);
  513.   }
  514.  
  515.   return ret;
  516. }
  517.  
  518. /*
  519. ** compressed image (4 or 8 bit)
  520. */
  521.  
  522. STATIC LONG decode_rle_v43(struct ClassBase *cb,Object *obj,struct ReadData *rd)
  523. { LONG (*decode)(APTR,UBYTE *,ULONG,ULONG);
  524.   UBYTE *buffer;
  525.   ULONG height;
  526.   LONG ret;
  527.  
  528.   if ((buffer=AllocPooled(rd->pool,(height=rd->height)*rd->width+260)) != NULL) {
  529.  
  530.     decode = decompress_4bit; if (rd->depth != 4) decode = decompress_8bit;
  531.  
  532.     if ((ret=(*decode)(rd->handle,buffer,rd->width,height)) == 0)
  533.       do {
  534.         DoSuperMethod(PictureClass,obj,
  535.                       PDTM_WRITEPIXELARRAY,buffer,RECTFMT_LUT8,0,0,--height,rd->width,1);
  536.         buffer += rd->width;
  537.       } while ((ret=height));
  538.  
  539.     return ret;
  540.   }
  541.  
  542.   return ERROR_NO_FREE_STORE;
  543. }
  544.  
  545. /*
  546. ** uncompressed image (1, 4, 8 or 24 bit)
  547. */
  548.  
  549. STATIC LONG decode_normal_v43(struct ClassBase *cb,Object *obj,struct ReadData *rd)
  550. { VOID (*convert)(UBYTE *,UBYTE *,ULONG);
  551.   ULONG padwidth,height,size;
  552.   UBYTE *buffer,*lbuf;
  553.   LONG ret = ERROR_NO_FREE_STORE;
  554.  
  555.   if ((size=rd->width) < (padwidth=rd->padwidth))
  556.     size = padwidth;
  557.  
  558.   if ((lbuf=(buffer=AllocPooled(rd->pool,size+8))) != NULL) {
  559.  
  560.     if (convert=grayscale,!rd->gray)
  561.       if (convert=convert_24bit,rd->fmt != RECTFMT_RGB)
  562.         if (convert=(VOID (*)())convert_stub,rd->depth != 8) {
  563.           buffer += rd->width; buffer -= padwidth; buffer += 8;
  564.           if (convert=decode_4bit,rd->depth != 4)
  565.             convert = decode_1bit;
  566.         }
  567.  
  568.     height = rd->height; ret = -1;
  569.     do {
  570.       if (FFRRead(rd->handle,buffer,padwidth) != padwidth)
  571.         return ret;
  572.       (*convert)(buffer,lbuf,rd->width);
  573.       DoSuperMethod(PictureClass,rd->obj,
  574.                     PDTM_WRITEPIXELARRAY,lbuf,rd->fmt,0,0,--height,rd->width,1);
  575.     } while (height);
  576.  
  577.     ret = 0;
  578.   }
  579.  
  580.   return ret;
  581. }
  582.  
  583. /*
  584. ** decode picture (V43 interface)
  585. */
  586.  
  587. STATIC LONG decode_picture_v43(struct ClassBase *cb,Object *obj,struct ReadData *rd)
  588. { LONG (*decode)(struct ClassBase *,Object *,struct ReadData *);
  589.   LONG ret;
  590.  
  591.   rd->u.p[r_lev] = 0; rd->u.p[r_num] = 0;
  592.  
  593.   SetDTAttrs(obj, NULL, NULL,
  594.              PDTA_SourceMode,  PMODE_V43,
  595.              PDTA_ModeID,      0,
  596.              DTA_ErrorLevel,   &rd->u.p[r_lev],
  597.              DTA_ErrorNumber,  &rd->u.p[r_num],
  598.              DTA_NominalHoriz, rd->width,
  599.              DTA_NominalVert,  rd->height,
  600.              DTA_ObjName,      rd->title,
  601.              TAG_DONE);
  602.  
  603.   if (ret=rd->u.p[r_num],!rd->u.p[r_lev]) {
  604.     if (decode=decode_normal_v43,rd->comp)
  605.       decode = decode_rle_v43;
  606.     ret = (*decode)(cb,obj,rd);
  607.   }
  608.  
  609.   return ret;
  610. }
  611.  
  612. /*
  613. ** extract all required information from the bmp header
  614. */
  615.  
  616. STATIC LONG read_bmp_header(struct ClassBase *cb,LONG *prefs,APTR data)
  617. { struct ReadData *rd = (struct ReadData *)data;
  618.   ULONG cmapentrysize,*methods,*cregs,tmp,val,r,g,b,c;
  619.   struct BitMapHeader *bmhd;
  620.   UBYTE *coltab,*cmap;
  621.   LONG bfOffBits;
  622.   LONG biSize;
  623.   LONG biDepth;
  624.   LONG biPlanes;
  625.   LONG biCompression;
  626.   LONG biClrUsed;
  627.  
  628.   /* preferences */
  629.   if (rd->gray=prefs[RD_GRAY],!rd->gray && prefs[RD_HAM]) {
  630.     if (val=*(ULONG *)prefs[RD_HAM],val != 6 && val != 8) val = 0;
  631.   } else val = 0;
  632.   rd->ham = val;
  633.  
  634.   if (val=~0,!prefs[RD_V42MODE] && (methods=GetDTMethods(rd->obj)))
  635.     do;while(((val=*methods++) != ~0) && (val-=PDTM_WRITEPIXELARRAY));
  636.   rd->mode = val;
  637.  
  638.   /* lets go */
  639.   if (FFRRead(rd->handle,rd->u.buf,18) != 18)
  640.     return FALSE;
  641.  
  642.   if (((UWORD)GET_2B(rd->u.buf,0)) != 0x4D42)
  643.     return FALSE;
  644.  
  645.   bfOffBits = GET_4B(rd->u.buf,10) - ((biSize=GET_4B(rd->u.buf,14)) + 14);
  646.  
  647.   if (biSize != 12 && biSize != 40 && biSize != 64)
  648.     return FALSE;
  649.  
  650.   if (FFRRead(rd->handle,rd->u.buf+4,biSize-=4) != biSize)
  651.     return FALSE;
  652.  
  653.   if (biSize == 8) { /* OS/2 1.x */
  654.     rd->width     = GET_2B(rd->u.buf, 4);
  655.     rd->height    = GET_2B(rd->u.buf, 6);
  656.     biDepth       = GET_2B(rd->u.buf,10);
  657.     biCompression = 0;
  658.     biClrUsed     = 0;
  659.     cmapentrysize = 3;
  660.     biPlanes      = GET_2B(rd->u.buf, 8);
  661.   }
  662.   else { /* Windows 3.x or OS/2 2.x */
  663.     rd->width     = GET_4B(rd->u.buf, 4);
  664.     rd->height    = GET_4B(rd->u.buf, 8);
  665.     biDepth       = GET_2B(rd->u.buf,14);
  666.     biCompression = GET_4B(rd->u.buf,16);
  667.     biClrUsed     = GET_4B(rd->u.buf,32);
  668.     cmapentrysize = 4;
  669.     biPlanes      = GET_2B(rd->u.buf,12);
  670.   }
  671.  
  672.   if (biPlanes != 1)
  673.     return FALSE;
  674.  
  675.   if ((rd->comp=biCompression) &&
  676.       ((biDepth == 4 && biCompression != BI_RLE4) || (biDepth == 8 && biCompression != BI_RLE8)))
  677.     return FALSE;
  678.  
  679.   rd->padwidth = (((biDepth * rd->width) + 31) & ~31) / 8;
  680.  
  681.   if (val=RECTFMT_LUT8,biDepth != 1 && biDepth != 4 && biDepth != 8) {
  682.  
  683.     if (biDepth != 24)
  684.       return FALSE;
  685.  
  686.     if ((biClrUsed=rd->ham))
  687.       rd->mode=biDepth=biClrUsed,biClrUsed=1,biClrUsed<<=(biDepth-2);
  688.  
  689.     if (!biClrUsed && (rd->gray || (rd->gray=rd->mode,rd->gray)))
  690.       biDepth=8,biClrUsed=256;
  691.  
  692.     val = RECTFMT_RGB;
  693.   }
  694.  
  695.   bmhd = (struct BitMapHeader *)rd->bmhd;
  696.   bmhd->bmh_Depth = rd->depth = biDepth;
  697.   if ((bmhd->bmh_PageWidth=bmhd->bmh_Width=rd->width) == 0 ||
  698.       (bmhd->bmh_PageHeight=bmhd->bmh_Height=rd->height) == 0)
  699.     return FALSE;
  700.  
  701.   if ((rd->fmt=val) != RECTFMT_RGB) {
  702.  
  703.     if (biClrUsed > 256)
  704.       return FALSE;
  705.  
  706.     if (biClrUsed <= 0)
  707.       biClrUsed=1,biClrUsed<<=biDepth;
  708.  
  709.     if ((coltab=AllocPooled(rd->pool,val=biClrUsed*cmapentrysize)) == NULL)
  710.       return FALSE;
  711.  
  712.     if (FFRRead(rd->handle,coltab,val) != val)
  713.       return FALSE;
  714.  
  715.     bfOffBits -= val;
  716.   }
  717.  
  718.   if (biClrUsed) {
  719.  
  720.     SetDTAttrs(rd->obj, NULL, NULL, PDTA_NumColors,(ULONG)biClrUsed, TAG_DONE);
  721.     if (GetDTAttrs(rd->obj, PDTA_ColorRegisters,&rd->u.p[r_col],PDTA_CRegs,&rd->u.p[r_crg], TAG_DONE) != 2)
  722.       return FALSE;
  723.  
  724.     /*
  725.     ** do not use "struct ColorRegister" for cmap since with the amiga port
  726.     ** of gcc a sizeof() for this structure is four and not three.. oh well
  727.     */
  728.  
  729.     coltab += 2; cmap = (UBYTE *)rd->u.p[r_col]; cmapentrysize += 2; cregs = (ULONG *)rd->u.p[r_crg];
  730.     if (c=0,rd->fmt == RECTFMT_RGB) {
  731.       if (rd->ham)
  732.         do {
  733.           tmp = ((c * 255) / (biClrUsed - 1)) * 0x01010101;
  734.           *cmap++ = tmp; *cregs++ = tmp;
  735.           *cmap++ = tmp; *cregs++ = tmp;
  736.           *cmap++ = tmp; *cregs++ = tmp;
  737.         } while (++c < biClrUsed);
  738.       else
  739.         do {
  740.           *cmap++ = c; *cregs++ = c;
  741.           *cmap++ = c; *cregs++ = c; 
  742.           *cmap++ = c; *cregs++ = c;
  743.         } while (c+=0x01010101,--biClrUsed);
  744.       rd->fmt += RECTFMT_LUT8;
  745.     }
  746.     else {
  747.       if (rd->gray)
  748.         do {
  749.            c = *coltab; c *= 11; r = *--coltab; c += 16*r; r = *--coltab; c += 5*r; c >>= 5; c *= 0x01010101;
  750.            *cmap++ = c; *cregs++ = c;
  751.            *cmap++ = c; *cregs++ = c;
  752.            *cmap++ = c; *cregs++ = c;
  753.         } while (coltab+=cmapentrysize,--biClrUsed);
  754.       else
  755.         do {
  756.           *cmap++ = (r = *  coltab); *cregs++ = (r *= 0x01010101);
  757.           *cmap++ = (g = *--coltab); *cregs++ = (g *= 0x01010101);
  758.           *cmap++ = (b = *--coltab); *cregs++ = (b *= 0x01010101);
  759.         } while (coltab+=cmapentrysize,--biClrUsed);
  760.       rd->ham = rd->gray = 0;
  761.     }
  762.   }
  763.  
  764.   if ((val=bfOffBits) > 0)
  765.     do
  766.       if (FFRGetC(rd->handle) < 0) break;
  767.     while (--val);
  768.  
  769.   return (val <= 0 ? TRUE : FALSE);
  770. }
  771.  
  772. /*
  773. ** load a picture
  774. */
  775.  
  776. STATIC LONG LoadBMP(struct ClassBase *cb,Object *obj)
  777. { LONG (*decode)(struct ClassBase *,Object *,struct ReadData *);
  778.   struct ReadData *rd;
  779.   LONG error;
  780.   APTR pool;
  781.  
  782.   if (error=ERROR_NO_FREE_STORE,pool=CreatePool(MEMF_CLEAR,4*1024,4*1024)) {
  783.  
  784.     if ((rd=AllocPooled(pool,sizeof(*rd)))) {
  785.  
  786.       rd->pool = pool; rd->bmhd = NULL; rd->u.p[r_fh] = 0; rd->u.p[r_src] = DTST_FILE; rd->title = 0;
  787.  
  788.       GetDTAttrs(rd->obj=obj,
  789.                  PDTA_BitMapHeader, &rd->bmhd,
  790.                  DTA_Handle,        &rd->u.p[r_fh],
  791.                  DTA_SourceType,    &rd->u.p[r_src],
  792.                  DTA_Name,          &rd->title,
  793.                  TAG_DONE);
  794.  
  795.       if (error=0,rd->u.p[r_src] != DTST_RAM) {
  796.  
  797.         if (error=ERROR_OBJECT_WRONG_TYPE,rd->u.p[r_src] == DTST_FILE && rd->bmhd && rd->u.p[r_fh]) {
  798.  
  799.           if ((rd->handle=OpenFFR(cb,pool,FFR_MODE_READ,(BPTR)rd->u.p[r_fh]))) {
  800.  
  801.             if (startup(cb,rd,read_bmp_header,pool)) {
  802.  
  803.               if (decode=decode_picture_v42,!rd->mode)
  804.                 decode=decode_picture_v43;
  805.               error = (*decode)(cb,obj,rd);
  806.             }
  807.             (VOID)CloseFFR(rd->handle);
  808.           }
  809.           else
  810.             error = ERROR_NO_FREE_STORE;
  811.         }
  812.       }
  813.     }
  814.     DeletePool(pool);
  815.   }
  816.  
  817.   if (error) {
  818.     if (error > 0) SetIoErr(error); return FALSE;
  819.   }
  820.  
  821.   return TRUE;
  822. }
  823.  
  824. /*
  825. ** convert HAM to RGB
  826. */
  827.  
  828. STATIC VOID HAMtoRGB(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
  829. { ULONG bits,mask,shift,pen,v;
  830.   UBYTE *cmap,*p,r,g,b;
  831.  
  832.   shift = HD.shift; mask = HD.mask; bits = HD.bits; cmap = HD.cmap;
  833.  
  834.   for(r=*cmap++,g=*cmap++,b=*cmap,cmap-=2; width; width--) {
  835.     if ((v=((pen=*pixelbuf++)>>bits)&3) == 0) {
  836.       p = cmap+2*pen+pen; r = *p++; g = *p++; b = *p;
  837.     }
  838.     else {
  839.       /*pen &= mask;*/ pen <<= shift;
  840.       if (!--v)
  841.         b = pen;
  842.       else if (!--v)
  843.         r = pen;
  844.       else
  845.         g = pen;
  846.     }
  847.     *outbuf++ = b; *outbuf++ = g; *outbuf++ = r;
  848.   }
  849. }
  850.  
  851. /*
  852. ** convert 2 bytes into one
  853. */
  854.  
  855. STATIC VOID encode_4bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
  856. { ULONG i;
  857.   UBYTE c;
  858.  
  859.   for(i=width/2; i!=0; i--) {
  860.     c = *pixelbuf++ & 0xf; c <<= 4; c |= *pixelbuf++ & 0xf; *outbuf++ = c;
  861.   }
  862.   if (width&1) {
  863.     c = *pixelbuf & 0xf; c <<= 4; *outbuf = c;
  864.   }
  865. }
  866.  
  867. /*
  868. ** convert 8 bytes into one
  869. */
  870.  
  871. STATIC VOID encode_1bit(UBYTE *pixelbuf,UBYTE *outbuf,ULONG width)
  872. { ULONG c,i,j;
  873.  
  874.   for(i=width/8; i!=0; *outbuf++=c,i--)
  875.     for(c=0,j=0x80; j!=0; j>>=1)
  876.       if (*pixelbuf++) c |= j;
  877.   if ((i=width&7)) {
  878.     for(c=0,j=0x80; i!=0; j>>=1,i--)
  879.       if (*pixelbuf++) c |= j;
  880.     *outbuf = c;
  881.   }
  882. }
  883.  
  884. /*
  885. ** encode picture (V42 interface)
  886. */
  887.  
  888. STATIC LONG encode_picture_v42(struct ClassBase *cb,Object *obj,struct SaveData *sd)
  889. { VOID (*encode)(UBYTE *,UBYTE *,ULONG);
  890.   ULONG *hd,b,d,height,padwidth;
  891.   struct RastPort trp,rp;
  892.   UBYTE *buffer,*lbuf;
  893.   LONG ret = ERROR_NO_FREE_STORE;
  894.  
  895.   InitRastPort(&rp); rp.BitMap = sd->bm; InitRastPort(&trp); d = GetBitMapAttr(sd->bm,BMA_DEPTH);
  896.  
  897.   if ((trp.BitMap=AllocBitMap(sd->width,1,d,BMF_MINPLANES,sd->bm)) != NULL) {
  898.  
  899.     if ((lbuf=AllocPooled(sd->pool,((sd->width+15)&~15))) != NULL) {
  900.  
  901.       if ((hd=AllocPooled(sd->pool,sizeof(struct hamData)+(padwidth=sd->padwidth))) != NULL) {
  902.  
  903.         if (encode=HAMtoRGB,!sd->isHAM)
  904.           if (encode=convert_8bit,sd->depth != 8)
  905.             if (encode=encode_4bit,sd->depth != 4)
  906.               encode = encode_1bit;
  907.  
  908.         *hd++ = (ULONG)sd->cmap; // cmap
  909.         *hd++ = b = d - 2;       // bits
  910.         *hd++ = (1 << b) - 1;    // mask
  911.         *hd++ = 8 - b;           // shift
  912.  
  913.         buffer = (UBYTE *)hd; height = sd->height;
  914.         do {
  915.           ReadPixelLine8(&rp,0,--height,sd->width,lbuf,&trp);
  916.           (*encode)(lbuf,buffer,sd->width);
  917.           if (FFRWrite(sd->handle,buffer,padwidth) != padwidth)
  918.             break;
  919.         } while (height);
  920.  
  921.         if ((ret=height))
  922.           ret = -1;
  923.       }
  924.     }
  925.     FreeBitMap(trp.BitMap);
  926.   }
  927.  
  928.   return ret;
  929. }
  930.  
  931. /*
  932. ** encode picture (V43 interface)
  933. */
  934.  
  935. STATIC LONG encode_picture_v43(struct ClassBase *cb,Object *obj,struct SaveData *sd)
  936. { VOID (*encode)(UBYTE *,UBYTE *,ULONG);
  937.   ULONG height,padwidth;
  938.   UBYTE *buffer,*lbuf;
  939.   LONG ret;
  940.  
  941.   if ((buffer=AllocPooled(sd->pool,padwidth=sd->padwidth)) != NULL) {
  942.  
  943.     if (lbuf=buffer,encode=convert_24bit,sd->fmt != RECTFMT_RGB)
  944.       if (encode=(VOID (*)())convert_stub,sd->depth != 8) {
  945.         if (encode=encode_4bit,sd->depth != 4)
  946.           encode = encode_1bit;
  947.         if ((lbuf=AllocPooled(sd->pool,sd->width)) == NULL) return ERROR_NO_FREE_STORE;
  948.       }
  949.  
  950.     height = sd->height;
  951.     do {
  952.       DoSuperMethod(PictureClass,obj,
  953.                     PDTM_READPIXELARRAY,lbuf,sd->fmt,0,0,--height,sd->width,1);
  954.       (*encode)(lbuf,buffer,sd->width);
  955.       if (FFRWrite(sd->handle,buffer,padwidth) != padwidth)
  956.         break;
  957.     } while (height);
  958.  
  959.     if ((ret=height)) ret = -1; return ret;
  960.   }
  961.  
  962.   return ERROR_NO_FREE_STORE;
  963. }
  964.  
  965. /*
  966. ** setup and write bmp header
  967. */
  968.  
  969. STATIC LONG write_bmp_header(struct ClassBase *cb,Object *obj,struct SaveData *sd)
  970. { ULONG bfSize,bfOffBits,biDepth,cnt,nc;
  971.   UBYTE *header,*coltab,*cmap;
  972.   LONG ret;
  973.  
  974.   if (nc=0,biDepth=24,cnt=0,!sd->isHAM && sd->depth != biDepth) {
  975.     if (nc=sd->numcolors,sd->isEHB)
  976.       nc += (cnt=nc);
  977.     if (biDepth=1,nc > 2)
  978.       if (biDepth=4,nc > 16)
  979.         biDepth = 8;
  980.   }
  981.   sd->padwidth = (((sd->width * (sd->depth=biDepth)) + 31) & ~31) / 8;
  982.  
  983.   bfOffBits = 14 + 40 + 4*nc; bfSize = bfOffBits + sd->height * sd->padwidth;
  984.  
  985.   if ((header=AllocPooled(sd->pool,bfOffBits)) != NULL) {
  986.  
  987.     PUT_2B(header,  0, 0x4D42);
  988.     PUT_4B(header,  2, bfSize);
  989.   //PUT_4B(header,  6, 0);
  990.     PUT_2B(header, 10, bfOffBits);
  991.  
  992.     PUT_1B(header, 14, 40);
  993.     PUT_2B(header, 18, sd->width);
  994.     PUT_2B(header, 22, sd->height);
  995.     PUT_1B(header, 26, 1);
  996.     PUT_1B(header, 28, biDepth);
  997.  
  998.   //PUT_1B(header, 30, BI_RGB);
  999.   //PUT_4B(header, 34, 0);
  1000.   //PUT_4B(header, 38, 0);
  1001.   //PUT_4B(header, 42, 0);
  1002.     if (nc &&  (nc != (1<<biDepth)))
  1003.       PUT_2B(header, 46, nc);
  1004.   //PUT_4B(header, 50, 0);
  1005.  
  1006.     if (nc) {
  1007.  
  1008.       coltab = &header[14+40+2]; cmap = sd->cmap; if (cnt) nc = cnt;
  1009.       do {
  1010.         *coltab = *cmap++; *--coltab = *cmap++; *--coltab = *cmap++;
  1011.       } while (coltab+=4+2,--nc);
  1012.  
  1013.       if (cmap=sd->cmap,cnt)
  1014.         do {
  1015.           *coltab = *cmap++/2; *--coltab = *cmap++/2; *--coltab = *cmap++/2;
  1016.         } while (coltab+=4+2,--cnt);
  1017.  
  1018.       nc = RECTFMT_LUT8;
  1019.     }
  1020.     //else nc = RECTFMT_RGB;
  1021.     sd->fmt = nc;
  1022.  
  1023.     if ((ret=FFRWrite(sd->handle,header,bfOffBits)-bfOffBits))
  1024.       ret = -1;
  1025.   }
  1026.   else
  1027.     ret = ERROR_NO_FREE_STORE;
  1028.  
  1029.   return ret;
  1030. }
  1031.  
  1032. /*
  1033. ** save a picture
  1034. */
  1035.  
  1036. #define DTSI(o) ((struct DTSpecialInfo *)(((struct Gadget *)o)->SpecialInfo))
  1037.  
  1038. STATIC LONG SaveBMP(struct ClassBase *cb,Object *obj,struct dtWrite *dtw)
  1039. { LONG (*encode)(struct ClassBase *,Object *,struct SaveData *);
  1040.   ULONG *methods,depth,mode,id;
  1041.   struct BitMapHeader *bmhd;
  1042.   struct SaveData sd;
  1043.   LONG error;
  1044.  
  1045.   if (dtw->dtw_FileHandle) {
  1046.  
  1047.     ObtainSemaphoreShared(&(DTSI(obj)->si_Lock));
  1048.  
  1049.     if (error=ERROR_NO_FREE_STORE,(sd.pool=CreatePool(MEMF_CLEAR,4*1024,4*1024)) != NULL) {
  1050.  
  1051.       if ((sd.handle=OpenFFR(cb,sd.pool,FFR_MODE_WRITE,dtw->dtw_FileHandle)) != NULL) {
  1052.  
  1053.         SetDTAttrs(obj, NULL, NULL, PDTA_SourceMode,PMODE_V43, TAG_DONE);
  1054.  
  1055.         sd.cmap = NULL; sd.numcolors = 0; sd.bm = NULL; mode = INVALID_ID; bmhd = NULL;
  1056.  
  1057.         GetDTAttrs(obj,
  1058.                    PDTA_BitMapHeader,   &bmhd,
  1059.                    PDTA_ModeID,         &mode,
  1060.                    PDTA_BitMap,         &sd.bm,
  1061.                    PDTA_NumColors,      &sd.numcolors,
  1062.                    PDTA_ColorRegisters, &sd.cmap,
  1063.                    TAG_DONE);
  1064.  
  1065.         error = ERROR_OBJECT_WRONG_TYPE;
  1066.  
  1067.         if (bmhd && mode != INVALID_ID && sd.bm && ((depth=bmhd->bmh_Depth) > 8 || (sd.numcolors && sd.cmap))) {
  1068.  
  1069.           sd.isEHB = ((mode & EXTRAHALFBRITE_KEY) != 0); sd.isHAM = ((mode & HAM_KEY) != 0);
  1070.  
  1071.           sd.depth = depth; sd.height = bmhd->bmh_Height; sd.width = bmhd->bmh_Width;
  1072.  
  1073.           if (error=ERROR_NOT_IMPLEMENTED,bmhd->bmh_Compression == cmpNone) {
  1074.  
  1075.             if ((error=write_bmp_header(cb,obj,&sd)) == 0) {
  1076.  
  1077.               if (id=~0,depth > 8 && (methods=GetDTMethods(obj)))
  1078.                 do;while(((id=*methods++) != ~0) && (id-=PDTM_READPIXELARRAY));
  1079.  
  1080.               if (encode=encode_picture_v42,!id)
  1081.                 encode=encode_picture_v43;
  1082.               error = (*encode)(cb,obj,&sd);
  1083.             }
  1084.           }
  1085.         }
  1086.         if (!CloseFFR(sd.handle))
  1087.           error = -1;
  1088.       }
  1089.       DeletePool(sd.pool);
  1090.     }
  1091.  
  1092.     ReleaseSemaphore(&(DTSI(obj)->si_Lock));
  1093.  
  1094.     if (error) {
  1095.       if (error > 0) SetIoErr(error); return FALSE;
  1096.     }
  1097.   }
  1098.  
  1099.   return TRUE;
  1100. }
  1101.  
  1102. /*
  1103. ** class dispatcher
  1104. */
  1105.  
  1106. ASM(Object *) Dispatch(REG(a0,struct IClass *cl),REG(a2,Object *obj),REG(a1,Msg msg))
  1107. { struct ClassBase *cb = (struct ClassBase *)cl->cl_UserData;
  1108.   struct RastPort *rp;
  1109.   Object *o = obj;
  1110.  
  1111.   if ((msg->MethodID == DTM_WRITE) && (((struct dtWrite *)msg)->dtw_Mode == DTWM_RAW))
  1112.     return (Object *)SaveBMP(cb,obj,(struct dtWrite *)msg);
  1113.  
  1114.   if (msg->MethodID != OM_UPDATE || !DoMethod(obj,ICM_CHECKLOOP)) {
  1115.     if ((obj=(Object *)DoSuperMethodA(cl,obj,msg))) {
  1116.       if (msg->MethodID == OM_NEW) {
  1117.         if ((o != (Object *)cl) || !LoadBMP(cb,obj))
  1118.           { CoerceMethod(cl,obj,OM_DISPOSE); if (obj) ; obj = NULL; }
  1119.       }
  1120.       else if (msg->MethodID == OM_UPDATE || msg->MethodID == OM_SET) {
  1121.         if ((rp=ObtainGIRPort(((struct opSet *)msg)->ops_GInfo)) != NULL) {
  1122.           DoMethod(o,GM_RENDER,((struct opSet *)msg)->ops_GInfo,rp,GREDRAW_UPDATE);
  1123.           ReleaseGIRPort(rp); obj = NULL;
  1124.         }
  1125.       }
  1126.     }
  1127.   }
  1128.   else obj = NULL;
  1129.  
  1130.   return obj;
  1131. }
  1132.