Aros/Developer/Docs/Libraries/Icon

Navbar for the Aros wikibook
Aros User
Aros User Docs
Aros User FAQs
Aros User Applications
Aros User DOS Shell
Aros/User/AmigaLegacy
Aros Dev Docs
Aros Developer Docs
Porting Software from AmigaOS/SDL
For Zune Beginners
Zune .MUI Classes
For SDL Beginners
Aros Developer BuildSystem
Specific platforms
Aros x86 Complete System HCL
Aros x86 Audio/Video Support
Aros x86 Network Support
Aros Intel AMD x86 Installing
Aros Storage Support IDE SATA etc
Aros Poseidon USB Support
x86-64 Support
Motorola 68k Amiga Support
Linux and FreeBSD Support
Windows Mingw and MacOSX Support
Android Support
Arm Raspberry Pi Support
PPC Power Architecture
misc
Aros Public License

Introduction

edit
  • OLD - OS1.x (4 col) - OS 2/3 (4 col)
  • NEW - NewIcons (size 36x40 x 32 col) - GlowIcons (size 46x46 x 256 col) - PowerIcons (24bit)
  • AROS - 24bit png dual

Possibilities for the future

  • SVG or SVGZ - Haiku HVIF has a reduced format.

This format is used by Amiga computers to display icons for each program for project you want to access from the graphical user interface Workbench.

On AROS icons with different sizes result in misalignment and clutter among icons, already square icons at the same size as Round icons, will look large. Also, folders that have edges or protrusions such as handles will appear smaller, this is why I used different sizes for Icon Sets. Best to be aware of misalignment issues with icons. Most icons are 46x46. Folder image area is 42x42 but regular icon image area just like other AROS Glow Icons is 38x38

Originally, there were 3 different formats.

1) The OS1.x/OS2.x icons.
2) The NewIcon icon extension.
3) The OS3.5 icon extension.

A note about the used data descriptors. All elements are in Motorola byte order (highest byte first):

APTR  - a memory pointer (usually this gets a boolean meaning on disk)
BYTE  - a single byte                   -128..127
UBYTE - an unsigned byte                   0..255
WORD  - a signed 16 bit value         -32768..32767
UWORD - an unsigned 16 bit value           0..65535
LONG  - a signed 32 bit value    -2147483648..2147483647
ULONG - a unsigned 32 bit value            0..4294967295

There are lots of elements marked with ???. These are usually filled with values, which have no effect at all. Thus they can normally be ignored. For some values the usual contents is described.


OS1.x/OS2.x format

edit

The OS1.x/OS2.x format is mainly an storage of the in-memory structures on disk. This text tries to show which values are important and which are not.

0x00 UWORD ic_Magic          always 0xE310
0x00 UWORD ic_Version        always 1
0x04 struct Gadget           (described below)
0x30 UBYTE ic_Type
     1 DISK                  a disk
     2 DRAWER                a directory
     3 TOOL                  a program
     4 PROJECT               a project file with defined program to start
     5 GARBAGE               the trashcan
     6 DEVICE                should never appear
     7 KICK                  a kickstart disk
     8 APPICON               should never appear
0x31 UBYTE ic_Pad            <undefined>
0x32 APTR  ic_DefaultTool    <boolean>
0x36 APTR  ic_ToolTypes      <boolean>
0x3A LONG  ic_CurrentX       X position of icon in drawer/on WorkBench
0x3E LONG  ic_CurrentY       Y position of icon in drawer/on WorkBench
0x42 APTR  ic_DrawerData     <boolean>
0x46 APTR  ic_ToolWindow     <boolean>
0x4A LONG  ic_StackSize      the stack size for program execution
                             (values < 4096 mean 4096 is used)

This is followed by certain other data structures:

struct DrawerData            if ic_DrawerData is not zero (see below)
struct Image                 first image
struct Image                 second image if ga_SelectRender not zero
                             (see below) in gadget structure
DefaultTool text             if ic_DefaultTool not zero (format see below)
ToolTypes texts              if ic_ToolTypes not zero (format see below)
ToolWindow text              if ic_ToolWindow not zero (format see below)
                             this is an extension, which was never implemented
struct DrawerData2           if ic_DrawerData is not zero and ga_UserData
                             is 1 (see below)

Now a description of the sub-formats:

a) The text storage method (DefaultTool, ToolWindow and ToolTypes):

0x00 ULONG tx_Size           the size of tx_Text including zero byte (tx_Zero)
0x04 ...   tx_Text           the plain text
.... UBYTE tx_Zero           the finishing zero byte

This means the text "Hallo" will be encoded as \00\00\00\06Hallo\00.

As ToolTypes are an array of texts the encoding is preceded by another ULONG value containing the number of entries. But to make parsing more interesting it is not the number as one would expect, but the number of entries increased by one and multiplied by 4. Thus 10 entries will have 44 as count.

b) The Gadget structure:

0x00 APTR  ga_Next           <undefined> always 0
0x04 WORD  ga_LeftEdge       unused ???
0x06 WORD  ga_TopEdge        unused ???
0x08 WORD  ga_Width          the width of the gadget
0x0A WORD  ga_Height         the height of the gadget
0x0C UWORD ga_Flags          gadget flags
     bit 2                   always set (image 1 is an image ;-)
     bit 1                   if set, we use 2 image-mode
     bit 0                   if set we use backfill mode, else complement mode
                             complement mode: gadget colors are inverted
                             backfill mode: like complement, but region
                             outside (color 0) of image is not inverted
     As you see, it makes no sense having bit 0 and 1 set.
0x0E UWORD ga_Activation     <undefined>
0x10 UWORD ga_GadgetType     <undefined>
0x12 APTR  ga_GadgetRender   <boolean> unused??? always true
0x16 APTR  ga_SelectRender   <boolean> (true if second image present)
0x1A APTR  ga_GadgetText     <undefined> always 0 ???
0x1E LONG  ga_MutualExclude  <undefined>
0x22 APTR  ga_SpecialInfo    <undefined>
0x26 UWORD ga_GadgetID       <undefined>
0x28 APTR  ga_UserData       lower 8 bits:  0 for old, 1 for icons >= OS2.x
			     upper 24 bits: undefined

c) The DrawerData structure: This structure is useful for drawers and disks (but there are some icons of other types, which still have these obsolete entries).

0x00 struct NewWindow        (see below)
0x30 LONG  dd_CurrentX       the current X position of the drawer window
                             contents (this is the relative offset of the
                             drawer drawmap)
0x34 LONG  dd_CurrentY       the current Y position of the drawer window contents

d) The NewWindow structure used by DrawerData:

