2 Copyright © 1995-2003, The AROS Development Team. All rights reserved.
6 /****************************************************************************************/
8 #include <datatypes/pictureclass.h>
10 #include <proto/dos.h>
11 #include <proto/alib.h>
13 #include <aros/bigendianio.h>
14 #include <aros/asmcall.h>
16 #include "icon_intern.h"
19 # include <aros/debug.h>
21 /****************************************************************************************/
23 #define ID_ICON MAKE_ID('I','C','O','N')
24 #define ID_FACE MAKE_ID('F','A','C','E')
25 #define ID_IMAG MAKE_ID('I','M','A','G')
27 /****************************************************************************************/
35 UBYTE MaxPaletteBytes
[2];
40 UBYTE TransparentColor
;
46 UBYTE NumImageBytes
[2];
47 UBYTE NumPaletteBytes
[2];
50 /****************************************************************************************/
53 LONG
MyDOSStreamHandler(struct Hook
*hook
, struct IFFHandle
* iff
, struct IFFStreamCmd
* cmd
)
57 switch(cmd
->sc_Command
)
65 error
= (FRead((BPTR
)iff
->iff_Stream
, cmd
->sc_Buf
, 1, cmd
->sc_NBytes
)) != cmd
->sc_NBytes
;
69 error
= (FWrite((BPTR
)iff
->iff_Stream
, cmd
->sc_Buf
, 1, cmd
->sc_NBytes
)) != cmd
->sc_NBytes
;
73 Flush((BPTR
)iff
->iff_Stream
);
74 error
= (Seek((BPTR
)iff
->iff_Stream
, cmd
->sc_NBytes
, OFFSET_CURRENT
)) == -1;
82 /****************************************************************************************/
84 /* Decode35() based on ModifyIcon by Dirk Stöcker */
86 /****************************************************************************************/
88 static char *Decode35(UBYTE
*buffer
, UBYTE
*outbuffer
, LONG numbytes
, LONG bits
, LONG entries
)
90 int cop
= 0, loop
= 0, numbits
= 0, mask
, curentry
= 0;
96 while((numbytes
|| (cop
&& numbits
>= bits
)) && (curentry
< entries
))
102 bitbuf
= (bitbuf
<<8)|*(buffer
++); --numbytes
;
106 byte
= (bitbuf
>>(numbits
-8))&0xFF;
109 if(byte
<= 127) cop
= byte
+1;
110 else if(byte
> 128) loop
= 256-byte
+1;
118 bitbuf
= (bitbuf
<<8)|*(buffer
++); --numbytes
;
122 byte
= (bitbuf
>>(numbits
-bits
))&mask
;
124 while(loop
&& (curentry
< entries
))
136 return curentry
!= entries
? "error decoding new icon data" : 0;
139 /****************************************************************************************/
141 VOID
MakeMask35(UBYTE
*imgdata
, UBYTE
*imgmask
, UBYTE transpcolor
, LONG imagew
, LONG imageh
)
144 WORD x
, y
, bpr
, mask
;
146 memset(imgmask
, 0xFF, RASSIZE(imagew
, imageh
));
148 bpr
= ((imagew
+ 15) & ~15) / 8;
152 for(y
= 0; y
< imageh
; y
++)
158 for(x
= 0; x
< imagew
; x
++)
160 if (*src
++ == transpcolor
)
178 /****************************************************************************************/
180 STATIC BOOL
ReadImage35(struct IFFHandle
*iff
, struct FileFaceChunk
*fc
,
181 struct FileImageChunk
*ic
, UBYTE
**imgdataptr
,
182 UBYTE
**imgpalptr
, UBYTE
**imgmaskptr
, struct IconBase
*IconBase
)
184 UBYTE
*src
, *mem
, *imgdata
, *imgpal
= NULL
, *imgmask
= NULL
;
185 LONG size
, imgsize
, palsize
, imagew
, imageh
, numcols
;
187 imagew
= fc
->Width
+ 1;
188 imageh
= fc
->Height
+ 1;
189 numcols
= ic
->NumColors
+ 1;
191 imgsize
= ic
->NumImageBytes
[0] * 256 + ic
->NumImageBytes
[1] + 1;
192 if (ic
->Flags
& IMAGE35F_HASPALETTE
)
194 palsize
= ic
->NumPaletteBytes
[0] * 256 + ic
->NumPaletteBytes
[1] + 1;
201 size
= imgsize
+ palsize
;
203 src
= mem
= AllocVec(size
, MEMF_ANY
);
204 if (!src
) return FALSE
;
206 if (ReadChunkBytes(iff
, src
, size
) != size
)
212 size
= imagew
* imageh
;
214 if (ic
->Flags
& IMAGE35F_HASPALETTE
)
216 size
+= numcols
* sizeof(struct ColorRegister
);
219 if (ic
->Flags
& IMAGE35F_HASTRANSPARENTCOLOR
)
221 size
+= RASSIZE(imagew
, imageh
);
224 imgdata
= AllocVec(size
, MEMF_ANY
);
231 if (ic
->ImageFormat
== 0)
233 memcpy(imgdata
, src
, imagew
* imageh
);
237 Decode35(src
, imgdata
, imgsize
, ic
->Depth
, imagew
* imageh
);
240 if (ic
->Flags
& IMAGE35F_HASPALETTE
)
242 struct ColorRegister
*dst
;
246 imgpal
= imgdata
+ imagew
* imageh
;
248 dst
= (struct ColorRegister
*)imgpal
;
250 if (ic
->PaletteFormat
== 0)
254 for(i
= 0; i
< numcols
; i
++)
268 Decode35(src
, imgpal
, palsize
, 8, 3 * numcols
);
270 if (sizeof(struct ColorRegister
) != 3)
272 struct ColorRegister
*dst
;
275 src
= imgpal
+ 3 * numcols
;
276 dst
= (struct ColorRegister
*)(imgpal
+ sizeof(struct ColorRegister
) * numcols
);
278 for (i
= 0; i
< numcols
; i
++)
293 } /* if (ic->Flags & IMAGE35F_HASPALETTE) */
295 if (ic
->Flags
& IMAGE35F_HASTRANSPARENTCOLOR
)
297 imgmask
= imgdata
+ imagew
* imageh
;
298 if (ic
->Flags
& IMAGE35F_HASPALETTE
)
300 imgmask
+= numcols
* sizeof(struct ColorRegister
);
303 MakeMask35(imgdata
, imgmask
,ic
->TransparentColor
, imagew
, imageh
);
306 *imgdataptr
= imgdata
;
308 *imgmaskptr
= imgmask
;
315 /****************************************************************************************/
317 BOOL
ReadIcon35(struct NativeIcon
*icon
, struct Hook
*streamhook
,
318 void *stream
, struct IconBase
*IconBase
)
320 static LONG stopchunks
[] =
326 struct IFFHandle
*iff
;
328 struct FileFaceChunk fc
;
329 struct FileImageChunk ic1
, ic2
;
330 UBYTE
*img1data
= NULL
, *img2data
= NULL
,
331 *img1pal
= NULL
, *img2pal
= NULL
,
332 *img1mask
= NULL
, *img2mask
= NULL
;
333 BOOL have_face
= FALSE
, have_imag1
= FALSE
, have_imag2
= FALSE
;
335 D(bug("ReadIcon35\n"));
337 iffhook
.h_Entry
= (HOOKFUNC
)HookEntry
;
338 iffhook
.h_SubEntry
= (HOOKFUNC
)MyDOSStreamHandler
;
340 if ((iff
= AllocIFF()))
342 D(bug("ReadIcon35. AllocIFF okay\n"));
344 iff
->iff_Stream
= (IPTR
)stream
;
346 InitIFF(iff
, IFFF_RSEEK
, &iffhook
);
348 if (!OpenIFF(iff
, IFFF_READ
))
350 D(bug("ReadIcon35. OpenIFF okay\n"));
352 if (!StopChunks(iff
, stopchunks
, 2))
356 D(bug("ReadIcon35. StopChunks okay\n"));
358 while(!(error
= ParseIFF(iff
, IFFPARSE_SCAN
)))
360 struct ContextNode
*cn
;
362 cn
= CurrentChunk(iff
);
364 D(bug("inside ParseIFF loop\n"));
365 if ((cn
->cn_ID
== ID_FACE
) && (cn
->cn_Size
>= sizeof(struct FileFaceChunk
)))
367 D(bug("ReadIcon35. Found FACE chunk\n"));
368 if (ReadChunkBytes(iff
, &fc
, sizeof(fc
)) == sizeof(fc
))
373 else if (have_face
&& (cn
->cn_ID
== ID_IMAG
) && (cn
->cn_Size
>= sizeof(struct FileImageChunk
)))
375 D(bug("ReadIcon35. Found IMAG chunk\n"));
376 if (ReadChunkBytes(iff
, (have_imag1
? &ic2
: &ic1
), sizeof(ic1
)) == sizeof(ic1
))
380 if (ReadImage35(iff
, &fc
, &ic2
, &img2data
, &img2pal
, &img2mask
, IconBase
))
387 if (ReadImage35(iff
, &fc
, &ic1
, &img1data
, &img1pal
, &img1mask
, IconBase
))
398 } /* while(!ParseIFF(iff, IFFPARSE_SCAN)) */
400 } /* if (!StopChunks(iff, stopchunks, 2)) */
402 } /* if (!OpenIFF(iff, IFFF_READ)) */
406 } /* if ((iff = AllocIFF())) */
410 icon
->icon35
.width
= fc
.Width
+ 1;
411 icon
->icon35
.height
= fc
.Height
+ 1;
412 icon
->icon35
.flags
= fc
.Flags
;
413 icon
->icon35
.aspect
= fc
.Aspect
;
415 icon
->icon35
.img1
.imagedata
= img1data
;
416 icon
->icon35
.img1
.palette
= img1pal
;
417 icon
->icon35
.img1
.mask
= img1mask
;
418 icon
->icon35
.img1
.numcolors
= ic1
.NumColors
+ 1;
419 icon
->icon35
.img1
.depth
= ic1
.Depth
;
420 icon
->icon35
.img1
.flags
= ic1
.Flags
;
421 icon
->icon35
.img1
.transparentcolor
= ic1
.TransparentColor
;
425 icon
->icon35
.img2
.imagedata
= img2data
;
426 icon
->icon35
.img2
.mask
= img2mask
;
427 icon
->icon35
.img2
.depth
= ic2
.Depth
;
428 icon
->icon35
.img2
.flags
= ic2
.Flags
;
429 icon
->icon35
.img2
.transparentcolor
= ic2
.TransparentColor
;
433 icon
->icon35
.img2
.palette
= img2pal
;
434 icon
->icon35
.img2
.numcolors
= ic2
.NumColors
+ 1;
438 icon
->icon35
.img2
.palette
= icon
->icon35
.img1
.palette
;
439 icon
->icon35
.img2
.numcolors
= icon
->icon35
.img1
.numcolors
;
447 /****************************************************************************************/
449 /* Encode35() based on ModifyIcon source by Dirk Stöcker */
451 /****************************************************************************************/
453 static UBYTE
*Encode35(ULONG depth
, UBYTE
*dtype
, LONG
*dsize
, ULONG size
, UBYTE
*src
)
456 ULONG bitbuf
, numbits
;
458 LONG ressize
, numcopy
, numequal
;
460 buf
= AllocVec(size
* 2, MEMF_ANY
);
461 if (!buf
) return NULL
;
468 k
= 0; /* the really output pointer */
470 for(i
= 1; numequal
|| numcopy
;)
472 if(i
< size
&& numequal
&& (src
[i
-1] == src
[i
]))
476 else if(i
< size
&& numequal
*depth
<= 16)
478 numcopy
+= numequal
; numequal
= 1; ++i
;
482 /* care for end case, where it maybe better to join the two */
483 if(i
== size
&& numcopy
+ numequal
<= 128 && (numequal
-1)*depth
<= 8)
485 numcopy
+= numequal
; numequal
= 0;
490 if((j
= numcopy
) > 128) j
= 128;
492 bitbuf
= (bitbuf
<<8) | (j
-1);
497 if((j
= numequal
) > 128) j
= 128;
499 bitbuf
= (bitbuf
<<8) | (256-(j
-1));
505 buf
[ressize
++] = (bitbuf
>> numbits
);
510 bitbuf
= (bitbuf
<<depth
) | src
[k
++];
515 buf
[ressize
++] = (bitbuf
>> numbits
);
519 if(i
< size
&& !numcopy
&& !numequal
)
527 buf
[ressize
++] = bitbuf
<< (8-numbits
);
529 if(ressize
> size
) /* no RLE */
533 for(i
= 0; i
< size
; ++i
)
544 /****************************************************************************************/
546 static BOOL
WriteImage35(struct IFFHandle
*iff
, struct Icon35
*icon35
,
547 struct Image35
*img
, struct IconBase
*IconBase
)
549 struct FileImageChunk ic
;
550 UBYTE
*imagedata
, *pal
= NULL
;
551 LONG imagesize
, palsize
= 0;
552 UBYTE imagepacked
, palpacked
= 0;
556 imageflags
= img
->flags
;
558 if (img
->palette
&& (img
->flags
& IMAGE35F_HASPALETTE
))
560 pal
= Encode35(8, &palpacked
, &palsize
, img
->numcolors
* 3, img
->palette
);
561 if (!pal
) return FALSE
;
565 imageflags
&= ~IMAGE35F_HASPALETTE
;
568 imagedata
= Encode35(img
->depth
, &imagepacked
, &imagesize
,
569 icon35
->width
* icon35
->height
, img
->imagedata
);
573 if (pal
) FreeVec(pal
);
577 ic
.TransparentColor
= img
->transparentcolor
;
578 ic
.NumColors
= img
->numcolors
- 1;
579 ic
.Flags
= imageflags
;
580 ic
.ImageFormat
= imagepacked
;
581 ic
.PaletteFormat
= palpacked
;
582 ic
.Depth
= img
->depth
;
583 ic
.NumImageBytes
[0] = (imagesize
- 1) / 256;
584 ic
.NumImageBytes
[1] = (imagesize
- 1) & 255;
585 ic
.NumPaletteBytes
[0] = (palsize
- 1) / 256;
586 ic
.NumPaletteBytes
[1] = (palsize
- 1) & 255;
588 if (!PushChunk(iff
, ID_ICON
, ID_IMAG
, IFFSIZE_UNKNOWN
))
592 if (WriteChunkBytes(iff
, &ic
, sizeof(ic
)) != sizeof(ic
))
599 if (WriteChunkBytes(iff
, imagedata
, imagesize
) != imagesize
)
607 if (WriteChunkBytes(iff
, pal
, palsize
) != palsize
)
616 } /* if (!PushChunk(iff, ID_ICON, ID_IMAG, IFFSIZE_UNKNOWN)) */
619 if (pal
) FreeVec(pal
);
624 /****************************************************************************************/
626 BOOL
WriteIcon35(struct NativeIcon
*icon
, struct Hook
*streamhook
,
627 void *stream
, struct IconBase
*IconBase
)
629 struct IFFHandle
*iff
;
631 struct FileFaceChunk fc
;
634 D(bug("WriteIcon35\n"));
636 if (!GetNativeIcon(&icon
->dobj
, IconBase
))
641 iffhook
.h_Entry
= (HOOKFUNC
)HookEntry
;
642 iffhook
.h_SubEntry
= (HOOKFUNC
)MyDOSStreamHandler
;
644 if ((iff
= AllocIFF()))
646 D(bug("WriteIcon35. AllocIFF okay\n"));
648 iff
->iff_Stream
= (IPTR
)stream
;
650 InitIFF(iff
, IFFF_RSEEK
, &iffhook
);
652 if (!OpenIFF(iff
, IFFF_WRITE
))
654 D(bug("WriteIcon35. OpenIFF okay\n"));
656 if (!PushChunk(iff
, ID_ICON
, ID_FORM
, IFFSIZE_UNKNOWN
))
658 D(bug("WriteIcon35. PushChunk(ID_ICON, ID_FORM) okay\n"));
660 if (!PushChunk(iff
, ID_ICON
, ID_FACE
, sizeof(struct FileFaceChunk
)))
664 D(bug("WriteIcon35. PushChunk(ID_ICON, ID_FACE) okay\n"));
666 fc
.Width
= icon
->icon35
.width
- 1;
667 fc
.Height
= icon
->icon35
.height
- 1;
668 fc
.Flags
= icon
->icon35
.flags
;
669 fc
.Aspect
= icon
->icon35
.aspect
;
671 cmapentries
= icon
->icon35
.img1
.numcolors
;
673 if (icon
->icon35
.img2
.imagedata
&&
674 icon
->icon35
.img2
.palette
&&
675 (icon
->icon35
.img2
.flags
& IMAGE35F_HASPALETTE
))
677 if (icon
->icon35
.img2
.numcolors
> cmapentries
)
679 cmapentries
= icon
->icon35
.img2
.numcolors
;
683 cmapentries
= cmapentries
* 3 - 1;
685 fc
.MaxPaletteBytes
[0] = cmapentries
/ 256;
686 fc
.MaxPaletteBytes
[1] = cmapentries
& 255;
688 if (WriteChunkBytes(iff
, &fc
, sizeof(fc
)) == sizeof(fc
))
690 D(bug("WriteIcon35. WriteChunkBytes of FACE chunk ok.\n"));
694 if (WriteImage35(iff
, &icon
->icon35
, &icon
->icon35
.img1
, IconBase
))
696 D(bug("WriteIcon35. WriteImage35() of 1st image ok.\n"));
698 if (icon
->icon35
.img2
.imagedata
)
700 if (WriteImage35(iff
, &icon
->icon35
, &icon
->icon35
.img2
, IconBase
))
702 D(bug("WriteIcon35. WriteImage35() of 2nd image ok.\n"));
707 } /* if (icon->icon35.img2.imagedata) */
713 } /* if (WriteImage35(iff, &icon->icon35, &icon->icon35.img1, IconBase)) */
715 } /* if (WriteChunkBytes(iff, &fc, sizeof(fc)) == sizeof(fc)) */
721 } /* if (!PushChunk(iff, ID_ICON, ID_FACE, sizeof(struct FileFaceChunk))) */
725 } /* if (!PushChunk(iff, ID_ICON, ID_FORM, IFFSIZE_UNKNOWN)) */
727 } /* if (!OpenIFF(iff, IFFF_READ)) */
729 } /* if ((iff = AllocIFF())) */
734 /****************************************************************************************/
736 VOID
FreeIcon35(struct NativeIcon
*icon
, struct IconBase
*IconBase
)
738 if (icon
->icon35
.img1
.imagedata
) FreeVec(icon
->icon35
.img1
.imagedata
);
739 if (icon
->icon35
.img2
.imagedata
) FreeVec(icon
->icon35
.img2
.imagedata
);
741 icon
->icon35
.img1
.imagedata
= NULL
;
742 icon
->icon35
.img2
.imagedata
= NULL
;
744 /* We don't free img.palette/img.mask because imagedata/palette/mask
745 were allocated together in one AllocVec() call */
749 /****************************************************************************************/