icon.library: improve support for old-style AROS icons
[AROS.git] / workbench / libs / icon / diskobjPNGio.c
blob944d6732c8eda1a03bd730e7c399fc8682084f63
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /****************************************************************************************/
8 #define DTT(x)
10 #include <datatypes/datatypes.h>
11 #include <intuition/intuition.h>
13 #include <proto/dos.h>
14 #include <proto/alib.h>
15 #include <proto/png.h>
16 #include <proto/datatypes.h>
18 #include <aros/bigendianio.h>
19 #include <aros/asmcall.h>
21 #include "icon_intern.h"
23 #include <aros/debug.h>
25 #include <png.h>
27 #define ATTR_ICONX 0x80001001
28 #define ATTR_ICONY 0x80001002
29 #define ATTR_DRAWERX 0x80001003
30 #define ATTR_DRAWERY 0x80001004
31 #define ATTR_DRAWERWIDTH 0x80001005
32 #define ATTR_DRAWERHEIGHT 0x80001006
33 #define ATTR_DRAWERFLAGS 0x80001007
34 #define ATTR_TOOLWINDOW 0x80001008 //OS4: STRPTR, tool window string, length including the tag
35 //must be a multiple of 8
36 #define ATTR_STACKSIZE 0x80001009
37 #define ATTR_DEFAULTTOOL 0x8000100a
38 #define ATTR_TOOLTYPE 0x8000100b
39 #define ATTR_VIEWMODES 0x8000100c //OS4 PNG use that
40 #define ATTR_DD_CURRENTX 0x8000100d //OS4 ULONG, drawer view X offset
41 #define ATTR_DD_CURRENTY 0x8000100e //OS4 ULONG, drawer view Y offset
42 #define ATTR_TYPE 0x8000100f //OS4 icon type (WBDISK...WBKICK)
43 #define ATTR_FRAMELESS 0x80001010 //OS4 ULONG, frameless property
44 #define ATTR_DRAWERFLAGS3 0x80001011 //OS4 ULONG, drawer flags
45 #define ATTR_VIEWMODES2 0x80001012 //OS4 ULONG, drawer view modes
46 #define ATTR_DRAWERFLAGS2 0x80001107 //written from AFA to store needed dopus Magellan settings
48 #define EFFECT_NONE (0)
49 #define EFFECT_LIGHTEN (1)
50 #define EFFECT_TINT_BLUE (2)
51 #define EFFECT_XOR (3)
53 #define EFFECT EFFECT_LIGHTEN
55 /****************************************************************************************/
58 ATTR_DRAWERFLAGS: AAABC
60 C : 1-bit flag : 0 = showonlyicons 1 = showallfiles
61 B : 1-bit flag : 0 = viewastext 1 = view as icons
62 AA : 2-bit value : 0 = viewbyname, 1 = viewbydata, 2 = viewbysize, 3 = viewbytype
65 static ULONG flags_to_ddflags(ULONG flags)
67 ULONG ret = 0;
69 if (flags & 1)
71 ret = DDFLAGS_SHOWALL;
73 else
75 ret = DDFLAGS_SHOWICONS;
78 return ret;
81 static ULONG flags_to_ddviewmodes(ULONG flags)
83 ULONG ret = 0;
85 if (flags & 2)
87 ret = DDVM_BYICON;
89 else
91 ret = (flags >> 2) + DDVM_BYNAME;
94 return ret;
97 static ULONG dd_to_flags(struct DiskObject *dobj)
99 ULONG drawerflags = 0;
101 if (dobj->do_DrawerData->dd_Flags & DDFLAGS_SHOWALL)
103 drawerflags |= 1;
106 if (dobj->do_DrawerData->dd_ViewModes == DDVM_BYICON)
108 drawerflags |= 2;
110 else
112 drawerflags |= ((dobj->do_DrawerData->dd_ViewModes - 2) << 2);
115 return drawerflags;
118 /* Returns an ARGB image.
119 * Set &width == -1 and &height == -1 to get the size.
120 * Otherwise, sets the image size of width & height
122 ULONG *ReadMemPNG(struct DiskObject *icon, APTR stream, LONG *width, LONG *height, const CONST_STRPTR *chunknames, APTR *chunkpointer, struct IconBase *IconBase)
124 APTR PNGBase = OpenLibrary("SYS:Classes/datatypes/png.datatype", 41);
125 APTR handle;
126 ULONG *argb = NULL;
128 if (!PNGBase) {
129 D(bug("[%s] Can't open png.datatype\n", __func__));
130 return NULL;
133 handle = PNG_LoadImageMEM(stream, -1, chunknames, chunkpointer, TRUE);
134 if (handle) {
135 ULONG *src, *dst;
136 LONG w = 0, h = 0;
137 LONG x,y, xoff, yoff;
139 PNG_GetImageInfo(handle, &w, &h, NULL, NULL);
140 D(bug("[%s] Dest (%d x %d), Image (%d x %d)\n", __func__,
141 *width, *height, w, h));
142 if (*width == -1 && *height == -1) {
143 *width = w;
144 *height = h;
147 PNG_GetImageData(handle, (APTR *)&src, NULL);
149 argb = AllocMemIcon(icon, (*width) * (*height) * sizeof(ULONG), MEMF_PUBLIC);
150 if (argb) {
151 xoff = ((*width) - w)/2;
152 yoff = ((*height) - h)/2;
154 dst = argb;
155 for (y = 0; y < *height; y++) {
156 LONG sy = y + yoff;
158 if (sy < 0)
159 sy = 0;
161 if (sy >= h)
162 sy = h-1;
164 for (x = 0; x < *width; x++, dst++) {
165 LONG sx = x + xoff;
167 if (sx < 0)
168 sx = 0;
170 if (sx >= w)
171 sx = w-1;
173 *dst = src[sy*w+sx];
178 PNG_FreeImage(handle);
179 } else {
180 D(bug("[%s] PNG datatype can't parse data\n", __func__));
183 CloseLibrary(PNGBase);
184 return argb;
188 /****************************************************************************************/
190 static void GetChunkInfo(APTR stream, APTR *chunkdata, ULONG *chunksize)
192 png_unknown_chunkp chunkp = stream;
193 *chunksize = chunkp->size;
194 *chunkdata = chunkp->data;
197 /****************************************************************************************/
199 STATIC BOOL MakePlanarImage(struct NativeIcon *icon, struct Image **img, UBYTE *src, struct IconBase *IconBase)
201 LONG width16 = (icon->ni_DiskObject.do_Gadget.Width + 15) & ~15;
202 LONG bpr = width16 / 8;
203 LONG planesize = bpr * icon->ni_DiskObject.do_Gadget.Height;
204 LONG x, y;
205 UWORD *p1, *p2;
206 ULONG *s = (ULONG *) src;
208 *img = (struct Image *) AllocMemIcon(&icon->ni_DiskObject, sizeof(struct Image) + planesize * 2,
209 MEMF_PUBLIC | MEMF_CLEAR);
210 if (*img == NULL)
211 return FALSE;
213 (*img)->Width = icon->ni_DiskObject.do_Gadget.Width;
214 (*img)->Height = icon->ni_DiskObject.do_Gadget.Height;
215 (*img)->Depth = 2;
216 (*img)->ImageData = (UWORD *) (*img + 1);
217 (*img)->PlanePick = 3;
219 p1 = (UWORD *) (*img)->ImageData;
220 p2 = p1 + planesize / 2;
222 for (y = 0; y < (*img)->Height; y++)
224 ULONG pixelmask = 0x8000;
225 UWORD plane1dat = 0;
226 UWORD plane2dat = 0;
228 for (x = 0; x < (*img)->Width; x++)
230 ULONG pixel = *s++;
232 #if AROS_BIG_ENDIAN
233 if ((pixel & 0xFF000000) > 0x80000000)
235 pixel = (((pixel & 0x00FF0000) >> 16) +
236 ((pixel & 0x0000FF00) >> 8) +
237 ((pixel & 0x000000FF)) +
238 127) / 256;
239 #else
240 if ((pixel & 0x000000FF) > 0x80)
242 pixel = (((pixel & 0x0000FF00) >> 8) + ((pixel & 0x00FF0000) >> 16) + ((pixel & 0xFF000000) >> 24) + 127) / 256;
243 #endif
245 if (pixel == 3)
247 /* Col 2: White */
248 plane2dat |= pixelmask;
250 else if ((pixel == 2) || (pixel == 1))
252 /* Col 3: Amiga Blue */
253 plane1dat |= pixelmask;
254 plane2dat |= pixelmask;
256 else
258 /* Col 1: Black */
259 plane1dat |= pixelmask;
263 pixelmask >>= 1;
264 if (!pixelmask)
266 pixelmask = 0x8000;
267 *p1++ = AROS_WORD2BE(plane1dat);
268 *p2++ = AROS_WORD2BE(plane2dat);
270 plane1dat = plane2dat = 0;
276 if (pixelmask != 0x8000)
278 *p1++ = AROS_WORD2BE(plane1dat);
279 *p2++ = AROS_WORD2BE(plane2dat);
283 } /* for(y = 0; y < icon->ni_Height; y++) */
285 return TRUE;
289 /****************************************************************************************/
291 STATIC BOOL MakePlanarImages(struct NativeIcon *icon, struct IconBase *IconBase)
293 if (!MakePlanarImage(icon, (struct Image **) &icon->ni_DiskObject.do_Gadget.GadgetRender,
294 (UBYTE *)icon->ni_Image[0].ARGB, IconBase))
296 return FALSE;
299 icon->ni_DiskObject.do_Gadget.Flags |= GFLG_GADGIMAGE;
301 if (!icon->ni_Image[1].ARGB)
302 return TRUE;
304 if (MakePlanarImage(icon, (struct Image **) &icon->ni_DiskObject.do_Gadget.SelectRender,
305 (UBYTE *)icon->ni_Image[1].ARGB, IconBase))
307 icon->ni_DiskObject.do_Gadget.Flags |= GFLG_GADGHIMAGE;
310 return TRUE;
313 /****************************************************************************************/
315 BOOL ReadIconPNG(struct DiskObject *dobj, BPTR file, struct IconBase *IconBase)
317 static CONST_STRPTR const chunknames[] =
319 "icOn",
320 NULL
322 APTR chunkpointer[] =
324 NULL,
325 NULL
328 struct NativeIcon *icon;
329 ULONG filesize;
330 APTR data;
332 icon = NATIVEICON(dobj);
334 D(bug("%s: File stream %p\n", __func__, file));
336 if (Seek(file, 0, OFFSET_END) < 0) return FALSE;
337 if ((filesize = Seek(file, 0, OFFSET_BEGINNING)) < 0) return FALSE;
339 D(bug("[%s] Inspecting a %d byte file\n", __func__, filesize));
341 /* Need a copy of whole file in memory for icon saving :-\ Because
342 that should save file back as it was, only with modified or new
343 icOn chunk. And it must also work when loading an icon and then
344 saving it using another name. */
346 data = AllocMemIcon(&icon->ni_DiskObject, filesize, MEMF_PUBLIC);
347 if (!data)
348 return FALSE;
350 if (Read(file, data, filesize) != filesize)
352 D(bug("[%s] Can't read from file\n", __func__));
353 return FALSE;
356 icon->ni_Extra.Data = data;
357 icon->ni_Extra.Size = filesize;
359 icon->ni_Extra.PNG[0].Offset = 0;
360 icon->ni_Extra.PNG[0].Size = filesize;
362 ULONG width = ~0, height = ~0;
364 icon->ni_Image[0].ARGB = ReadMemPNG(&icon->ni_DiskObject, icon->ni_Extra.Data + icon->ni_Extra.PNG[0].Offset, &width, &height, chunknames, chunkpointer, IconBase);
365 if (icon->ni_Image[0].ARGB == NULL) {
366 D(bug("[%s] Can't parse PNG image at 0\n", __func__));
367 return FALSE;
370 icon->ni_Face.Width = width;
371 icon->ni_Face.Height = height;
372 icon->ni_Face.Aspect = ICON_ASPECT_RATIO_UNKNOWN;
374 #define DO(x) (&x->ni_DiskObject)
376 DO(icon)->do_Magic = WB_DISKMAGIC;
377 DO(icon)->do_Version = (WB_DISKVERSION << 8) | WB_DISKREVISION;
378 DO(icon)->do_Type = 0; /* Invalid */
379 DO(icon)->do_CurrentX = NO_ICON_POSITION;
380 DO(icon)->do_CurrentY = NO_ICON_POSITION;
381 DO(icon)->do_Gadget.Width = width;
382 DO(icon)->do_Gadget.Height = height;
383 DO(icon)->do_StackSize = AROS_STACKSIZE;
385 if (chunkpointer[0])
387 UBYTE *chunkdata;
388 ULONG chunksize;
389 ULONG ttnum = 0;
390 ULONG ttarraysize = 0;
391 BOOL ok = TRUE;
393 GetChunkInfo(chunkpointer[0], (APTR *)&chunkdata, &chunksize);
395 while(chunksize >= 4)
397 ULONG attr;
398 IPTR val = 0;
399 BOOL need_drawerdata = FALSE;
401 attr = (chunkdata[0] << 24) | (chunkdata[1] << 16) | (chunkdata[2] << 8) | chunkdata[3];
402 chunksize -=4;
403 chunkdata += 4;
405 switch(attr)
407 case ATTR_DRAWERX:
408 case ATTR_DRAWERY:
409 case ATTR_DRAWERWIDTH:
410 case ATTR_DRAWERHEIGHT:
411 case ATTR_DRAWERFLAGS:
412 case ATTR_DRAWERFLAGS2:
413 case ATTR_DRAWERFLAGS3:
414 case ATTR_VIEWMODES:
415 case ATTR_VIEWMODES2:
416 case ATTR_DD_CURRENTX:
417 case ATTR_DD_CURRENTY:
418 need_drawerdata = TRUE;
419 /* Fall through */
421 case ATTR_ICONX:
422 case ATTR_ICONY:
423 case ATTR_STACKSIZE:
424 case ATTR_TYPE:
425 case ATTR_FRAMELESS:
426 if (chunksize >= 4)
428 val = (chunkdata[0] << 24) | (chunkdata[1] << 16) | (chunkdata[2] << 8) | chunkdata[3];
429 chunksize -=4;
430 chunkdata += 4;
432 else
434 ok = FALSE;
436 break;
438 /* case ATTR_UNKNOWN: */
439 case ATTR_DEFAULTTOOL:
440 case ATTR_TOOLTYPE:
441 val = (IPTR)chunkdata;
442 chunksize -= strlen((char *)val) + 1;
443 chunkdata += strlen((char *)val) + 1;
445 if (chunksize < 0)
447 ok = FALSE;
449 break;
451 default:
452 /* Unknown attribute/tag. Impossible to handle correctly
453 if we don't know if it's a string attribute or not. */
454 ok = FALSE;
455 break;
457 } /* switch(attr) */
459 if (!ok) break;
461 if (need_drawerdata && !(DO(icon)->do_DrawerData))
463 DO(icon)->do_DrawerData = AllocMemIcon(DO(icon), sizeof(struct DrawerData), MEMF_PUBLIC | MEMF_CLEAR);
464 if (!(DO(icon)->do_DrawerData))
466 ok = FALSE;
467 break;
470 DO(icon)->do_DrawerData->dd_NewWindow.LeftEdge = 20;
471 DO(icon)->do_DrawerData->dd_NewWindow.TopEdge = 20;
472 DO(icon)->do_DrawerData->dd_NewWindow.Width = 300;
473 DO(icon)->do_DrawerData->dd_NewWindow.Height = 200;
474 DO(icon)->do_Gadget.UserData = (APTR)1; /* See DupDiskObject logic */
477 switch(attr)
479 case ATTR_ICONX:
480 DO(icon)->do_CurrentX = val;
481 break;
483 case ATTR_ICONY:
484 DO(icon)->do_CurrentY = val;
485 break;
487 case ATTR_STACKSIZE:
488 DO(icon)->do_StackSize = val;
489 break;
491 case ATTR_DRAWERX:
492 DO(icon)->do_DrawerData->dd_NewWindow.LeftEdge = (WORD)val;
493 break;
495 case ATTR_DRAWERY:
496 DO(icon)->do_DrawerData->dd_NewWindow.TopEdge = (WORD)val;
497 break;
499 case ATTR_DRAWERWIDTH:
500 DO(icon)->do_DrawerData->dd_NewWindow.Width = (WORD)val;
501 break;
503 case ATTR_DRAWERHEIGHT:
504 DO(icon)->do_DrawerData->dd_NewWindow.Height = (WORD)val;
505 break;
507 case ATTR_DRAWERFLAGS:
508 DO(icon)->do_DrawerData->dd_Flags = flags_to_ddflags(val);
509 DO(icon)->do_DrawerData->dd_ViewModes = flags_to_ddviewmodes(val);
510 break;
512 case ATTR_DEFAULTTOOL:
513 DO(icon)->do_DefaultTool = AllocMemIcon(DO(icon), strlen((char *)val) + 1, MEMF_PUBLIC | MEMF_CLEAR);
514 if (DO(icon)->do_DefaultTool)
516 strcpy(DO(icon)->do_DefaultTool, (char *)val);
518 else
520 ok = FALSE;
522 break;
523 case ATTR_FRAMELESS:
524 NATIVEICON(icon)->ni_Frameless = val ? TRUE : FALSE;
525 break;
527 case ATTR_TOOLTYPE:
528 ttnum++;
530 D(bug("[Icon.PNG] Got tooltype number %u : %s\n", ttnum - 1, val));
532 if (ttarraysize < ttnum + 1)
534 STRPTR *old_tooltypes = DO(icon)->do_ToolTypes;
536 ttarraysize += 10;
538 DO(icon)->do_ToolTypes = AllocMemIcon(DO(icon), ttarraysize * sizeof(APTR), MEMF_PUBLIC | MEMF_CLEAR);
539 if (DO(icon)->do_ToolTypes)
541 D(bug("[Icon.PNG] Allocated array of %u entries @ 0x%p (old 0x%p)\n", ttarraysize, DO(icon)->do_ToolTypes, old_tooltypes));
542 if (old_tooltypes)
544 CopyMemQuick(old_tooltypes, DO(icon)->do_ToolTypes, (ttnum - 1) * sizeof(APTR));
546 /* TODO: Free old array */
549 else
551 ok = FALSE;
555 if (!ok) break;
557 DO(icon)->do_ToolTypes[ttnum - 1] = AllocMemIcon(DO(icon), strlen((char *)val) + 1, MEMF_PUBLIC | MEMF_CLEAR);
558 if (DO(icon)->do_ToolTypes[ttnum - 1])
560 strcpy(DO(icon)->do_ToolTypes[ttnum - 1], (char *)val);
562 else
564 ok = FALSE;
566 break;
568 } /* switch(attr) */
570 if (!ok) break;
572 } /* while(chunksize >= 4) */
574 if (!ok)
576 D(bug("=== Failure during icOn chunk parsing ===\n"));
577 FreeIconPNG(&icon->ni_DiskObject, IconBase);
578 return FALSE;
582 } /* if (chunkpointer[0]) */
584 #undef DO
587 * FIXME: Someone killed PNG Icon do_Type detection here which causes
588 * following lines to always free DrawerData even when it
589 * shouldn't be freed (only possible to know if do_Type is
590 * known). So for now following lines disabled and DrawerData
591 * is always kept (even when it shouldn't).
594 #if 0
595 if (icon->ni_DiskObject.do_DrawerData &&
596 (icon->ni_DiskObject.do_Type != WBDISK) &&
597 (icon->ni_DiskObject.do_Type != WBDRAWER) &&
598 (icon->ni_DiskObject.do_Type != WBGARBAGE))
600 FreePooled(pool, icon->ni_DiskObject.do_DrawerData, sizeof(struct DrawerData));
601 icon->ni_DiskObject.do_DrawerData = NULL;
603 #endif
605 } /**/
607 /* Look for a possible 2nd PNG image attached onto the first one */
609 UBYTE *filepos = icon->ni_Extra.Data + icon->ni_Extra.PNG[0].Offset + 8;
610 BOOL done = FALSE;
612 while(!done && filepos < ((UBYTE *)icon->ni_Extra.Data + icon->ni_Extra.Size))
614 ULONG chunksize = (filepos[0] << 24) | (filepos[1] << 16) |
615 (filepos[2] << 8) | filepos[3];
616 ULONG chunktype = (filepos[4] << 24) | (filepos[5] << 16) |
617 (filepos[6] << 8) | filepos[7];
619 chunksize += 12;
621 if (chunktype == MAKE_ID('I', 'E', 'N', 'D'))
623 done = TRUE;
626 filepos += chunksize;
629 if (filepos + 8 < (UBYTE *)icon->ni_Extra.Data + icon->ni_Extra.Size)
631 ULONG offset = filepos - (UBYTE *)icon->ni_Extra.Data;
633 icon->ni_Extra.PNG[0].Size = offset;
634 icon->ni_Extra.PNG[1].Offset = offset;
635 icon->ni_Extra.PNG[1].Size = (filesize - icon->ni_Extra.PNG[0].Size);
636 icon->ni_Image[1].ARGB = ReadMemPNG(&icon->ni_DiskObject, filepos, &icon->ni_Face.Width, &icon->ni_Face.Height, NULL, NULL, IconBase);
639 } /**/
641 /* If there's no image for selected-state, generate one */
642 if (!icon->ni_Image[1].ARGB)
644 ULONG size = icon->ni_Face.Width * icon->ni_Face.Height;
646 if ((icon->ni_Image[1].ARGB = AllocMemIcon(&icon->ni_DiskObject, size * sizeof(ULONG), MEMF_PUBLIC)))
648 ULONG *src = (ULONG *)icon->ni_Image[0].ARGB;
649 ULONG *dst = (ULONG *)icon->ni_Image[1].ARGB;
651 while(size--)
653 ULONG pixel = *src++;
655 /* Effects like in changetoselectediconcolor.c */
657 #if EFFECT == EFFECT_LIGHTEN
658 #if AROS_BIG_ENDIAN
659 pixel = (pixel & 0xFF000000) +
660 ((pixel >> 1) & 0x007F7F7F) +
661 0x00808080;
662 #else
663 pixel = (pixel & 0x000000FF) +
664 ((pixel >> 1) & 0x7F7F7F00) +
665 0x80808000;
666 #endif
667 #elif EFFECT == EFFECT_TINT_BLUE
668 #if AROS_BIG_ENDIAN
669 pixel = (pixel & 0xFF000000) +
670 ((pixel >> 1) & 0x007F7F7F) +
671 0x00000080;
672 #else
673 pixel = (pixel & 0x000000FF) +
674 ((pixel >> 1) & 0x7F7F7F00) +
675 0x80000000;
676 #endif
678 #elif EFFECT == EFFECT_XOR
679 #if AROS_BIG_ENDIAN
680 pixel = (pixel & 0xFF000000) +
681 ((pixel & 0x00FFFFFF) ^ 0x00FFFFFF);
682 #else
683 pixel = (pixel & 0x000000FF) +
684 ((pixel & 0xFFFFFF00) ^ 0xFFFFFF00);
685 #endif
686 #endif
687 *dst++ = pixel;
693 * Support old-style AROS PNG icons. 3rd party applications
694 * will still be using them.
697 if (!MakePlanarImages(icon, IconBase))
699 D(bug("Planar image creation failed\n"));
700 FreeIconPNG(&icon->ni_DiskObject, IconBase);
701 return FALSE;
704 return TRUE;
708 /****************************************************************************************/
710 STATIC VOID MakeCRCTable(struct IconBase *IconBase)
712 unsigned long c;
713 int n, k;
715 IconBase->ib_CRCTable = AllocMem(256 * sizeof(ULONG), MEMF_ANY);
716 if (!IconBase->ib_CRCTable)
717 return;
718 for (n = 0; n < 256; n++)
720 c = (unsigned long) n;
721 for (k = 0; k < 8; k++)
723 if (c & 1)
724 c = 0xedb88320L ^ (c >> 1);
725 else
726 c = c >> 1;
728 IconBase->ib_CRCTable[n] = c;
732 /****************************************************************************************/
734 STATIC ULONG UpdateCRC(ULONG crc, UBYTE *buf, ULONG len, struct IconBase *IconBase)
736 ULONG c = crc;
737 ULONG n;
739 for (n = 0; n < len; n++)
741 c = IconBase->ib_CRCTable[(c ^ buf[n]) & 0xff] ^ (c >> 8);
744 return c;
748 /****************************************************************************************/
750 STATIC BOOL WriteIconAttr(BPTR file, ULONG id, ULONG val, ULONG *chunksize,
751 ULONG *crc, struct IconBase *IconBase)
753 UBYTE buf[8];
755 buf[0] = id >> 24;
756 buf[1] = id >> 16;
757 buf[2] = id >> 8;
758 buf[3] = id;
759 buf[4] = val >> 24;
760 buf[5] = val >> 16;
761 buf[6] = val >> 8;
762 buf[7] = val;
764 if (Write(file, buf, 8) != 8) return FALSE;
766 *chunksize += 8;
767 *crc = UpdateCRC(*crc, buf, 8, IconBase);
768 return TRUE;
771 /****************************************************************************************/
773 STATIC BOOL WriteIconStrAttr(BPTR file, ULONG id, char *val, ULONG *chunksize,
774 ULONG *crc, struct IconBase *IconBase)
776 UBYTE buf[4];
777 ULONG len = strlen(val) + 1;
779 buf[0] = id >> 24;
780 buf[1] = id >> 16;
781 buf[2] = id >> 8;
782 buf[3] = id;
784 if (Write(file, buf, 4) != 4) return FALSE;
785 *crc = UpdateCRC(*crc, buf, 4, IconBase);
787 if (Write(file, val, len) != len) return FALSE;
788 *crc = UpdateCRC(*crc, val, len, IconBase);
790 *chunksize += 4 + len;
792 return TRUE;
795 /****************************************************************************************/
797 STATIC BOOL WriteIconChunk(BPTR file, struct DiskObject *dobj, struct IconBase *IconBase)
799 ULONG crc = 0xFFFFFFFF;
800 ULONG chunksize = 0;
801 ULONG sizeseek = Seek(file, 0, OFFSET_CURRENT);
802 UBYTE buf[] = {0x12, 0x34, 0x56, 0x78, 'i', 'c', 'O', 'n'};
804 if (sizeseek < 0) return FALSE;
806 /* Write Chunk size + chunk type */
807 if (Write(file, buf, 8) != 8) return FALSE;
809 crc = UpdateCRC(crc, buf + 4, 4, IconBase); /* chunksize is excluded from CRC */
811 /* Write Frameless */
812 if (!WriteIconAttr(file, ATTR_FRAMELESS, NATIVEICON(dobj)->ni_Frameless, &chunksize, &crc, IconBase))
814 return FALSE;
817 /* Write Stack Size */
819 if (!WriteIconAttr(file, ATTR_STACKSIZE, dobj->do_StackSize, &chunksize, &crc, IconBase))
821 return FALSE;
824 /* Write Icon X Position */
825 if (dobj->do_CurrentX != NO_ICON_POSITION)
827 if (!WriteIconAttr(file, ATTR_ICONX, dobj->do_CurrentX, &chunksize, &crc, IconBase))
829 return FALSE;
833 /* Write Icon Y Position */
834 if (dobj->do_CurrentY != NO_ICON_POSITION)
836 if (!WriteIconAttr(file, ATTR_ICONY, dobj->do_CurrentY, &chunksize, &crc, IconBase))
838 return FALSE;
842 if (dobj->do_DrawerData)
844 if (!WriteIconAttr(file, ATTR_DRAWERX, dobj->do_DrawerData->dd_NewWindow.LeftEdge,
845 &chunksize, &crc, IconBase))
847 return FALSE;
850 if (!WriteIconAttr(file, ATTR_DRAWERY, dobj->do_DrawerData->dd_NewWindow.TopEdge,
851 &chunksize, &crc, IconBase))
853 return FALSE;
856 if (!WriteIconAttr(file, ATTR_DRAWERWIDTH, dobj->do_DrawerData->dd_NewWindow.Width,
857 &chunksize, &crc, IconBase))
859 return FALSE;
862 if (!WriteIconAttr(file, ATTR_DRAWERHEIGHT, dobj->do_DrawerData->dd_NewWindow.Height,
863 &chunksize, &crc, IconBase))
865 return FALSE;
868 if (!WriteIconAttr(file, ATTR_DRAWERFLAGS, dd_to_flags(dobj),
869 &chunksize, &crc, IconBase))
871 return FALSE;
874 } /* if (dobj->do_DrawerData) */
876 if (dobj->do_DefaultTool)
878 if (!WriteIconStrAttr(file, ATTR_DEFAULTTOOL, dobj->do_DefaultTool,
879 &chunksize, &crc, IconBase))
881 return FALSE;
886 if (dobj->do_ToolTypes)
888 STRPTR *tt = (STRPTR *)dobj->do_ToolTypes;
890 for(tt = (STRPTR *)dobj->do_ToolTypes; *tt; tt++)
892 if (!WriteIconStrAttr(file, ATTR_TOOLTYPE, *tt, &chunksize,
893 &crc, IconBase))
895 return FALSE;
900 /* Write CRC */
902 crc ^= 0xFFFFFFFF;
903 buf[0] = crc >> 24;
904 buf[1] = crc >> 16;
905 buf[2] = crc >> 8;
906 buf[3] = crc;
907 if (Write(file, buf, 4) != 4) return FALSE;
909 /* Write chunk's size */
910 if (Seek(file, sizeseek, OFFSET_BEGINNING) < 0) return FALSE;
912 buf[0] = chunksize >> 24;
913 buf[1] = chunksize >> 16;
914 buf[2] = chunksize >> 8;
915 buf[3] = chunksize;
916 if (Write(file, buf, 4) != 4) return FALSE;
918 if (Seek(file, 0, OFFSET_END) < 0) return FALSE;
920 return TRUE;
923 /****************************************************************************************/
925 BOOL WriteIconPNG(BPTR file, struct DiskObject *dobj, struct IconBase *IconBase)
927 struct NativeIcon *nativeicon = NATIVEICON(dobj);
928 UBYTE *mempos = nativeicon->ni_Extra.Data + nativeicon->ni_Extra.PNG[0].Offset;
929 BOOL done = FALSE;
931 D(bug("%s: ni=%p, ni->ni_Extra.Data = %p\n", __func__, nativeicon, nativeicon->ni_Extra.Data));
932 if (nativeicon->ni_Extra.Data == NULL)
933 return FALSE;
935 ObtainSemaphore(&IconBase->iconlistlock);
936 if (!IconBase->ib_CRCTable)
937 MakeCRCTable(IconBase);
938 ReleaseSemaphore(&IconBase->iconlistlock);
939 if (!IconBase->ib_CRCTable)
940 return FALSE;
942 /* Write PNG header */
943 if (Write(file, mempos, 8) != 8) return FALSE;
945 mempos += 8;
947 while(!done)
949 ULONG chunksize = (mempos[0] << 24) | (mempos[1] << 16) |
950 (mempos[2] << 8) | mempos[3];
951 ULONG chunktype = (mempos[4] << 24) | (mempos[5] << 16) |
952 (mempos[6] << 8) | mempos[7];
954 chunksize += 12;
956 if (chunktype == MAKE_ID('I', 'E', 'N', 'D'))
958 if (!WriteIconChunk(file, dobj, IconBase)) return FALSE;
959 done = TRUE;
962 if (chunktype != MAKE_ID('i', 'c', 'O', 'n'))
964 if (Write(file, mempos, chunksize) != chunksize)
966 return FALSE;
970 mempos += chunksize;
974 if (nativeicon->ni_Extra.PNG[1].Offset > 0)
976 ULONG size = nativeicon->ni_Extra.PNG[1].Size;
978 /* 2nd PNG Image attached */
980 if (Write(file, nativeicon->ni_Extra.Data + nativeicon->ni_Extra.PNG[1].Offset, size) != size) return FALSE;
983 return TRUE;
986 /****************************************************************************************/
988 VOID FreeIconPNG(struct DiskObject *dobj, struct IconBase *IconBase)
992 /****************************************************************************************/