0x00 WORD  nw_LeftEdge       left edge distance of window
0x02 WORD  nw_TopEdge        top edge distance of window
0x04 WORD  nw_Width          the width of the window (outer width)
0x06 WORD  nw_Height         the height of the window (outer height)
0x08 UBYTE nw_DetailPen      always 255 ???
0x09 UBYTE nw_BlockPen       always 255 ???
0x0A ULONG nw_IDCMPFlags     <undefined>
0x0E ULONG nw_Flags          <undefined>
0x12 APTR  nw_FirstGadget    <undefined>
0x16 APTR  nw_CheckMark      <undefined>
0x1A APTR  nw_Title          <undefined>
0x1E APTR  nw_Screen         <undefined>
0x22 APTR  nw_BitMap         <undefined>
0x26 WORD  nw_MinWidth       <undefined> often 94, minimum window width
0x28 WORD  nw_MinHeight      <undefined> often 65, minimum window height
0x2A UWORD nw_MaxWidth       <undefined> often 0xFFFF, maximum window width
0x2C UWORD nw_MaxHeight      <undefined> often 0xFFFF, maximum window width
0x2E UWORD nw_Type           <undefined>

e) The DrawerData2 structure for OS2.x drawers:

0x00 ULONG dd_Flags          flags for drawer display
     value 0                 handle viewmode like parent drawer current
                             setting (OS1.x compatibility mode)
     bit 0                   view icons
     bit 1                   view all files (bit 0 maybe set or unset
                             with this)
0x04 UWORD dd_ViewModes      viewmodes of drawer display
     value 0                 show icons (OS1.x compatibility mode)
     value 1                 show icons
     value 2                 show sorted by name
     value 3                 show sorted by date
     value 4                 show sorted by size
     value 5                 show sorted by type

f) And now the last element, the Image structure:

0x00 WORD  im_LeftEdge       always 0 ???
0x00 WORD  im_TopEdge        always 0 ???
0x04 WORD  im_Width          the width of the image
0x06 WORD  im_Height         the height of the image
0x08 WORD  im_Depth          the image bitmap depth
0x0A APTR  im_ImageData      <boolean> always true ???
0x0E UBYTE im_PlanePick      foreground color register index
0x0F UBYTE im_PlaneOnOff     background color register index
0x10 APTR  im_Next           always 0 ???

This is followed by the image data in planar mode. The width of the image is always rounded to next 16bit boundary.


NewIcon extension

edit

As the original icon format is very limited when using more than the 4 or 8 default colors and also when using different palette sets than the default, there have been ideas how to circumvent this. A Shareware author invented NewIcons format, which uses the ToolTypes to store image data, as expanding the original format very surely would haven broken compatibility.

The NewIcons stuff usually starts with following 2 ToolTypes text (text inside of the "" only):

"*** DON'T EDIT THE FOLLOWING LINES!! ***"

Afterwards the image data is encoded as ASCII. The lines for first image always start with "IM1=". If present the second image starts with "IM2=".

The first line of each image set contains the image information and the palette.

0x00 UBYTE ni_Transparency
     "B"                     transparency on
     "C"                     transparency off
0x01 UBYTE ni_Width          image width + 0x21  - "}" means width 92
0x02 UBYTE ni_Height         image height + 0x21 - "}" means height 92
0x03 UWORD ni_Colors         ASCII coded number of palette entries:
     entries are: ((buf[3]-0x21)<<6)+(buf[4]-0x21)
     "!'" means 6 entries

Afterwards the encoded palette is stored. Each element has 8 bit and colors are stored in order red, green, blue. The encoded format is described below. The ni_Width and ni_Height maximum values are 93. The maximum color value is theoretically 255. I have seen images with at least 257 stored colors (but less than 256 used).

The following lines contain the image data encoded with the same system as the palette. The number of bits used to encode an entry depends of the number of colors (6 colors f.e. need 3 bit). The lines have maximum 127 bytes including the "IM1=" or "IM2=" header. Thus including the zero byte, the string will be 128 byte.

En/Decoding algorithm:

Each byte encodes 7bit (except the RLE bytes)
Bytes 0x20 to 0x6F represent 7bit value 0x00 to 0x4F
Bytes 0xA1 to 0xD0 represent 7bit value 0x50 to 0x7F
Bytes 0xD1 to 0xFF are RLE bytes:
  0xD1 represents  1*7 zero bits,
  0xD2 represents  2*7 zero bits and the last value
  0xFF represents 47*7 zero bits.

Opposite to the original icon format, the NewIcons format uses chunky modus to store the image data.

The encoding for images and palette stops at the string boundary (127 bytes) with buffer flush (and adding pad bits) and is restarted with next line.


OS3.5 extension

edit

The original inventor of NewIcon format was Phil Vedovatti. And the one responsible for designing the Glow Icons used with Amiga OS 3.5/3.9 was Mat Chaput.

The OS3.5 format introduces nearly the same information as in NewIcons, but in a more usable format. The tooltypes are no longer misused, but a new data block is appended at the end of the icon file. This data block is in IFF format.

Those files consist of a classic info disk structure (might or might not contain a newicon structure in the tool-types), followed by an IFF icon structure (the actual glowicon bits).

A GlowIcon is thus an IFF structure with a ICON identifier which can contain the (newly added) chunks FACE and IMAG. The file may or may not contain multiple IMAG chunks (though a minimal of 1 and maximum of 2 makes sense in this context).

It consists of the standard header

0x00 UBYTE[4] ic_Header      set to "FORM"
0x04 ULONG    ic_Size        size [excluding the first 8 bytes!]
0x08 UBYTE[4] ic_Identifier  set to "ICON"

Now Chunks of different data follow. Each chunk consists of 8 header bytes and the data bytes. If the size in header is uneven, then it is automatically padded with 1 byte at the end.

Currently 3 chunks are used with following data. Note that IFF generally allows expansion and chunk reordering, so do not rely on any current size information or chunk order, but skip unknown data based on the size information stored in file.

1)

0x00 UBYTE[4] fc_Header      set to "FACE"
0x04 ULONG    fc_Size        size [excluding the first 8 bytes!]
0x08 UBYTE    fc_Width       icon width subtracted by 1
0x09 UBYTE    fc_Height      icon height subtracted by 1
0x0A UBYTE    fc_Flags       flags
     bit 0                   icon is frameless
0x0B UBYTE    fc_Aspect      image aspect ratio:
     upper 4 bits            x aspect
     lower 4 bits            y aspect
0x0C UWORD    fc_MaxPalBytes maximum number of bytes used in image palettes
                             subtracted by 1 (i.e. if palette 1 has 17 and
                             palette 2 has 45 entries, then this is 45)

2) Now 2 chunks of this type may come, where first chunk is image 1 and second chunk is image 2.

 
0x00 UBYTE[4] im_Header      set to "IMAG"
0x04 ULONG    im_Size        size [excluding the first 8 bytes!]
0x08 UBYTE    im_Transparent number of the transparent color
0x09 UBYTE    im_NumColors   number of colors subtracted by 1
0x0A UBYTE    im_Flags
     bit 0                   there exists a transparent color
     bit 1                   a palette data is attached (NOTE, that first
                             image always needs palette data, whereas the
                             second one can reuse the first palette.)
