Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / libs / icon / diskobjPNGio.c
blob7acf5c69a6e5a0665dc9a3ee81843a7e8a2e6c75
1 /*
2 Copyright © 1995-2014, 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/pngdt.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),
150 MEMF_PUBLIC, IconBase);
151 if (argb) {
152 xoff = ((*width) - w)/2;
153 yoff = ((*height) - h)/2;
155 dst = argb;
156 for (y = 0; y < *height; y++) {
157 LONG sy = y + yoff;
159 if (sy < 0)
160 sy = 0;
162 if (sy >= h)
163 sy = h-1;
165 for (x = 0; x < *width; x++, dst++) {
166 LONG sx = x + xoff;
168 if (sx < 0)
169 sx = 0;
171 if (sx >= w)
172 sx = w-1;
174 *dst = src[sy*w+sx];
179 PNG_FreeImage(handle);
180 } else {
181 D(bug("[%s] PNG datatype can't parse data\n", __func__));
184 CloseLibrary(PNGBase);
185 return argb;
189 /****************************************************************************************/
191 static void GetChunkInfo(APTR stream, APTR *chunkdata, ULONG *chunksize)
193 png_unknown_chunkp chunkp = stream;
194 *chunksize = chunkp->size;
195 *chunkdata = chunkp->data;
198 /****************************************************************************************/
200 STATIC BOOL MakePlanarImage(struct NativeIcon *icon, struct Image **img, UBYTE *src, struct IconBase *IconBase)
202 LONG width16 = (icon->ni_DiskObject.do_Gadget.Width + 15) & ~15;
203 LONG bpr = width16 / 8;
204 LONG planesize = bpr * icon->ni_DiskObject.do_Gadget.Height;
205 LONG x, y;
206 UWORD *p1, *p2;
207 ULONG *s = (ULONG *) src;
209 *img = (struct Image *) AllocMemIcon(&icon->ni_DiskObject,
210 sizeof(struct Image) + planesize * 2, MEMF_PUBLIC | MEMF_CLEAR,
211 IconBase);
212 if (*img == NULL)
213 return FALSE;
215 (*img)->Width = icon->ni_DiskObject.do_Gadget.Width;
216 (*img)->Height = icon->ni_DiskObject.do_Gadget.Height;
217 (*img)->Depth = 2;
218 (*img)->ImageData = (UWORD *) (*img + 1);
219 (*img)->PlanePick = 3;
221 p1 = (UWORD *) (*img)->ImageData;
222 p2 = p1 + planesize / 2;
224 for (y = 0; y < (*img)->Height; y++)
226 ULONG pixelmask = 0x8000;
227 UWORD plane1dat = 0;
228 UWORD plane2dat = 0;
230 for (x = 0; x < (*img)->Width; x++)
232 ULONG pixel = *s++;
234 #if AROS_BIG_ENDIAN
235 if ((pixel & 0xFF000000) > 0x80000000)
237 pixel = (((pixel & 0x00FF0000) >> 16) +
238 ((pixel & 0x0000FF00) >> 8) +
239 ((pixel & 0x000000FF)) +
240 127) / 256;
241 #else
242 if ((pixel & 0x000000FF) > 0x80)
244 pixel = (((pixel & 0x0000FF00) >> 8) + ((pixel & 0x00FF0000) >> 16) + ((pixel & 0xFF000000) >> 24) + 127) / 256;
245 #endif
247 if (pixel == 3)
249 /* Col 2: White */
250 plane2dat |= pixelmask;
252 else if ((pixel == 2) || (pixel == 1))
254 /* Col 3: Amiga Blue */
255 plane1dat |= pixelmask;
256 plane2dat |= pixelmask;
258 else
260 /* Col 1: Black */
261 plane1dat |= pixelmask;
265 pixelmask >>= 1;
266 if (!pixelmask)
268 pixelmask = 0x8000;
269 *p1++ = AROS_WORD2BE(plane1dat);
270 *p2++ = AROS_WORD2BE(plane2dat);
272 plane1dat = plane2dat = 0;
278 if (pixelmask != 0x8000)
280 *p1++ = AROS_WORD2BE(plane1dat);
281 *p2++ = AROS_WORD2BE(plane2dat);
285 } /* for(y = 0; y < icon->ni_Height; y++) */
287 return TRUE;
291 /****************************************************************************************/
293 STATIC BOOL MakePlanarImages(struct NativeIcon *icon, struct IconBase *IconBase)
295 if (!MakePlanarImage(icon, (struct Image **) &icon->ni_DiskObject.do_Gadget.GadgetRender,
296 (UBYTE *)icon->ni_Image[0].ARGB, IconBase))
298 return FALSE;
301 icon->ni_DiskObject.do_Gadget.Flags |= GFLG_GADGIMAGE;
303 if (!icon->ni_Image[1].ARGB)
304 return TRUE;
306 if (MakePlanarImage(icon, (struct Image **) &icon->ni_DiskObject.do_Gadget.SelectRender,
307 (UBYTE *)icon->ni_Image[1].ARGB, IconBase))
309 icon->ni_DiskObject.do_Gadget.Flags |= GFLG_GADGHIMAGE;
312 return TRUE;
315 /****************************************************************************************/
317 BOOL ReadIconPNG(struct DiskObject *dobj, BPTR file, struct IconBase *IconBase)
319 static CONST_STRPTR const chunknames[] =
321 "icOn",
322 NULL
324 APTR chunkpointer[] =
326 NULL,
327 NULL
330 struct NativeIcon *icon;
331 ULONG filesize;
332 APTR data;
334 icon = NATIVEICON(dobj);
336 D(bug("%s: File stream %p\n", __func__, file));
338 if (Seek(file, 0, OFFSET_END) < 0) return FALSE;
339 if ((filesize = Seek(file, 0, OFFSET_BEGINNING)) < 0) return FALSE;
341 D(bug("[%s] Inspecting a %d byte file\n", __func__, filesize));
343 /* Need a copy of whole file in memory for icon saving :-\ Because
344 that should save file back as it was, only with modified or new
345 icOn chunk. And it must also work when loading an icon and then
346 saving it using another name. */
348 data = AllocMemIcon(&icon->ni_DiskObject, filesize, MEMF_PUBLIC,
349 IconBase);
350 if (!data)
351 return FALSE;
353 if (Read(file, data, filesize) != filesize)
355 D(bug("[%s] Can't read from file\n", __func__));
356 return FALSE;
359 icon->ni_Extra.Data = data;
360 icon->ni_Extra.Size = filesize;
362 icon->ni_Extra.PNG[0].Offset = 0;
363 icon->ni_Extra.PNG[0].Size = filesize;
365 ULONG width = ~0, height = ~0;
367 icon->ni_Image[0].ARGB = ReadMemPNG(&icon->ni_DiskObject, icon->ni_Extra.Data + icon->ni_Extra.PNG[0].Offset, &width, &height, chunknames, chunkpointer, IconBase);
368 if (icon->ni_Image[0].ARGB == NULL) {
369 D(bug("[%s] Can't parse PNG image at 0\n", __func__));
370 return FALSE;
373 icon->ni_Face.Width = width;
374 icon->ni_Face.Height = height;
375 icon->ni_Face.Aspect = ICON_ASPECT_RATIO_UNKNOWN;
377 #define DO(x) (&x->ni_DiskObject)
379 DO(icon)->do_Magic = WB_DISKMAGIC;
380 DO(icon)->do_Version = (WB_DISKVERSION << 8) | WB_DISKREVISION;
381 DO(icon)->do_Type = 0; /* Invalid */
382 DO(icon)->do_CurrentX = NO_ICON_POSITION;
383 DO(icon)->do_CurrentY = NO_ICON_POSITION;
384 DO(icon)->do_Gadget.Width = width;
385 DO(icon)->do_Gadget.Height = height;
386 DO(icon)->do_StackSize = AROS_STACKSIZE;
388 if (chunkpointer[0])
390 UBYTE *chunkdata;
391 ULONG chunksize;
392 ULONG ttnum = 0;
393 ULONG ttarraysize = 0;
394 BOOL ok = TRUE;
396 GetChunkInfo(chunkpointer[0], (APTR *)&chunkdata, &chunksize);
398 while(chunksize >= 4)
400 ULONG attr;
401 IPTR val = 0;
402 BOOL need_drawerdata = FALSE;
404 attr = (chunkdata[0] << 24) | (chunkdata[1] << 16) | (chunkdata[2] << 8) | chunkdata[3];
405 chunksize -=4;
406 chunkdata += 4;
408 switch(attr)
410 case ATTR_DRAWERX:
411 case ATTR_DRAWERY:
412 case ATTR_DRAWERWIDTH:
413 case ATTR_DRAWERHEIGHT:
414 case ATTR_DRAWERFLAGS:
415 case ATTR_DRAWERFLAGS2:
416 case ATTR_DRAWERFLAGS3:
417 case ATTR_VIEWMODES:
418 case ATTR_VIEWMODES2:
419 case ATTR_DD_CURRENTX:
420 case ATTR_DD_CURRENTY:
421 need_drawerdata = TRUE;
422 /* Fall through */
424 case ATTR_ICONX:
425 case ATTR_ICONY:
426 case ATTR_STACKSIZE:
427 case ATTR_TYPE:
428 case ATTR_FRAMELESS:
429 if (chunksize >= 4)
431 val = (chunkdata[0] << 24) | (chunkdata[1] << 16) | (chunkdata[2] << 8) | chunkdata[3];
432 chunksize -=4;
433 chunkdata += 4;
435 else
437 ok = FALSE;
439 break;
441 /* case ATTR_UNKNOWN: */
442 case ATTR_DEFAULTTOOL:
443 case ATTR_TOOLTYPE:
444 val = (IPTR)chunkdata;
445 chunksize -= strlen((char *)val) + 1;
446 chunkdata += strlen((char *)val) + 1;
448 if (chunksize < 0)
450 ok = FALSE;
452 break;
454 default:
455 /* Unknown attribute/tag. Impossible to handle correctly
456 if we don't know if it's a string attribute or not. */
457 ok = FALSE;
458 break;
460 } /* switch(attr) */
462 if (!ok) break;
464 if (need_drawerdata && !(DO(icon)->do_DrawerData))
466 DO(icon)->do_DrawerData =
467 AllocMemIcon(DO(icon), sizeof(struct DrawerData),
468 MEMF_PUBLIC | MEMF_CLEAR, IconBase);
469 if (!(DO(icon)->do_DrawerData))
471 ok = FALSE;
472 break;
475 DO(icon)->do_DrawerData->dd_NewWindow.LeftEdge = 20;
476 DO(icon)->do_DrawerData->dd_NewWindow.TopEdge = 20;
477 DO(icon)->do_DrawerData->dd_NewWindow.Width = 300;
478 DO(icon)->do_DrawerData->dd_NewWindow.Height = 200;
479 DO(icon)->do_Gadget.UserData = (APTR)1; /* See DupDiskObject logic */
482 switch(attr)
484 case ATTR_ICONX:
485 DO(icon)->do_CurrentX = val;
486 break;
488 case ATTR_ICONY:
489 DO(icon)->do_CurrentY = val;
490 break;
492 case ATTR_STACKSIZE:
493 DO(icon)->do_StackSize = val;
494 break;
496 case ATTR_DRAWERX:
497 DO(icon)->do_DrawerData->dd_NewWindow.LeftEdge = (WORD)val;
498 break;
500 case ATTR_DRAWERY:
501 DO(icon)->do_DrawerData->dd_NewWindow.TopEdge = (WORD)val;
502 break;
504 case ATTR_DRAWERWIDTH:
505 DO(icon)->do_DrawerData->dd_NewWindow.Width = (WORD)val;
506 break;
508 case ATTR_DRAWERHEIGHT:
509 DO(icon)->do_DrawerData->dd_NewWindow.Height = (WORD)val;
510 break;
512 case ATTR_DRAWERFLAGS:
513 DO(icon)->do_DrawerData->dd_Flags = flags_to_ddflags(val);
514 DO(icon)->do_DrawerData->dd_ViewModes = flags_to_ddviewmodes(val);
515 break;
517 case ATTR_DEFAULTTOOL:
518 DO(icon)->do_DefaultTool =
519 AllocMemIcon(DO(icon), strlen((char *)val) + 1,
520 MEMF_PUBLIC | MEMF_CLEAR, IconBase);
521 if (DO(icon)->do_DefaultTool)
523 strcpy(DO(icon)->do_DefaultTool, (char *)val);
525 else
527 ok = FALSE;
529 break;
530 case ATTR_FRAMELESS:
531 NATIVEICON(icon)->ni_Frameless = val ? TRUE : FALSE;
532 break;
534 case ATTR_TOOLTYPE:
535 ttnum++;
537 D(bug("[Icon.PNG] Got tooltype number %u : %s\n", ttnum - 1, val));
539 if (ttarraysize < ttnum + 1)
541 STRPTR *old_tooltypes = DO(icon)->do_ToolTypes;
543 ttarraysize += 10;
545 DO(icon)->do_ToolTypes =
546 AllocMemIcon(DO(icon),
547 ttarraysize * sizeof(APTR),
548 MEMF_PUBLIC | MEMF_CLEAR, IconBase);
549 if (DO(icon)->do_ToolTypes)
551 D(bug("[Icon.PNG] Allocated array of %u entries @ 0x%p (old 0x%p)\n", ttarraysize, DO(icon)->do_ToolTypes, old_tooltypes));
552 if (old_tooltypes)
554 CopyMemQuick(old_tooltypes, DO(icon)->do_ToolTypes, (ttnum - 1) * sizeof(APTR));
556 /* TODO: Free old array */
559 else
561 ok = FALSE;
565 if (!ok) break;
567 DO(icon)->do_ToolTypes[ttnum - 1] =
568 AllocMemIcon(DO(icon), strlen((char *)val) + 1,
569 MEMF_PUBLIC | MEMF_CLEAR, IconBase);
570 if (DO(icon)->do_ToolTypes[ttnum - 1])
572 strcpy(DO(icon)->do_ToolTypes[ttnum - 1], (char *)val);
574 else
576 ok = FALSE;
578 break;
580 } /* switch(attr) */
582 if (!ok) break;
584 } /* while(chunksize >= 4) */
586 if (!ok)
588 D(bug("=== Failure during icOn chunk parsing ===\n"));
589 FreeIconPNG(&icon->ni_DiskObject, IconBase);
590 return FALSE;
594 } /* if (chunkpointer[0]) */
596 #undef DO
599 * FIXME: Someone killed PNG Icon do_Type detection here which causes
600 * following lines to always free DrawerData even when it
601 * shouldn't be freed (only possible to know if do_Type is
602 * known). So for now following lines disabled and DrawerData
603 * is always kept (even when it shouldn't).
606 #if 0
607 if (icon->ni_DiskObject.do_DrawerData &&
608 (icon->ni_DiskObject.do_Type != WBDISK) &&
609 (icon->ni_DiskObject.do_Type != WBDRAWER) &&
610 (icon->ni_DiskObject.do_Type != WBGARBAGE))
612 FreePooled(pool, icon->ni_DiskObject.do_DrawerData, sizeof(struct DrawerData));
613 icon->ni_DiskObject.do_DrawerData = NULL;
615 #endif
617 } /**/
619 /* Look for a possible 2nd PNG image attached onto the first one */
621 UBYTE *filepos = icon->ni_Extra.Data + icon->ni_Extra.PNG[0].Offset + 8;
622 BOOL done = FALSE;
624 while(!done && filepos < ((UBYTE *)icon->ni_Extra.Data + icon->ni_Extra.Size))
626 ULONG chunksize = (filepos[0] << 24) | (filepos[1] << 16) |
627 (filepos[2] << 8) | filepos[3];
628 ULONG chunktype = (filepos[4] << 24) | (filepos[5] << 16) |
629 (filepos[6] << 8) | filepos[7];
631 chunksize += 12;
633 if (chunktype == MAKE_ID('I', 'E', 'N', 'D'))
635 done = TRUE;
638 filepos += chunksize;
641 if (filepos + 8 < (UBYTE *)icon->ni_Extra.Data + icon->ni_Extra.Size)
643 ULONG offset = filepos - (UBYTE *)icon->ni_Extra.Data;
645 icon->ni_Extra.PNG[0].Size = offset;
646 icon->ni_Extra.PNG[1].Offset = offset;
647 icon->ni_Extra.PNG[1].Size = (filesize - icon->ni_Extra.PNG[0].Size);
648 icon->ni_Image[1].ARGB = ReadMemPNG(&icon->ni_DiskObject, filepos, &icon->ni_Face.Width, &icon->ni_Face.Height, NULL, NULL, IconBase);
651 } /**/
653 /* If there's no image for selected-state, generate one */
654 if (!icon->ni_Image[1].ARGB)
656 ULONG size = icon->ni_Face.Width * icon->ni_Face.Height;
658 if ((icon->ni_Image[1].ARGB =
659 AllocMemIcon(&icon->ni_DiskObject, size * sizeof(ULONG),
660 MEMF_PUBLIC, IconBase)))
662 ULONG *src = (ULONG *)icon->ni_Image[0].ARGB;
663 ULONG *dst = (ULONG *)icon->ni_Image[1].ARGB;
665 while(size--)
667 ULONG pixel = *src++;
669 /* Effects like in changetoselectediconcolor.c */
671 #if EFFECT == EFFECT_LIGHTEN
672 #if AROS_BIG_ENDIAN
673 pixel = (pixel & 0xFF000000) +
674 ((pixel >> 1) & 0x007F7F7F) +
675 0x00808080;
676 #else
677 pixel = (pixel & 0x000000FF) +
678 ((pixel >> 1) & 0x7F7F7F00) +
679 0x80808000;
680 #endif
681 #elif EFFECT == EFFECT_TINT_BLUE
682 #if AROS_BIG_ENDIAN
683 pixel = (pixel & 0xFF000000) +
684 ((pixel >> 1) & 0x007F7F7F) +
685 0x00000080;
686 #else
687 pixel = (pixel & 0x000000FF) +
688 ((pixel >> 1) & 0x7F7F7F00) +
689 0x80000000;
690 #endif
692 #elif EFFECT == EFFECT_XOR
693 #if AROS_BIG_ENDIAN
694 pixel = (pixel & 0xFF000000) +
695 ((pixel & 0x00FFFFFF) ^ 0x00FFFFFF);
696 #else
697 pixel = (pixel & 0x000000FF) +
698 ((pixel & 0xFFFFFF00) ^ 0xFFFFFF00);
699 #endif
700 #endif
701 *dst++ = pixel;
707 * Support old-style AROS PNG icons. 3rd party applications
708 * will still be using them.
711 if (!MakePlanarImages(icon, IconBase))
713 D(bug("Planar image creation failed\n"));
714 FreeIconPNG(&icon->ni_DiskObject, IconBase);
715 return FALSE;
718 return TRUE;
722 /****************************************************************************************/
724 STATIC VOID MakeCRCTable(struct IconBase *IconBase)
726 unsigned long c;
727 int n, k;
729 IconBase->ib_CRCTable = AllocMem(256 * sizeof(ULONG), MEMF_ANY);
730 if (!IconBase->ib_CRCTable)
731 return;
732 for (n = 0; n < 256; n++)
734 c = (unsigned long) n;
735 for (k = 0; k < 8; k++)
737 if (c & 1)
738 c = 0xedb88320L ^ (c >> 1);
739 else
740 c = c >> 1;
742 IconBase->ib_CRCTable[n] = c;
746 /****************************************************************************************/
748 STATIC ULONG UpdateCRC(ULONG crc, UBYTE *buf, ULONG len, struct IconBase *IconBase)
750 ULONG c = crc;
751 ULONG n;
753 for (n = 0; n < len; n++)
755 c = IconBase->ib_CRCTable[(c ^ buf[n]) & 0xff] ^ (c >> 8);
758 return c;
762 /****************************************************************************************/
764 STATIC BOOL WriteIconAttr(BPTR file, ULONG id, ULONG val, ULONG *chunksize,
765 ULONG *crc, struct IconBase *IconBase)
767 UBYTE buf[8];
769 buf[0] = id >> 24;
770 buf[1] = id >> 16;
771 buf[2] = id >> 8;
772 buf[3] = id;
773 buf[4] = val >> 24;
774 buf[5] = val >> 16;
775 buf[6] = val >> 8;
776 buf[7] = val;
778 if (Write(file, buf, 8) != 8) return FALSE;
780 *chunksize += 8;
781 *crc = UpdateCRC(*crc, buf, 8, IconBase);
782 return TRUE;
785 /****************************************************************************************/
787 STATIC BOOL WriteIconStrAttr(BPTR file, ULONG id, char *val, ULONG *chunksize,
788 ULONG *crc, struct IconBase *IconBase)
790 UBYTE buf[4];
791 ULONG len = strlen(val) + 1;
793 buf[0] = id >> 24;
794 buf[1] = id >> 16;
795 buf[2] = id >> 8;
796 buf[3] = id;
798 if (Write(file, buf, 4) != 4) return FALSE;
799 *crc = UpdateCRC(*crc, buf, 4, IconBase);
801 if (Write(file, val, len) != len) return FALSE;
802 *crc = UpdateCRC(*crc, val, len, IconBase);
804 *chunksize += 4 + len;
806 return TRUE;
809 /****************************************************************************************/
811 STATIC BOOL WriteIconChunk(BPTR file, struct DiskObject *dobj, struct IconBase *IconBase)
813 ULONG crc = 0xFFFFFFFF;
814 ULONG chunksize = 0;
815 ULONG sizeseek = Seek(file, 0, OFFSET_CURRENT);
816 UBYTE buf[] = {0x12, 0x34, 0x56, 0x78, 'i', 'c', 'O', 'n'};
818 if (sizeseek < 0) return FALSE;
820 /* Write Chunk size + chunk type */
821 if (Write(file, buf, 8) != 8) return FALSE;
823 crc = UpdateCRC(crc, buf + 4, 4, IconBase); /* chunksize is excluded from CRC */
825 /* Write Frameless */
826 if (!WriteIconAttr(file, ATTR_FRAMELESS, NATIVEICON(dobj)->ni_Frameless, &chunksize, &crc, IconBase))
828 return FALSE;
831 /* Write Stack Size */
833 if (!WriteIconAttr(file, ATTR_STACKSIZE, dobj->do_StackSize, &chunksize, &crc, IconBase))
835 return FALSE;
838 /* Write Icon X Position */
839 if (dobj->do_CurrentX != NO_ICON_POSITION)
841 if (!WriteIconAttr(file, ATTR_ICONX, dobj->do_CurrentX, &chunksize, &crc, IconBase))
843 return FALSE;
847 /* Write Icon Y Position */
848 if (dobj->do_CurrentY != NO_ICON_POSITION)
850 if (!WriteIconAttr(file, ATTR_ICONY, dobj->do_CurrentY, &chunksize, &crc, IconBase))
852 return FALSE;
856 if (dobj->do_DrawerData)
858 if (!WriteIconAttr(file, ATTR_DRAWERX, dobj->do_DrawerData->dd_NewWindow.LeftEdge,
859 &chunksize, &crc, IconBase))
861 return FALSE;
864 if (!WriteIconAttr(file, ATTR_DRAWERY, dobj->do_DrawerData->dd_NewWindow.TopEdge,
865 &chunksize, &crc, IconBase))
867 return FALSE;
870 if (!WriteIconAttr(file, ATTR_DRAWERWIDTH, dobj->do_DrawerData->dd_NewWindow.Width,
871 &chunksize, &crc, IconBase))
873 return FALSE;
876 if (!WriteIconAttr(file, ATTR_DRAWERHEIGHT, dobj->do_DrawerData->dd_NewWindow.Height,
877 &chunksize, &crc, IconBase))
879 return FALSE;
882 if (!WriteIconAttr(file, ATTR_DRAWERFLAGS, dd_to_flags(dobj),
883 &chunksize, &crc, IconBase))
885 return FALSE;
888 } /* if (dobj->do_DrawerData) */
890 if (dobj->do_DefaultTool)
892 if (!WriteIconStrAttr(file, ATTR_DEFAULTTOOL, dobj->do_DefaultTool,
893 &chunksize, &crc, IconBase))
895 return FALSE;
900 if (dobj->do_ToolTypes)
902 STRPTR *tt = (STRPTR *)dobj->do_ToolTypes;
904 for(tt = (STRPTR *)dobj->do_ToolTypes; *tt; tt++)
906 if (!WriteIconStrAttr(file, ATTR_TOOLTYPE, *tt, &chunksize,
907 &crc, IconBase))
909 return FALSE;
914 /* Write CRC */
916 crc ^= 0xFFFFFFFF;
917 buf[0] = crc >> 24;
918 buf[1] = crc >> 16;
919 buf[2] = crc >> 8;
920 buf[3] = crc;
921 if (Write(file, buf, 4) != 4) return FALSE;
923 /* Trim any garbage at end of file */
924 if (SetFileSize(file, 0, OFFSET_CURRENT) < 0) return FALSE;
926 /* Write chunk's size */
927 if (Seek(file, sizeseek, OFFSET_BEGINNING) < 0) return FALSE;
929 buf[0] = chunksize >> 24;
930 buf[1] = chunksize >> 16;
931 buf[2] = chunksize >> 8;
932 buf[3] = chunksize;
933 if (Write(file, buf, 4) != 4) return FALSE;
935 if (Seek(file, 0, OFFSET_END) < 0) return FALSE;
937 return TRUE;
940 /****************************************************************************************/
942 BOOL WriteIconPNG(BPTR file, struct DiskObject *dobj, struct IconBase *IconBase)
944 struct NativeIcon *nativeicon = NATIVEICON(dobj);
945 UBYTE *mempos = nativeicon->ni_Extra.Data + nativeicon->ni_Extra.PNG[0].Offset;
946 BOOL done = FALSE;
948 D(bug("%s: ni=%p, ni->ni_Extra.Data = %p\n", __func__, nativeicon, nativeicon->ni_Extra.Data));
949 if (nativeicon->ni_Extra.Data == NULL)
950 return FALSE;
952 ObtainSemaphore(&IconBase->iconlistlock);
953 if (!IconBase->ib_CRCTable)
954 MakeCRCTable(IconBase);
955 ReleaseSemaphore(&IconBase->iconlistlock);
956 if (!IconBase->ib_CRCTable)
957 return FALSE;
959 /* Write PNG header */
960 if (Write(file, mempos, 8) != 8) return FALSE;
962 mempos += 8;
964 while(!done)
966 ULONG chunksize = (mempos[0] << 24) | (mempos[1] << 16) |
967 (mempos[2] << 8) | mempos[3];
968 ULONG chunktype = (mempos[4] << 24) | (mempos[5] << 16) |
969 (mempos[6] << 8) | mempos[7];
971 chunksize += 12;
973 if (chunktype == MAKE_ID('I', 'E', 'N', 'D'))
975 if (!WriteIconChunk(file, dobj, IconBase)) return FALSE;
976 done = TRUE;
979 if (chunktype != MAKE_ID('i', 'c', 'O', 'n'))
981 if (Write(file, mempos, chunksize) != chunksize)
983 return FALSE;
987 mempos += chunksize;
991 if (nativeicon->ni_Extra.PNG[1].Offset > 0)
993 ULONG size = nativeicon->ni_Extra.PNG[1].Size;
995 /* 2nd PNG Image attached */
997 if (Write(file, nativeicon->ni_Extra.Data + nativeicon->ni_Extra.PNG[1].Offset, size) != size) return FALSE;
1000 return TRUE;
1003 /****************************************************************************************/
1005 VOID FreeIconPNG(struct DiskObject *dobj, struct IconBase *IconBase)
1009 /****************************************************************************************/