childs -> children.
[AROS.git] / workbench / libs / icon / diskobj35io.c
blob6d6d5528a9dbda03580891d5f252493d45f7138f
1 /*
2 Copyright © 1995-2003, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /****************************************************************************************/
8 #include <aros/debug.h>
10 #include <datatypes/pictureclass.h>
12 #include <proto/dos.h>
13 #include <proto/alib.h>
15 #include <zlib.h>
17 #include <aros/bigendianio.h>
18 #include <aros/asmcall.h>
20 #include "icon_intern.h"
22 /****************************************************************************************/
24 #define ID_ICON MAKE_ID('I','C','O','N')
25 #define ID_FACE MAKE_ID('F','A','C','E')
26 #define ID_IMAG MAKE_ID('I','M','A','G')
27 #define ID_png MAKE_ID('p','n','g',' ')
28 #define ID_ARGB MAKE_ID('A','R','G','B')
30 /****************************************************************************************/
32 struct FileFaceChunk
34 UBYTE Width;
35 UBYTE Height;
36 UBYTE Flags;
37 UBYTE Aspect;
38 UBYTE MaxPaletteBytes[2];
41 struct FileImageChunk
43 UBYTE TransparentColor;
44 UBYTE NumColors;
45 UBYTE Flags;
46 UBYTE ImageFormat;
47 UBYTE PaletteFormat;
48 UBYTE Depth;
49 UBYTE NumImageBytes[2];
50 UBYTE NumPaletteBytes[2];
53 /****************************************************************************************/
55 static LONG MyDOSStreamHandler(struct Hook *hook, struct IFFHandle * iff, struct IFFStreamCmd * cmd)
57 LONG error = 0;
59 struct IconBase *IconBase = hook->h_Data;
61 switch(cmd->sc_Command)
63 case IFFCMD_INIT:
64 case IFFCMD_CLEANUP:
65 error = 0;
66 break;
68 case IFFCMD_READ:
69 error = (FRead((BPTR)iff->iff_Stream, cmd->sc_Buf, 1, cmd->sc_NBytes)) != cmd->sc_NBytes;
70 break;
72 case IFFCMD_WRITE:
73 error = (FWrite((BPTR)iff->iff_Stream, cmd->sc_Buf, 1, cmd->sc_NBytes)) != cmd->sc_NBytes;
74 break;
76 case IFFCMD_SEEK:
77 Flush((BPTR)iff->iff_Stream);
78 error = (Seek((BPTR)iff->iff_Stream, cmd->sc_NBytes, OFFSET_CURRENT)) == -1;
79 break;
82 return error;
85 static LONG MyMemStreamHandler(struct Hook *hook, struct IFFHandle * iff, struct IFFStreamCmd * cmd)
87 LONG error = 0;
88 APTR *buffp = (APTR *)iff->iff_Stream;
89 APTR buff = *buffp;
91 switch(cmd->sc_Command)
93 case IFFCMD_INIT:
94 case IFFCMD_CLEANUP:
95 error = 0;
96 break;
98 case IFFCMD_READ:
99 error = 0;
100 CopyMem(buff, cmd->sc_Buf, cmd->sc_NBytes);
101 (*buffp) += cmd->sc_NBytes;
102 break;
104 case IFFCMD_WRITE:
105 error = 0;
106 CopyMem(cmd->sc_Buf, buff, cmd->sc_NBytes);
107 (*buffp) += cmd->sc_NBytes;
108 break;
110 case IFFCMD_SEEK:
111 (*buffp) += cmd->sc_NBytes;
112 error = 0;
113 break;
116 return error;
119 /****************************************************************************************/
121 /* Decode35() based on ModifyIcon by Dirk Stöcker */
123 /****************************************************************************************/
125 static char *Decode35(UBYTE *buffer, UBYTE *outbuffer, LONG numbytes, LONG bits, LONG entries)
127 int cop = 0, loop = 0, numbits = 0, mask, curentry = 0;
128 ULONG bitbuf = 0;
129 UBYTE byte;
131 mask = (1<<bits)-1;
133 while((numbytes || (cop && numbits >= bits)) && (curentry < entries))
135 if(!cop)
137 if(numbits < 8)
139 bitbuf = (bitbuf<<8)|*(buffer++); --numbytes;
140 numbits += 8;
143 byte = (bitbuf>>(numbits-8))&0xFF;
144 numbits -= 8;
146 if(byte <= 127) cop = byte+1;
147 else if(byte > 128) loop = 256-byte+1;
148 else continue;
151 if(cop) ++loop;
153 if(numbits < bits)
155 bitbuf = (bitbuf<<8)|*(buffer++); --numbytes;
156 numbits += 8;
159 byte = (bitbuf>>(numbits-bits))&mask;
161 while(loop && (curentry < entries))
163 *outbuffer++ = byte;
164 ++curentry;
165 --loop;
168 if(cop) --cop;
170 numbits -= bits;
173 return curentry != entries ? "error decoding new icon data" : 0;
176 /****************************************************************************************/
178 VOID MakeMask35(UBYTE *imgdata, UBYTE *imgmask, UBYTE transpcolor, LONG imagew, LONG imageh)
180 UBYTE *src, *dst;
181 WORD x, y, bpr, mask;
183 memset(imgmask, 0xFF, RASSIZE(imagew, imageh));
185 bpr = ((imagew + 15) & ~15) / 8;
186 src = imgdata;
187 dst = imgmask;
189 for(y = 0; y < imageh; y++)
191 UBYTE *dstx = dst;
193 mask = 0x80;
195 for(x = 0; x < imagew; x++)
197 if (*(src++) == transpcolor)
199 *dstx &= ~mask;
202 mask >>= 1;
203 if (!mask)
205 mask = 0x80;
206 dstx++;
209 dst += bpr;
215 /****************************************************************************************/
216 void *malloc(size_t size)
218 return AllocVec(size, MEMF_PUBLIC);
221 void free(void *ptr)
223 FreeVec(ptr);
226 STATIC BOOL ReadARGB35(struct DiskObject *icon, struct IFFHandle *iff, struct FileFaceChunk *fc,
227 LONG chunksize, UBYTE **argbptr,
228 struct IconBase *IconBase)
230 UBYTE *src, *mem, *argb = NULL;
231 LONG imagew, imageh;
232 ULONG zsize;
233 uLongf size;
234 int err;
236 imagew = fc->Width + 1;
237 imageh = fc->Height + 1;
238 size = imagew * imageh * 4;
240 D(bug("[%s] ARGB size is %dx%d, %d => %d bytes\n", __func__, imagew, imageh, chunksize, size));
242 src = mem = AllocMemIcon(icon, chunksize, MEMF_PUBLIC);
243 if (!src) return FALSE;
245 if (ReadChunkBytes(iff, src, chunksize) != chunksize)
247 goto fail;
250 argb = AllocMemIcon(icon, size, MEMF_PUBLIC);
251 if (!argb) goto fail;
253 zsize = AROS_BE2WORD(*((UWORD *)(src + 6))) + 1;
254 err = uncompress(argb, &size, src + 10, zsize);
255 if (err != Z_OK) {
256 D(bug("%s: Can't uncompress %d ARGB bytes: %s\n", __func__, zsize, zError(err)));
257 goto fail;
260 *argbptr = argb;
262 return TRUE;
264 fail:
265 return FALSE;
268 /****************************************************************************************/
270 STATIC BOOL ReadImage35(struct DiskObject *icon, struct IFFHandle *iff, struct FileFaceChunk *fc,
271 struct FileImageChunk *ic, UBYTE **imgdataptr,
272 struct ColorRegister **imgpalptr, struct IconBase *IconBase)
274 UBYTE *src, *mem, *imgdata = NULL;
275 struct ColorRegister *imgpal = NULL;
276 LONG size, imgsize, palsize, imagew, imageh, numcols;
278 imagew = fc->Width + 1;
279 imageh = fc->Height + 1;
280 numcols = ic->NumColors + 1;
282 imgsize = ic->NumImageBytes[0] * 256 + ic->NumImageBytes[1] + 1;
283 if (ic->Flags & IMAGE35F_HASPALETTE)
285 palsize = ic->NumPaletteBytes[0] * 256 + ic->NumPaletteBytes[1] + 1;
287 else
289 palsize = 0;
292 D(bug("[%s] Image size is %dx%d, %d bytes\n", __func__, imagew, imageh, imgsize));
293 D(bug("[%s] Palette size is %d colors, %d bytes\n", __func__, numcols, palsize));
295 size = imgsize + palsize;
297 src = mem = AllocMemIcon(icon, size, MEMF_PUBLIC);
298 if (!src) return FALSE;
300 if (ReadChunkBytes(iff, src, size) != size)
302 return FALSE;
305 if (ic->Flags & IMAGE35F_HASPALETTE)
307 if (numcols < 1 || numcols > 256)
308 return FALSE;
310 size = numcols * sizeof(struct ColorRegister);
311 imgpal = AllocMemIcon(icon, size, MEMF_PUBLIC);
312 if (!imgpal) goto fail;
315 size = imagew * imageh;
316 imgdata = AllocMemIcon(icon, size, MEMF_PUBLIC);
317 if (!imgdata) goto fail;
319 if (ic->ImageFormat == 0)
321 memcpy(imgdata, src, imagew * imageh);
323 else
325 Decode35(src, imgdata, imgsize, ic->Depth, imagew * imageh);
327 src += imgsize;
329 if (ic->Flags & IMAGE35F_HASPALETTE)
331 struct ColorRegister *dst;
333 dst = imgpal;
335 D(bug("[%s] PaletteFormat %d, src %p\n", __func__, ic->PaletteFormat, src));
336 if (ic->PaletteFormat == 0)
338 ULONG i, r, g, b;
340 for(i = 0; i < numcols; i++)
342 r = *src++;
343 g = *src++;
344 b = *src++;
346 dst->red = r;
347 dst->green = g;
348 dst->blue = b;
349 dst++;
352 else
354 CONST_STRPTR err;
356 err = Decode35(src, (UBYTE *)imgpal, palsize, 8, 3 * numcols);
357 if (err) {
358 D(bug("[%s] Palette decode error: %s\n", __func__, err));
359 imgpal = NULL;
363 if (imgpal && sizeof(struct ColorRegister) != 3)
365 struct ColorRegister *dst;
366 UWORD i, r, g, b;
368 D(bug("[%s] Realigning ColorRegister\n", __func__));
370 src = (APTR)imgpal + 3 * numcols;
371 dst = (struct ColorRegister *)(imgpal + sizeof(struct ColorRegister) * numcols);
373 for (i = 0; i < numcols; i++)
375 b = *--src;
376 g = *--src;
377 r = *--src;
379 dst--;
381 dst->red = r;
382 dst->green = g;
383 dst->blue = b;
388 } /* if (ic->Flags & IMAGE35F_HASPALETTE) */
390 *imgdataptr = imgdata;
391 *imgpalptr = imgpal;
393 return TRUE;
395 fail:
396 return FALSE;
399 /****************************************************************************************/
401 BOOL ReadIcon35(struct NativeIcon *icon, struct Hook *streamhook,
402 void *stream, struct IconBase *IconBase)
404 static const LONG const stopchunks[] =
406 ID_ICON, ID_FACE,
407 ID_ICON, ID_IMAG,
408 ID_ICON, ID_png,
409 ID_ICON, ID_ARGB,
412 struct IFFHandle *iff;
413 struct Hook iffhook;
414 struct FileFaceChunk fc;
415 struct FileImageChunk ic1, ic2;
416 UBYTE *argb1data = NULL, *argb2data = NULL;
417 UBYTE *img1data = NULL, *img2data = NULL;
418 struct ColorRegister *img1pal = NULL, *img2pal = NULL;
419 BOOL have_face = FALSE, have_imag1 = FALSE, have_imag2 = FALSE;
420 BOOL have_argb1 = FALSE, have_argb2 = FALSE;
421 int have_png = 0;
422 LONG here, extrasize;
423 APTR data;
425 D(bug("ReadIcon35, stream %p\n", stream));
427 here = Seek((BPTR)stream, 0, OFFSET_CURRENT);
428 D(bug("[%s] Extra data starts at %d\n", __func__, here));
429 Seek((BPTR)stream, 0, OFFSET_END);
430 extrasize = Seek((BPTR)stream, 0, OFFSET_CURRENT);
431 D(bug("[%s] Extra data ends at %d\n", __func__, extrasize));
432 extrasize -= here;
433 Seek((BPTR)stream, here, OFFSET_BEGINNING);
434 D(bug("[%s] .. %d bytes\n", __func__, extrasize));
436 /* No extra data? That's fine. */
437 if (extrasize <= 0) {
438 D(bug("[%s] No extra data\n", __func__));
439 return TRUE;
442 if (IFFParseBase == NULL)
443 return FALSE;
445 data = AllocMemIcon(&icon->ni_DiskObject, extrasize, MEMF_PUBLIC);
446 if (data == NULL)
447 return FALSE;
449 if (Read((BPTR)stream, data, extrasize) != extrasize) {
450 D(bug("[%s] Can't read extra data\n", __func__));
451 return FALSE;
454 icon->ni_Extra.Data = data;
455 icon->ni_Extra.Size = extrasize;
457 iffhook.h_Entry = (HOOKFUNC)HookEntry;
458 iffhook.h_SubEntry = (HOOKFUNC)MyMemStreamHandler;
459 iffhook.h_Data = (APTR)IconBase;
461 if ((iff = AllocIFF()))
463 D(bug("ReadIcon35. AllocIFF okay\n"));
465 iff->iff_Stream = (IPTR)&data;
467 InitIFF(iff, IFFF_RSEEK, &iffhook);
469 if (!OpenIFF(iff, IFFF_READ))
471 D(bug("ReadIcon35. OpenIFF okay\n"));
473 if (!StopChunks(iff, stopchunks, 4))
475 LONG error;
477 D(bug("ReadIcon35. StopChunks okay\n"));
479 while(!(error = ParseIFF(iff, IFFPARSE_SCAN)))
481 struct ContextNode *cn;
483 cn = CurrentChunk(iff);
485 D(bug("inside ParseIFF loop\n"));
486 if ((cn->cn_ID == ID_FACE) && (cn->cn_Size >= sizeof(struct FileFaceChunk)))
488 D(bug("ReadIcon35. Found FACE chunk\n"));
489 if (ReadChunkBytes(iff, &fc, sizeof(fc)) == sizeof(fc))
491 have_face = TRUE;
494 else if (have_face && (cn->cn_ID == ID_IMAG) && (cn->cn_Size >= sizeof(struct FileImageChunk)))
496 D(bug("ReadIcon35. Found IMAG chunk\n"));
497 if (ReadChunkBytes(iff, (have_imag1 ? &ic2 : &ic1), sizeof(ic1)) == sizeof(ic1))
499 if (have_imag1)
501 if (ReadImage35(&icon->ni_DiskObject, iff, &fc, &ic2, &img2data, &img2pal, IconBase))
503 have_imag2 = TRUE;
506 else
508 if (ReadImage35(&icon->ni_DiskObject, iff, &fc, &ic1, &img1data, &img1pal, IconBase))
510 have_imag1 = TRUE;
515 } else if (cn->cn_ID == ID_ARGB) {
516 D(bug("ReadIcon35. Found ARGB chunk\n"));
517 if (have_argb1)
519 if (ReadARGB35(&icon->ni_DiskObject, iff, &fc, cn->cn_Size, &argb2data, IconBase))
521 have_argb2 = TRUE;
524 else
526 if (ReadARGB35(&icon->ni_DiskObject, iff, &fc, cn->cn_Size, &argb1data, IconBase))
528 have_argb1 = TRUE;
531 } else if (cn->cn_ID == ID_png) {
532 if (have_png < 2) {
533 LONG here = data - icon->ni_Extra.Data;
534 D(bug("[%s] Found PNG image %d\n", __func__, have_png));
535 icon->ni_Extra.PNG[have_png].Offset = here;
536 icon->ni_Extra.PNG[have_png].Size = cn->cn_Size;
537 } else {
538 D(bug("[%s] Ignoring PNG image %d\n", __func__, have_png));
540 have_png++;
541 } else {
542 D(bug("[%s] Unknown chunk ID 0x%08x\n", __func__, cn->cn_ID));
545 } /* while(!ParseIFF(iff, IFFPARSE_SCAN)) */
547 } /* if (!StopChunks(iff, stopchunks, 4)) */
549 } /* if (!OpenIFF(iff, IFFF_READ)) */
551 FreeIFF(iff);
553 } /* if ((iff = AllocIFF())) */
555 /* Only use the Width and Height fields of a FACE section
556 * if it also contains image data.
558 if (have_face) {
559 if (have_argb1 || have_argb2 || have_imag1 || have_imag2) {
560 icon->ni_Face.Width = fc.Width + 1;
561 icon->ni_Face.Height = fc.Height + 1;
563 //icon->icon35.flags = fc.Flags;
564 icon->ni_Face.Aspect = fc.Aspect;
567 if (have_argb1)
569 icon->ni_Image[0].ARGB = (APTR)argb1data;
572 if (have_argb2)
574 icon->ni_Image[1].ARGB = (APTR)argb2data;
577 if (have_imag1)
579 icon->ni_Image[0].ImageData = img1data;
580 icon->ni_Image[0].Palette = img1pal;
581 icon->ni_Image[0].Pens = ic1.NumColors + 1;
582 icon->ni_Image[0].TransparentColor = ic1.TransparentColor;
584 if (icon->ni_Image[0].Pens < 1 || icon->ni_Image[0].Pens > 256)
585 return FALSE;
587 if (have_imag2)
589 icon->ni_Image[1].ImageData = img2data;
590 icon->ni_Image[1].TransparentColor = ic2.TransparentColor;
592 if (img2pal)
594 icon->ni_Image[1].Palette = img2pal;
595 icon->ni_Image[1].Pens = ic2.NumColors + 1;
596 if (icon->ni_Image[1].Pens < 1 || icon->ni_Image[0].Pens > 256)
597 return FALSE;
600 else
602 icon->ni_Image[1].Palette = img1pal;
603 icon->ni_Image[1].Pens = ic1.NumColors + 1;
608 return TRUE;
611 /****************************************************************************************/
613 /* Encode35() based on ModifyIcon source by Dirk Stöcker */
615 /****************************************************************************************/
617 static UBYTE *Encode35(struct DiskObject *icon, ULONG depth, UBYTE *dtype, LONG *dsize, ULONG size, CONST UBYTE *src, APTR IconBase)
619 int i, j, k;
620 ULONG bitbuf, numbits;
621 UBYTE *buf;
622 LONG ressize, numcopy, numequal;
624 buf = AllocMemIcon(icon, size * 2, MEMF_PUBLIC);
625 if (!buf) return NULL;
627 numcopy = 0;
628 numequal = 1;
629 bitbuf = 0;
630 numbits = 0;
631 ressize = 0;
632 k = 0; /* the really output pointer */
634 for(i = 1; numequal || numcopy;)
636 if(i < size && numequal && (src[i-1] == src[i]))
638 ++numequal; ++i;
640 else if(i < size && numequal*depth <= 16)
642 numcopy += numequal; numequal = 1; ++i;
644 else
646 /* care for end case, where it maybe better to join the two */
647 if(i == size && numcopy + numequal <= 128 && (numequal-1)*depth <= 8)
649 numcopy += numequal; numequal = 0;
652 if(numcopy)
654 if((j = numcopy) > 128) j = 128;
656 bitbuf = (bitbuf<<8) | (j-1);
657 numcopy -= j;
659 else
661 if((j = numequal) > 128) j = 128;
663 bitbuf = (bitbuf<<8) | (256-(j-1));
664 numequal -= j;
665 k += j-1;
666 j = 1;
669 buf[ressize++] = (bitbuf >> numbits);
671 while(j--)
673 numbits += depth;
674 bitbuf = (bitbuf<<depth) | src[k++];
676 if(numbits >= 8)
678 numbits -= 8;
679 buf[ressize++] = (bitbuf >> numbits);
683 if(i < size && !numcopy && !numequal)
685 numequal = 1; ++i;
690 if(numbits)
691 buf[ressize++] = bitbuf << (8-numbits);
693 if(ressize > size) /* no RLE */
695 ressize = size;
696 *dtype = 0;
697 for(i = 0; i < size; ++i)
698 buf[i]= src[i];
700 else
701 *dtype = 1;
703 *dsize = ressize;
705 return buf;
708 /****************************************************************************************/
710 static BOOL WriteARGB35(struct IFFHandle *iff, struct NativeIcon *icon,
711 APTR ARGB, struct IconBase *IconBase)
713 struct ARGB35_Header {
714 ULONG ztype; /* Always 1 */
715 ULONG zsize; /* Compressed size, -1 */
716 UWORD resv; /* Always 0 */
717 } ahdr;
718 Bytef *zdest;
719 uLongf zsize, size;
720 int err;
721 BOOL ok = FALSE;
723 /* Assume uncompressible.. */
724 zsize = size = icon->ni_Face.Width * icon->ni_Face.Height * 4;
726 zdest = AllocVec(zsize, MEMF_ANY);
727 if (!zdest)
728 return FALSE;
730 err = compress(zdest, &zsize, ARGB, size);
731 if (err != Z_OK) {
732 D(bug("%s: Can't compress %d ARGB bytes: %s\n", __func__, size, zError(err)));
733 goto exit;
736 ahdr.ztype = AROS_LONG2BE(1);
737 ahdr.zsize = AROS_LONG2BE(zsize - 1);
738 ahdr.resv = AROS_WORD2BE(0);
740 if (!PushChunk(iff, ID_ICON, ID_ARGB, IFFSIZE_UNKNOWN))
742 ok = TRUE;
744 if ((WriteChunkBytes(iff, &ahdr, sizeof(ahdr)) != sizeof(ahdr)) ||
745 (WriteChunkBytes(iff, zdest, zsize) != zsize))
747 ok = FALSE;
750 PopChunk(iff);
753 exit:
754 FreeVec(zdest);
755 return ok;
758 /****************************************************************************************/
760 static BOOL WriteImage35(struct IFFHandle *iff, struct NativeIcon *icon,
761 struct NativeIconImage *img, struct IconBase *IconBase)
763 struct FileImageChunk ic;
764 UBYTE *imagedata, *pal = NULL;
765 LONG imagesize, palsize = 0;
766 UBYTE imagepacked, palpacked = 0;
767 UBYTE imageflags = 0;
768 BOOL ok = FALSE;
770 if (img->Palette)
772 pal = Encode35(&icon->ni_DiskObject, 8, &palpacked, &palsize, img->Pens * 3, (APTR)img->Palette, IconBase);
773 if (!pal) return FALSE;
774 imageflags |= IMAGE35F_HASPALETTE;
777 if (img->TransparentColor >= 0)
778 imageflags |= IMAGE35F_HASTRANSPARENTCOLOR;
780 imagedata = Encode35(&icon->ni_DiskObject, 8, &imagepacked, &imagesize,
781 icon->ni_Face.Width * icon->ni_Face.Height, img->ImageData, IconBase);
783 if (!imagedata)
785 return FALSE;
788 ic.TransparentColor = (imageflags & IMAGE35F_HASTRANSPARENTCOLOR) ? 255 : img->TransparentColor;
789 ic.NumColors = img->Pens - 1;
790 ic.Flags = imageflags;
791 ic.ImageFormat = imagepacked;
792 ic.PaletteFormat = palpacked;
793 ic.Depth = 8;
794 ic.NumImageBytes[0] = (imagesize - 1) / 256;
795 ic.NumImageBytes[1] = (imagesize - 1) & 255;
796 ic.NumPaletteBytes[0] = (palsize - 1) / 256;
797 ic.NumPaletteBytes[1] = (palsize - 1) & 255;
799 if (!PushChunk(iff, ID_ICON, ID_IMAG, IFFSIZE_UNKNOWN))
801 ok = TRUE;
803 if (WriteChunkBytes(iff, &ic, sizeof(ic)) != sizeof(ic))
805 ok = FALSE;
808 if (ok)
810 if (WriteChunkBytes(iff, imagedata, imagesize) != imagesize)
812 ok = FALSE;
816 if (ok && pal)
818 if (WriteChunkBytes(iff, pal, palsize) != palsize)
820 ok = FALSE;
825 PopChunk(iff);
827 } /* if (!PushChunk(iff, ID_ICON, ID_IMAG, IFFSIZE_UNKNOWN)) */
829 return ok;
832 /****************************************************************************************/
834 BOOL WriteIcon35(struct NativeIcon *icon, struct Hook *streamhook,
835 void *stream, struct IconBase *IconBase)
837 struct IFFHandle *iff;
838 struct Hook iffhook;
839 struct FileFaceChunk fc;
840 BOOL ok = FALSE;
842 D(bug("WriteIcon35\n"));
844 if (IFFParseBase == NULL)
846 D(bug("%s: IFFParseBase is NULL\n", __func__));
847 return FALSE;
850 if (!GetNativeIcon(&icon->ni_DiskObject, IconBase))
852 D(bug("%s: No native icon data\n", __func__));
853 return TRUE;
856 /* If the extra imagery wasn't modified, just write it out. */
857 if (icon->ni_Extra.Size != 0) {
858 LONG len;
860 len = FWrite((BPTR)stream, icon->ni_Extra.Data, 1, icon->ni_Extra.Size);
861 if (len < 0 || (ULONG)len != icon->ni_Extra.Size)
862 return FALSE;
864 return TRUE;
867 D(bug("%s: Write Icon %p\n", __func__, icon));
868 D(bug("%s: n_Image[0].ImageData = %p\n", __func__, icon->ni_Image[0].ImageData));
869 D(bug("%s: n_Image[1].ImageData = %p\n", __func__, icon->ni_Image[1].ImageData));
870 D(bug("%s: n_Image[0].ARGB = %p\n", __func__, icon->ni_Image[0].ARGB));
871 D(bug("%s: n_Image[1].ARGB = %p\n", __func__, icon->ni_Image[1].ARGB));
873 if (icon->ni_Image[0].ImageData == NULL && icon->ni_Image[0].ARGB == NULL)
875 D(bug("%s: No image data to write\n", __func__));
876 return TRUE;
879 iffhook.h_Entry = (HOOKFUNC)HookEntry;
880 iffhook.h_SubEntry = (HOOKFUNC)MyDOSStreamHandler;
881 iffhook.h_Data = (APTR)IconBase;
883 if ((iff = AllocIFF()))
885 D(bug("WriteIcon35. AllocIFF okay\n"));
887 iff->iff_Stream = (IPTR)stream;
889 InitIFF(iff, IFFF_RSEEK, &iffhook);
891 if (!OpenIFF(iff, IFFF_WRITE))
893 D(bug("WriteIcon35. OpenIFF okay\n"));
895 if (!PushChunk(iff, ID_ICON, ID_FORM, IFFSIZE_UNKNOWN))
897 D(bug("WriteIcon35. PushChunk(ID_ICON, ID_FORM) okay\n"));
899 if (!PushChunk(iff, ID_ICON, ID_FACE, sizeof(struct FileFaceChunk)))
901 WORD cmapentries;
903 D(bug("WriteIcon35. PushChunk(ID_ICON, ID_FACE) okay\n"));
905 fc.Width = icon->ni_Face.Width - 1;
906 fc.Height = icon->ni_Face.Height - 1;
907 fc.Flags = (icon->ni_Frameless) ? ICON35F_FRAMELESS : 0;
908 fc.Aspect = icon->ni_Face.Aspect;
910 cmapentries = icon->ni_Image[0].Pens;
912 if (icon->ni_Image[1].ImageData &&
913 icon->ni_Image[1].Palette)
915 if (icon->ni_Image[1].Pens > cmapentries)
917 cmapentries = icon->ni_Image[1].Pens;
921 cmapentries = cmapentries * 3 - 1;
923 fc.MaxPaletteBytes[0] = cmapentries / 256;
924 fc.MaxPaletteBytes[1] = cmapentries & 255;
926 if (WriteChunkBytes(iff, &fc, sizeof(fc)) == sizeof(fc))
928 D(bug("WriteIcon35. WriteChunkBytes of FACE chunk ok.\n"));
930 PopChunk(iff);
932 if (icon->ni_Image[0].ImageData)
934 if (WriteImage35(iff, icon, &icon->ni_Image[0], IconBase))
936 D(bug("WriteIcon35. WriteImage35() of 1st image ok.\n"));
938 if (icon->ni_Image[1].ImageData)
940 if (WriteImage35(iff, icon, &icon->ni_Image[1], IconBase))
942 D(bug("WriteIcon35. WriteImage35() of 2nd image ok.\n"));
944 ok = TRUE;
947 } /* if (icon->ni_Image[1].ImageData) */
948 else
950 ok = TRUE;
953 } /* if (WriteImage35(iff, &icon, &icon->ni_Image[0], IconBase)) */
954 } /* if (icon->ni_Image[0].ImageData) */
956 if (icon->ni_Image[0].ARGB)
958 if (WriteARGB35(iff, icon, &icon->ni_Image[0].ARGB, IconBase))
960 D(bug("WriteIcon35. WriteImage35() of 1st image ok.\n"));
961 if (icon->ni_Image[1].ARGB)
963 if (WriteARGB35(iff, icon, &icon->ni_Image[1].ARGB, IconBase))
965 D(bug("WriteIcon35. WriteImage35() of 2nd image ok.\n"));
966 ok = TRUE;
968 } else {
969 ok = TRUE;
971 } /* if (WriteARGB35(iff, icon, &icon->ni_Image[0].ARGB, IconBase) */
972 } /* if (icon->ni_Image[0].ARGB) */
974 } /* if (WriteChunkBytes(iff, &fc, sizeof(fc)) == sizeof(fc)) */
975 else
977 PopChunk(iff);
980 } /* if (!PushChunk(iff, ID_ICON, ID_FACE, sizeof(struct FileFaceChunk))) */
982 if (icon->ni_Extra.PNG[0].Size &&
983 !PushChunk(iff, ID_ICON, ID_png, IFFSIZE_UNKNOWN)) {
984 WriteChunkBytes(iff, icon->ni_Extra.Data + icon->ni_Extra.PNG[0].Offset, icon->ni_Extra.PNG[0].Size);
986 PopChunk(iff);
989 if (icon->ni_Extra.PNG[1].Size &&
990 !PushChunk(iff, ID_ICON, ID_png, IFFSIZE_UNKNOWN)) {
991 WriteChunkBytes(iff, icon->ni_Extra.Data + icon->ni_Extra.PNG[1].Offset, icon->ni_Extra.PNG[1].Size);
993 PopChunk(iff);
996 PopChunk(iff);
998 } /* if (!PushChunk(iff, ID_ICON, ID_FORM, IFFSIZE_UNKNOWN)) */
1000 } /* if (!OpenIFF(iff, IFFF_READ)) */
1002 } /* if ((iff = AllocIFF())) */
1004 return ok;
1007 /****************************************************************************************/
1009 VOID FreeIcon35(struct NativeIcon *icon, struct IconBase *IconBase)
1013 /****************************************************************************************/