0x0B UBYTE    im_ImageFormat storage format of image data
     value 0                 uncompressed
     value 1                 run-length compressed
0x0C UBYTE    im_PalFormat   storage format of palette data (same as above)
0x0D UBYTE    im_Depth       the number of bits used to store a pixel
0x0E UWORD    im_ImageSize   number of bytes used to store image (subtracted
                             by 1)
0x10 UWORD    im_PalSize     number of bytes used to store palette
                             (subtracted by 1)
0x12 UBYTE[...]              the image data
.... UBYTE[...]              the palette data (if existing)

Now about the run-length compression. This is equal to the run-length method in IFF-ILBM format: The input data is seen as a bit-stream, where each entry has im_Depth bits for image or 8 bits for palette. First comes an 8 bit RLE block with following meaning:

 
0x00 .. 0x7F copy the next n entries as they are, where n is "RLE-value"+1
0x80         ignore this, do nothing
0x81 .. 0xFF produce the next entry n times, where n is 256-"RLE-value"+1
             (if using signed chars n is "RLE-value"+1)

In uncompressed mode, each byte represents one pixel (even if lower depth is used).

When saving Classic Icons we are only concerned with the IFF icon images. The IFF Data starts with "FORM....ICONFACE". Save the ILBM file as the actual number of bitplanes & index values & colormap from the icon data. Once you extract the images & colormap it's easy to write the ILBM. To make it easier ILBM can be uncompressed planar images & colormap. There is information for ILBM format if you search for IFF85.

Sometimes Classic Amiga Icons contain OS3.5 IFF Data & ARGB data chunks attached to the end of the file. See Icon Library for methods to read the zlib compressed 32bit data.

The IFF data should contain two IMAG chunks for images but it could contain one or none. If it contains only one image we only export one image. If it contain no IMAG chunks for images but it contains one or two ARGB chunks attached to the end of the IFF data then it's an OS4 icon which is a Classic Amiga Icons with the OS3.5 Extension without IMAG but ARGB instead. If it contains one or two IMAG & one or two ARGB chunks then it is an AROS ARGB Icon format.

To decode the image data for IMAG chunks for Glow Icon Format. The image data decoder and RLE decoder are working

Having traced the CybergraphX ReadRGBPixel function. It uses DoPixelFunct which then reverts to do_pixel_funct which is part of Rom/Graphics. ReadPixel only uses RGB values.

If a sample pixel that is (255,46,58,78). It's an ARGB 32 bit pixel. Yet ReadRGBPixel returns 3029582 which is 2E3A4E or in decimal it is 46,58,78. So the alpha is missing. It's only RGB. That makes sense because it uses the same function as ReadPixel.

Something strange happens when reading alpha pixels (less than 255). The color (12,0,0,0) has an alpha of 12 but ReadRGBPixel returns (146,146,146). So it seems that ReadRGBPixel uses Premultiplied Alpha with the background color (153 in this case). Part of the mystery is solved. Now can supply a sample value for WriteRGBPixel then go from there.

After evaluating several alpha pixels in the original image and comparing the resulting values from ReadRGBPixel I've worked out the Alpha Blending Formula.

If the background color is (153,153,153) and the ARGB pixel is (13,0,0,0) this is the formula:

//Alpha Blending
//alpha=13
//factor= 1-[(roundup(alpha/3))/100] =
(1 - 0.05) = 0.95
//value = (int)153*(factor) = (145,145,145).

This is the DrawLargeImage function so far. In the screenshot "pixel buffer" is the byte buffer containing the pixel data from the original image which is the small image. Each ARGB pixel in the original image gets mapped to a region of pixels which are 2x2 in this case since pixelateSize=2.


PowerIcons PNG

edit

Workbench (Wanderer) does not read anything directly itself - it relies on icon.library for "file" processing. The loading of PNG Icons does not happen using datatype *system*. It's done through libpng functions. To avoid that both icon.library and png.datatype have libpng statically linked in (double file/mem usage), it's done only for one of them: png.datatype. The png.datatype exposes some extra functions PNG_#?. See workbench/classes/datatypes/png/png.conf and directaccess.c in same directory.

In workbench/libs/icon/diskobjPNGio.c you can see how the PNG_ functions are used to read the PNG icon. In there you'll also see a function MakePlanarImage(). It's one function which will certainly slow down things a bit. What is does (in very unoptimized way) is to create a very simple realtime remapped planar version of the PNG image(s) to be used on low color (LUT) screens.

In libpng 1.5, png_ptr and info_ptr are opaque data types, and can't be dereferenced.

Replace that code with the following (which works in both libpng 1.2 and 1.5)

...
   Write(png_get_io_ptr(png_ptr), data, length);
...

The reason is that in a (near!) future version of libpng, the details of the png_ptr and info_ptr data structures may change dramatically.

Changes are trivial, just grep for the old field name (ie 'io_ptr') in png.h, and use the appropriate accessor function. 

merge icon35 and png icons

  • png data would live in the IFF stream of the icon35 format (IFF type 'PNG ')
  • 4 color and icon35 image formats would be precomputed by the ilbmtoicon tool
  • AOS should be able to read and understand this format

The easiest way to split PNG icons & retain the icOn chunk is to find the first 'IEND' & second 'IEND' if there is one then calculate filesize1 & filesize2 then read & write binary. You could use another method to get the images but the icOn chunk may be lost unless you locate it just before 'IEND' then save it to .bin file or store it some other way to later write to file. As far as classic Icons you can just read them sequentially. For AROS we can just use IconControl functions but for Windows or an OS other than AROS you need another method to read the icon data.

Do OS4 and MorphOS use the same type of PNG icons as us, or a different variation? They use the same format (which PowerIcons originated), which is a plain PNG file named "*.info" with some extra PNG hunks in it to hold some icon data. (PNG is like IFF in that way).

Extending the Icon 3.5 to include PNG data, so that (a) our generated ICONs can work on any Amiga system, including OS 1.x to 3.x, and (b) my poor 68000 can choose a planar image from the icon file instead of spending approx 7 seconds per icon converting from ARGB to 4-color planar.

Existing PNG support will *not* be changed - so we should continue to be able to enjoy AmigaOS4 and Morphos icons sets on the faster processors.

png images with special ic0n chunk embedded inside png. can be 1 or 2 png images.

ic0n chunk stores the 'old' data required to fill f.e. a drawerdata structure.

it is a taglist that can contain zero or more tags from the following list:

ATTR_DRAWERX,
ATTR_DRAWERY,
ATTR_DRAWERWIDTH,
ATTR_DRAWERHEIGHT,
ATTR_DRAWERFLAGS,
ATTR_DRAWERFLAGS2,
ATTR_DRAWERFLAGS3,
ATTR_VIEWMODES,
ATTR_VIEWMODES2,
ATTR_DD_CURRENTX,
ATTR_DD_CURRENTY :
ATTR_ICONX,
ATTR_ICONY,
ATTR_STACKSIZE,
ATTR_TYPE,
ATTR_FRAMELESS:
ATTR_DEFAULTTOOL,
ATTR_TOOLTYPE:

Of course, each tag followed by its respective value.

void List_Icontype(char *name)
{    
    LONG length = 0;
    struct DiskObject *icon = NULL;
    Printf("Reading icOn chunk values...\n");    
    Printf("Icon Filename: %s\n", name);

    char *iconfile = RemoveFileExtension(name);
    icon = GetDiskObjectNew(iconfile);
    if (icon != NULL)
    {        
        if (icon->do_Type)
        {
           LONG type = icon->do_Type;
           Printf("Icontype: %ld\n", type); 
        }
    }
    FreeDiskObject(icon);        
}

LONG List_Icon_Chunk_Deftool(char *name)
{    
    LONG length = 0;
    struct DiskObject *icon = NULL;
    Printf("Reading icOn chunk values...\n");    
    Printf("Icon Filename: %s\n", name);

    char *iconfile = RemoveFileExtension(name);
    icon = GetDiskObjectNew(iconfile);
    if (icon != NULL)
    {                
        if (icon->do_DefaultTool) 
        {
            Printf("Deftool: %s\n", icon->do_DefaultTool);
            length = strlen(icon->do_DefaultTool) + 1;
        }
    }
    FreeDiskObject(icon);

    return length;    
}

LONG List_Icon_Chunk_Tooltype(char *name)
{
    LONG length = 0;
    struct DiskObject *icon = NULL;
    Printf("Reading icOn chunk values...\n");    
    Printf("Icon Filename: %s\n", name);

    char *iconfile = RemoveFileExtension(name);
    icon = GetDiskObjectNew(iconfile);
    if (icon != NULL)
    {        
        if (icon->do_ToolTypes)
        {
            int i = 0;
            char *tt = NULL;
            while ((tt = icon->do_ToolTypes[i]) != NULL)
            {
                Printf("Tooltype: %s\n", tt);
                length += strlen(icon->do_ToolTypes[i]) + 1;
                i++;
            }
        }
    }
    FreeDiskObject(icon);

    return length;
}

void List_Icon_Chunk_Tags(char *name, BPTR file, int curPos, LONG pSize)
{    
    ULONG attr;
	IPTR val = 0;     
    UBYTE *chunkdata;
	UBYTE Buffer32[4];           

    LONG len = 0;
    LONG chunksize = pSize;
    LONG pOffset = (LONG)curPos;

    Printf("Reading icOn chunk tags...\n");
    Printf("icOn chunk Size: %ld\n", pSize);
    Printf("icOn chunk Offset: %ld\n", pOffset);

    //#define ATTR_ICONX   	    0x80001001
    //#define ATTR_ICONY   	    0x80001002
    //#define ATTR_DRAWERX 	    0x80001003
    //#define ATTR_DRAWERY 	    0x80001004
    //#define ATTR_DRAWERWIDTH    0x80001005
    //#define ATTR_DRAWERHEIGHT   0x80001006
    //#define ATTR_DRAWERFLAGS    0x80001007
    //#define ATTR_TOOLWINDOW     0x80001008  //OS4: STRPTR, tool window string, length including the tag, multiple of 8
    //#define ATTR_STACKSIZE	    0x80001009
    //#define ATTR_DEFAULTTOOL    0x8000100a
    //#define ATTR_TOOLTYPE	    0x8000100b
    //#define ATTR_VIEWMODES      0x8000100c  //OS4 PNG use that
    //#define ATTR_DD_CURRENTX    0x8000100d  //OS4 ULONG, drawer view X offset
    //#define ATTR_DD_CURRENTY    0x8000100e  //OS4 ULONG, drawer view Y offset
    //#define ATTR_TYPE           0x8000100f  //OS4 icon type (WBDISK...WBKICK)
    //#define ATTR_FRAMELESS      0x80001010  //OS4 ULONG, frameless property
    //#define ATTR_DRAWERFLAGS3   0x80001011  //OS4 ULONG, drawer flags
    //#define ATTR_VIEWMODES2     0x80001012  //OS4 ULONG, drawer view modes
    //#define ATTR_DRAWERFLAGS2   0x80001107  //written from AFA to store needed dopus Magellan settings       

    while(pSize >= 4) //(pOffset < chunksize)
    {   
        /* Read icOn chunk attribute tag */
        Seek(file,pOffset,OFFSET_BEGINNING);
		Read(file,Buffer32, 4); //length = 4;        
        attr = (Buffer32[0] << 24) | (Buffer32[1] << 16) | (Buffer32[2] << 8) | Buffer32[3];                

        pOffset += 4; //offset + 4
        pSize -=4; //size - 4

        /* Read icOn chunk value tag */
        Seek(file,pOffset,OFFSET_BEGINNING);
		Read(file,Buffer32, 4); //length = 4;        
        val = (Buffer32[0] << 24) | (Buffer32[1] << 16) | (Buffer32[2] << 8) | Buffer32[3];

        pOffset += 4; //offset + 4
        pSize -=4; //size - 4

        /* Compare icOn chunk attribute tags */
        if(attr == 0x80001001) Printf("IconX: %ld\n", val);
        if(attr == 0x80001002) Printf("IconY: %ld\n", val); 
        if(attr == 0x80001003) Printf("DrawerX: %ld\n", val); 
        if(attr == 0x80001004) Printf("DrawerY: %ld\n", val);
        if(attr == 0x80001005) Printf("Drawerwidth: %ld\n", val); 
        if(attr == 0x80001006) Printf("Drawerheight: %ld\n", val);
        if(attr == 0x80001007) Printf("Drawerflag: %ld\n", val);
        if(attr == 0x80001008) Printf("Toolwin: %ld\n", val);      
        if(attr == 0x80001009) Printf("Stacksize: %ld\n", val);
        if(attr == 0x80001010) Printf("Frameless: %ld\n", val);
        if(attr == 0x8000100f) Printf("Icontype: %ld\n", val);
        //if(attr == 0x8000100a) Printf("Deftool found.\n");
        //if(attr == 0x8000100b) Printf("Tooltype found.\n");

        if(attr == 0x8000100a)
        { 
            Printf("Deftool found.\n");
            len = List_Icon_Chunk_Deftool(name);
            pOffset += len;
        }

        if(attr == 0x8000100b)
        {
            Printf("Tooltype found.\n");
            len = List_Icon_Chunk_Tooltype(name);            
            pOffset += len;
        }
    } /* while(chunksize >= 4) */    
}


Handling

edit

Handling of icons by an AppWindow/Menu/Icon. That's how the concept of graphically dealing with files (represented as icon objects) from an already running application was implemented from Kickstart 2.04 on. So selecting icons isn't enough for any application to be aware of it: the user has to do one more action (which is to drag the selected icon(s) towards an AppWindow/Icon or to select an AppMenu).

Wanderer only allows to use AppWindows yet. So promote your window as an AppWindow, then listen to the AppMessage and act accordingly.

If you want to act on more than one icon at a time, you will need to adapt the code to browse AppMessage->am_ArgList as many times as AppMessage->am_NumArgs ...

Our "DefaultIcon" implementation was better (and more like the original) - it would be easy to add default Icons that use pattern matching rather than the less efficient datatype matching.

If the icon is associated with a directory (WBDISK, WBDRAWER, WBGARBAGE), it needs a DrawerData structure to go with it. This structure contains an Intuition NewWindow structure [...] Workbench uses it to hold the current window position and size of the window so it will reopen in the same place.

for a directory, the icon is stored in a .info file at the same level where the directory name appears (not in the directory itself). The icon type should be set to DRAWER. The icon for a disk should always be stored in a file named disk.info at the root level directory of the disk. The icon type should be set to DISK. (The icon type can be set and the icon imagery edited with the IconEdit program.)

So it is clear that an Amiga disk named "foo" contains a file named "disk.info" at the root: here is the imagery of the icon of the disk (seen on the main Workbench window and associated with the name "foo"), and here is also the coordinates of the window to be opened when the user double-clicks on it. If the disk contains a drawer named "bar" with an icon, you can use "C:List foo:" to be able to read the content which should at least include "bar" (which is the drawer itself) and "bar.info" (which contains the drawer icon imagery (seen in the foo window on workbench screen) _and_ the coordinates of the window to be opened when the user double-clicks on this bar icon). Of course it is possible to have disks without icons, and drawers without icons: in such cases, Workbench can provide default ones (and always do for disks).

AFAIK Amiga icons are handled like that:

Open them doing something like

struct DiskObject *icon = GetIconTags(PUT_YOUR_TAGS_HERE);

and then you can for example read the coordinates of the icon by

printf("Icon X coord. in drawer/on WorkBench: %ldn",icon->do_CurrentX); 
printf("Icon Y coord. in drawer/on WorkBench: %ldn",icon->do_CurrentY);

and if it's the icon of a drawer or of a disk (then the info file contains a DrawerData structure), you can read the coordinates of the window to open when double-clicking on the icon:

printf("Left Edge position of drawer's window: %dn",icon->do_DrawerData->dd_NewWindow.LeftEdge); 
printf("Top Edge position of drawer's window:  %dn",icon->do_DrawerData->dd_NewWindow.TopEdge); 
printf("Drawer's window Width:                 %dn",icon->do_DrawerData->dd_NewWindow.Width); 
printf("Drawer's window Height:                %dn",icon->do_DrawerData->dd_NewWindow.Height);

If it's a drawer (or disk) icon designed for OS2+, it contains Flags and ViewModes in DrawerData structure that store the way icons are shown in the drawer's window: you can read it by something like:

switch(icon->do_DrawerData->dd_Flags) 
{ 
    case 0: 
        printf("Default"); 
        break; 
    case 1: 
        printf("Show only icons"); 
        break; 
    case 2: 
        printf("Show all files"); 
        break; 
    case 3: 
        printf("Show all files"); 
        break; 
    default: 
        printf("Only values between 0 an 3 should be found here"); 
} 
switch(icon->do_DrawerData->dd_ViewModes) 
{ 
    case 0: 
        printf("Default (inherit from parent)"); 
        break; 
    case 1: 
        printf("View as icons"); 
        break; 
    case 2: 
        printf("View as text, sorted by name"); 
        break; 
    case 3: 
        printf("View as text, sorted by date"); 
        break; 
    case 4: 
        printf("View as text, sorted by size"); 
        break; 
    case 5: 
        printf("View as text, sorted by type"); 
        break; 
    default: 
        printf("Only values between 0 an 5 should be found here"); 
}

The default icons to specify possible operations for an Icon (thereby filetype) via the default icons tooltypes. The normal Icon behaviour would still be used for its default action but it could also expose specific actions for that file type, e.g.

ICON_ACTION="Preview","SYS:Utiltieis/MultiView"
ICON_ACTION="Edit","Extras:Gfx/LunaPaint"


Tooltype

edit

from http://utilitybase.com/forum/index.php?action=vthread&forum=2&topic=1252

Be very careful with modifying the tooltypeslist in an icon.

  1. Read in an icon (Icon->GetdiskObject())
  2. Build a new tooltypeslist
  3. Copy the address of the current tooltypelist to a safe place
  4. Copy the address of the NEW tooltypeslist to the icon
  5. Rewrite the icon (Icon->PutDiskObject())
  1. Copy the address of the old tooltypeslist from the safe place BACK into the icon
  2. Free the diskobject (Icon->FreeDiskObject())

6 and 7 are not actually necessary. icon.library keeps track of all the data associated with a loaded icon through a mechanism attached to the 'struct DiskObject' itself, in the private undocumented part of the structure. It does not follow the pointers or assume that they point somewhere meaningful.

In essence, this means that you can modify every bit of information in the documented portion of the 'struct DiskObject' without ill effects. But you have to be careful that the information is in itself consistent if you want to write it back to disk. While icon.library does perform some sanity checking, especially icon.library V44 and beyond, there is only so much you can do.

Applications generally want to call GetDiskObjectNew() -- rather than GetDiskObject() -- to get disk objects for icons dropped in the window

#include <workbench/workbench.h>
#include <workbench/icon.h>

#include <proto/icon.h>

#include <stdio.h>

int main(int argc, char **argv)
{
    STRPTR newToolTypes[] =
    {
        "AROS=RULES",
        "Tooltypes are actually free-form text",
        "Ain't that neat?",
        NULL
    };
    
    struct DiskObject *icon = GetIconTags
    (
        "writetooltypes", ICONGETA_FailIfUnavailable, FALSE, TAG_DONE
    );
    
    if (icon != NULL)
    {
        STRPTR *oldToolTypes = icon->do_ToolTypes;
        
        icon->do_ToolTypes = newToolTypes;
        if (!PutIconTags("writetooltypes", icon, TAG_DONE))
        {
            printf("ERROR: Failed to write icon.\n");
        }
        icon->do_ToolTypes = oldToolTypes;
        
        FreeDiskObject(icon);
    }
    else
    {
        printf("ERROR: Failed to open icon for file\n");
        return 20;
    }

    return 0;
}


LayoutIcon

edit

Currently, LayoutIcon is unimplemented, and an idea that could save me a lot of RAM for PNG images, when they are rendered on low-color screens. The idea is to use LayoutIcon() to render the icon into the Screen's bitmap layout, and use that as the gadget imagery for the icon, and FreeMem() the PNG or other high-color icon imagery.

This is similar to how AOS does things, but with one trick - I 'remember' what image format (and offset and size in the .icon file) was originally there, and when PutDiskObject() is called I carefully avoid scribbling on the image data, preserving the original image.

But you need update the images, when a user change the screen depth. In AFA layoutIcon is too unimplement, i add some times before a jump in debugger command when function is called to test.if a program use this function.I see that workbench not use this function.also other programs do not use. But a speedup of AROS iconlib and much less memory usage is possible, when you make a cache, so that all default Icons only load once.getdiskobject give then only a pointer to existing default icon.

The problem on AROS is, it load every time the icon in and use new memory. For example if you show 100 jpg files, then 100* the icon def_jpg.info is load.so 100* memory usage and load time usage. As wanderer loads always all icons, even if only icon view is select.

transparent PNG

edit

graphics.lbrary BltMaskBitMapRastPort is useful

static void Change_State(int Reset)
{
    int x;

    for(x=Levels_Struct[CurrentLevel].Beginning; x<IconCounter; x++)
    {
        if(Icons_Struct[x].Icon_OK)
        {
            if(Icons_Struct[x].Icon_Status != 0)
            {
                if(Reset == 0)
                {
                    if((Icons_Struct[x].Icon_Status & ICON_ACTIVE) == 0 && Icons_Struct[x].Icon_Status < 4)
                    {
                        // 11000111b
                        Icons_Struct[x].Icon_Status = (Icons_Struct[x].Icon_Status - 1) & 0xC7;
                    }
                    else
                    {
                        Icons_Struct[x].Icon_Status = (Icons_Struct[x].Icon_Status + 1) & 0xC7;
                    }
                }
                else
                {
                    Icons_Struct[x].Icon_Status = 0;
                }

                Insert_Icon((Icons_Struct[x].Icon_Status & SELECTED_ICON) ? IDS_SELECTED : IDS_NORMAL, x);
            }
        }
    }
}

static void Insert_Icon(int Tryb, int IconNumber)
{
    BltBitMapRastPort(BMP_Buffer,
        Icons_Struct[IconNumber].Icon_PositionX,
        0,
        &RP_DoubleBuffer, //Window_struct->RPort,
        0, //Icons_Struct[IconNumber].Icon_PositionX,
        0,
        Icons_Struct[IconNumber].Icon_Width + 1,
        WindowHeight,
        0xC0);

    DrawIconState(&RP_DoubleBuffer, //Window_struct->RPort,
        Icon[IconNumber],
        NULL,
        0, //Icons_Struct[IconNumber].Icon_PositionX,
        Icons_Struct[IconNumber].Icon_PositionY - MovingTable[(Icons_Struct[IconNumber].Icon_Status & 0x07)],
        Tryb,
        ICONDRAWA_Frameless, TRUE,
        ICONDRAWA_EraseBackground, FALSE,
        TAG_DONE);

    BltBitMapRastPort(BMP_DoubleBuffer,
        0,
        0,
        Window_struct->RPort,
        Icons_Struct[IconNumber].Icon_PositionX,
        0,
        Icons_Struct[IconNumber].Icon_Width + 1,
        WindowHeight,
        0xC0);
}

static void Blink_Icon(int IconNumber)
{
    int x, Tryb=IDS_SELECTED;

    for(x=0; x<8; x++)
    {
        Insert_Icon(Tryb, IconNumber);
        Delay(3);

        if(Tryb == IDS_NORMAL) Tryb = IDS_SELECTED;
        else Tryb = IDS_NORMAL;
    }
}

Datatype Detection

edit

The icon.library uses the datatype descriptors from sys:devs/datatypes to identify the file type. Then a default icon def_NAME.info is used for a file with a type of NAME. The AROS build-system uses the tool createdtdesc to create datatype descriptors from simple text files.

Bugs

edit

After icons can be moved, it will be good to be able to snapshot their position.

And the position of the window in the drawer icon. But beware that IIRC there is a bug/unimplemented feature somewhere (in icon.library?) that prevents it to store properly DrawerData struct (dd_Flags and dd_NewWindow members) in all cases. So Wanderer suffers of the problem too currently, and you can't both save the "View All Files" state _and_ snapshot the window position of a drawer.

  1. having a database in the dir containing mappings is also inefficient when working with individual files - perhaps more so than matching using deficons/datatypes (which generally scan the first bytes of a file only). What happens in a large directory and the file you are querying is deep within the database? slower performance..
  1. modern filesystems can store additional metadata with files - e.g. in NTFS pretty much everything is an attribute of some form or other, it wouldnt take much to make it possible to include querying/setting such attributed as part of most amigaos code's exall/exnext dir scanning loops.

one scenario is some combination of using file system meta data and our default icons.

An application scans a directory of files using the normal AmigaOS routines. we provide a new routine (*) to query a file/locks attributes (which uses packets to speak with the file system handler and query the meta data) which we use to request the data formats attribute. This shouldn't incur any/much IO penalty since the meta data is most likely already cached as part of scanning the dir. if the attribute isn't available we can then use default icons pattern/data matching to identify the file - and optionally then set the attribute if the file system does support meta-data.

(*) perhaps this call could be handled in the deficon code itself anyhow, so that existing amigaos code that uses icon.library, etc, would benefit from it without need for change.

function readIFFICON(file){
		
		var index = file.index;
		var img = {states:[]};
		
		function readChunk(){
			var chunk = {};
			chunk.name = file.readString(4);
			chunk.size = file.readDWord();
			return chunk;
		}

		while (index<file.length-4){
			file.goto(index);
			var chunk = readChunk();
			index += chunk.size + 8;
			if (chunk.size%2 === 1) index++;
			
			switch (chunk.name){
				case "FACE":
					img.width = file.readUbyte() + 1;
					img.height = file.readUbyte() + 1;
					img.flags = file.readUbyte();
					img.aspectRatio = file.readUbyte(); //upper 4 bits:x aspect, lower 4 bits: y aspect
					img.MaxPaletteSize = file.readWord();
                    console.log("Icon is " + img.width + "x" + img.height);
					break;
				case "IMAG":
					var endIndex = file.index + chunk.size;

					var state = {};
					state.transparentIndex = file.readUbyte();
					state.NumColors = file.readUbyte() + 1;
					state.flags = file.readUbyte();
					state.imageCompression = file.readUbyte();
					state.paletteCompression = file.readUbyte();
					state.depth = file.readUbyte();
					state.imageSize = file.readWord() + 1;
					state.paletteSize = file.readWord() + 1;

					state.pixels = [];
					state.palette = [];

					var imageDataOffset = file.index;
					var paletteDataOffset = imageDataOffset + state.imageSize;

                    if (state.imageCompression){
						// note: this is BIT aligned, not byte aligned ...
						// -> RLE control chars are 8 bits, but the data elements are n bits, determined by state.depth

						var max = (state.imageSize-1) * 8;
						var bitIndex = 0;

						while (bitIndex < max) {
							var b = file.readBits(8,bitIndex,imageDataOffset);
                            bitIndex += 8;
							
							if (b > 128) {
								var b2 = file.readBits(state.depth,bitIndex,imageDataOffset);
                                bitIndex += state.depth;
								for (var k = 0; k < 257 - b; k++) state.pixels.push(b2);
							}
							if (b < 128) {
								for (k = 0; k <= b; k++){
									state.pixels.push(file.readBits(state.depth,bitIndex,imageDataOffset));
                                    bitIndex += state.depth;
                                }
							}
						}
					}else{
                        // note: uncompressed data is BYTE aligned, even if state.depth < 8
						for (var i = 0; i < state.imageSize; i++){
							state.pixels.push(file.readUbyte())
						}
					}

					if (state.paletteSize){
                        file.goto(paletteDataOffset);
                        var rgb = [];

                        var bitsPerColorByte = 8;

                        if (state.paletteCompression){
                            var max = (state.paletteSize-1) * 8;
                            var bitIndex = 0;

                            while (bitIndex < max) {
                                var b = file.readBits(8,bitIndex,paletteDataOffset);
                                bitIndex += 8;

                                if (b > 128) {
                                    var b2 = file.readBits(bitsPerColorByte,bitIndex,paletteDataOffset);
                                    bitIndex += bitsPerColorByte;
                                    for (var k = 0; k < 257 - b; k++) rgb.push(b2);
                                }
                                if (b < 128) {
                                    for (k = 0; k <= b; k++){
                                        rgb.push(file.readBits(bitsPerColorByte,bitIndex,paletteDataOffset));
                                        bitIndex += bitsPerColorByte;
                                    }
                                }
                            }
                        }else{
                            for (i = 0; i < state.paletteSize; i++){
                                rgb.push(file.readUbyte())
                            }
                        }

                        if (rgb.length>2){
                        	for (i = 0, max = rgb.length; i<max; i+=3){
                        		state.palette.push([rgb[i],rgb[i+1],rgb[i+2]])
							}
						}
					}
					
					img.states.push(state);


					break;
				case "ARGB":
					// zlib compressed
					// found some info/structure on https://amigaworld.net//modules/newbb/viewtopic.php?viewmode=flat&order=0&topic_id=34625&forum=15&post_id=639101#639062

					console.log("decoding ARGB data");
					
					var state = {};

					state.rgba = true;
					state.pixels = [];
					state.palette = [];
					
					
					for (var offset = 0; offset<10;offset++){
						// no idea what this data structure is ...
						// first DWORD always seem to be 1?
						state.dummy = file.readUbyte();
						//console.log(state.dummy);
					}
					
					var size = chunk.size-offset;
					var data = new Uint8Array(size);
					for (var i = 0; i<size; i++){
						data[i] = file.readUbyte();
					}

					try{
						var a;
						if (typeof Zlib !== "undefined"){
							// running in browser
							a = new Zlib.Inflate(data).decompress();
						}else{
							// running in node
							var zlib = require('zlib');
							a = zlib.inflateSync(data);
						}
						
						for (var y = 0; y<img.height; y++){
							for (var x = 0; x<img.width; x++){
								var pixelIndex = (y*img.width + x) * 4;
								var color = [a[pixelIndex+1]||0,a[pixelIndex+2]||0,a[pixelIndex+3]||0,(a[pixelIndex]||0)/255];
								state.pixels.push(color);
							}
						}
						
						img.states.push(state);
						
						
					}catch (e) {
						console.log("invalid zlib structure");
					}
					
					break;
				default:
					console.log("unhandled IFF chunk: " + chunk.name);
					break;
			}
		}
		
		return img;
	}

/**************************************************************************************************/

static char *DecodeOS35(unsigned char *buffer, LONG numbytes, LONG bits, struct IconImage *im, enum DecodeType type, LONG mode)
{
  int cop = 0, loop = 0, entries, numbits = 0, mask, curentry = 0;
  ULONG bitbuf = 0;
  ULONG byte;

  //DecodeNew(buffer+10, numi, imf ? dep : 8, im, DECODE_IMAGE, imf)
  //DecodeNew(buffer+10+numi, nump, 8, im, DECODE_PALETTE, palf)

  Printf ("DecodeOS35 - mode: %ld\n", mode);
  Printf ("DecodeOS35 - bits: %ld\n", bits);
  Printf ("DecodeOS35 - bytes: %ld\n", numbytes);
  Printf ("DecodeOS35 - colors: %ld\n", im->NumColors);

  Printf ("Icon Image Dimensions: %ld, %ld\n", im->Width, im->Height);

  if(type == DECODE_IMAGE) Printf ("DECODE_IMAGE\n");
  if(type == DECODE_PALETTE) Printf ("DECODE_PALETTE\n");

  //WriteData("Ram Disk:imgdata1.bin", buffer, numbytes);

  if(!mode) /* no RLE */
    cop = numbytes*8/bits; //planar Size
  if(type == DECODE_PALETTE)
    entries = im->NumColors*3;
  else
    entries = im->Width*im->Height;

  mask = (1<<bits)-1;

  /* UnpackByteRun RLE */
  while((numbytes || (cop && numbits >= bits)) && (curentry < entries))
  {
    if(!cop) /* RLE */
    {
      if(numbits < 8)
      {
        bitbuf = (bitbuf<<8)|*(buffer++); --numbytes;
        numbits += 8;
      }
      byte = (bitbuf>>(numbits-8))&0xFF;
      numbits -= 8;
      if(byte <= 127)     cop = byte+1;
      else if(byte > 128) loop = 256-byte+1;
      else                continue;
    }
    if(cop) ++loop;

    if(numbits < bits)
    {
      bitbuf = (bitbuf<<8)|*(buffer++); --numbytes;
      numbits += 8;
    }
    byte = (bitbuf>>(numbits-bits))&mask;
    
    while(loop && (curentry < entries))
    {
      if(type == DECODE_PALETTE)
      { /* NOTE: This may not be very fast, but for sure portable */
        switch(curentry%3)
        {
        case 0: im->Palette[curentry/3].Red = byte; break;
        case 1: im->Palette[curentry/3].Green = byte; break;
        case 2: im->Palette[curentry/3].Blue = byte; break;
        }
      }
      else
        im->ImageData[curentry] = byte;
      ++curentry;
      --loop;
    }
    if(cop) --cop;
    numbits -= bits;
  }  
  //return "DecodeOS35 completed successfully";
  return curentry != entries ? "error decoding icon data" : 0;
}

/**************************************************************************************************/

Examples

edit
/*
    Example for changing icon tooltypes.
*/

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/icon.h>

#include <workbench/startup.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static STRPTR conwinname   = "CON:30/50/500/400/Tooltype parsing/AUTO/CLOSE/WAIT";
static BPTR conwin;
static BPTR olddir = (BPTR)-1;
static struct DiskObject *dobj;
static STRPTR *oldtoolarray, *newtoolarray;

static void clean_exit(CONST_STRPTR s);

int main(int argc, char **argv)
{
    if (argc)
    {
        clean_exit("Application must be started from Wanderer.");
        /* See dos_readargs.c for start from Shell. */
    }
    else
    {
        struct WBStartup *wbmsg = (struct WBStartup *)argv;
        struct WBArg *wbarg = wbmsg->sm_ArgList;
        STRPTR *toolarray;
        LONG toolcnt = 0;
        LONG idx;
        
        /*
            An application started from Wanderer doesn't have a console window
            for output. We have to open our own con: window or all output will
            go to Nirwana.
        */
        conwin = fopen(conwinname, "w");
        if (!conwin)
        {
            clean_exit("Can't open console window");
        }
        
        if ( (wbarg->wa_Lock) && (*wbarg->wa_Name) )
        {
            fprintf(conwin, "Trying to open %s\n", wbarg->wa_Name);
            
            /* We must enter the directory of the icon */
            olddir = CurrentDir(wbarg->wa_Lock);

            dobj = GetDiskObject(wbarg->wa_Name);
            if (dobj)
            {
                /*
                    Remember the old toolarray, so that we can put it back later.
                */
                oldtoolarray = dobj->do_ToolTypes;
            
                /* Count entries */
                if (oldtoolarray)
                {
                    toolarray = oldtoolarray;
                    while (*toolarray)
                    {
                        toolcnt++;
                        toolarray++;
                    }
                }
                fprintf(conwin, "Old icon has %d tooltype entries\n", toolcnt);
                
                /* Create new toolarray */
                newtoolarray = AllocVec(sizeof(STRPTR) * (toolcnt + 3), MEMF_ANY);
                if (!newtoolarray)
                {
                    clean_exit("Can't allocate memory for new toolarray");
                }
                /*
                    Add two new entries and copy the pointers to the
                    old values. If w'd want to change the strings we'd
                    have to work with copies of the strings.
                */
                newtoolarray[0] = "START";
                for (idx = 0 ; idx < toolcnt; idx++)
                {
                    newtoolarray[idx+1] = oldtoolarray[idx];
                }
                newtoolarray[toolcnt + 1] = "END";
                newtoolarray[toolcnt + 2] = NULL;
                
                /* Change toolarray pointer and save icon. */
                dobj->do_ToolTypes = newtoolarray;
                if (!PutDiskObject(wbarg->wa_Name, dobj))
                {
                    clean_exit("Can't write Diskobject");
                }
            }
            else
            {
                clean_exit("Can't open DiskObjekt");
            }
        }
    }

    clean_exit(NULL);

    return 0;
}

static void clean_exit(CONST_STRPTR s)
{
    if (s)
    {
        if (conwin)
        {
            fprintf(conwin, "%s\n", s);
        }
        else
        {
            printf("%s\n", s);
        }
    }
    
    /* Give back allocated resourses */
    if (conwin) fclose(conwin);

    /*
        Free DiskObject. We have to set back the pointer to the toolarray or
        we'll get memory corruption.
    */
    if (dobj)
    {
        dobj->do_ToolTypes = oldtoolarray;
        FreeDiskObject(dobj);
    }
    
    FreeVec(newtoolarray);
    
    /*
        Switch back to old directory. It's important that the directory which
        was active at program start is set when the application is quit.
    */
    if (olddir != (BPTR)-1)
    {
        CurrentDir(olddir);
        olddir = (BPTR)-1;
    }
    
    exit(0);
}


The problem with an SVG based icon is that's there's no place to store the icon data itself. In PNG icons they use an icOn chunk. Classic Icons store icon attributes in the diskobject data, etc. But SVG would have to be a hybrid icon. Classic Amiga Icon File at the beginning. Where the IFF data for a Glow Icon would normally be is instead the beginning of the SVG data. How many images can it store?

SVG is a very flexible format because it allows to embed vector, bitmap and text content, and transformations / filters / animations, so you don't even need to define something like dual PNGs (one SVG should be enough to emulate it). SVG allows to define metadata of any kind, that can be used to store the icon attributes (and much more). You can add those tags everywhere (AFAIR), so even at beginning of the XML data (this can be "forced" as a requirement for those new icons, if it's needed).


Reference

edit
struct DiskObject *NewDiskObject(ULONG type) 
struct DiskObject *GetIconTagList(CONST_STRPTR name, const struct TagItem *tags)

struct DiskObject *GetDiskObject(CONST_STRPTR name) 
BOOL PutDiskObject(CONST_STRPTR name, struct DiskObject *icon) 
void FreeDiskObject(struct DiskObject *diskobj)

BOOL AddFreeList(struct FreeList *freelist, APTR mem, unsigned long size) 
void FreeFreeList(struct FreeList *freelist)

UBYTE *FindToolType(const STRPTR *toolTypeArray, const STRPTR typeName) 
BOOL MatchToolValue(UBYTE *typeString, UBYTE *value) 
UBYTE *BumpRevision(UBYTE *newname, UBYTE *oldname)

struct DiskObject *GetDefDiskObject(LONG type) 
BOOL PutDefDiskObject(struct DiskObject *icon) 
struct DiskObject *GetDiskObjectNew(CONST_STRPTR name) 
BOOL DeleteDiskObject(UBYTE *name)

struct DiskObject *DupDiskObjectA(struct DiskObject *icon, struct TagItem *tags)

ULONG IconControlA(struct DiskObject *icon, struct TagItem *tags) 
void DrawIconStateA(struct RastPort *rp, struct DiskObject *icon, STRPTR label, LONG leftEdge, LONG topEdge, ULONG state, struct TagItem *tags)

BOOL GetIconRectangleA(struct RastPort *rp, struct DiskObject *icon, STRPTR label, struct Rectangle *rectangle, struct TagItem *tags)

BOOL PutIconTagList(CONST_STRPTR name, struct DiskObject *icon, struct TagItem *tags) 
BOOL LayoutIconA(struct DiskObject *icon, struct Screen *screen, struct TagItem *tags) 
void ChangeToSelectedIconColor(struct ColorRegister *cr)