ELFIconSpec

Revision 13 as of 2008-03-30 17:59:13

Clear message

Summary

As a seasoned user of the terminal, the issue of an application having an icon embedded into it is something that I didn't even notice until I started converting others to Ubuntu. I propose adding a non-obtrusive section to ELF applications that provides this functionality and can be accessed through GNOME's thumbnail capability. This idea is meant to compliment the icons provided through the package manager and take advantage of the extensibility of the ELF specification.

Many users expect applications that they've downloaded to have recognizable icons, this icon is usually something familiar from visiting the website for the program. A good example of an application that's not already included in the Ubuntu repo is "songbird", which has a large egg right next to the download link and for its Windows icon.

In addition, provided that this technology is adopted by different segments of the development community (GNOME, automake, and developers) then icon handling will no-longer require any action for packagers. GNOME could easily check the ELF binary for an icon, so no configuration file would be necessary for the appropriate icon to appear. By storing a GUID in the binary it would also be possible to theme icons for all system applications (over-riding the icon stored in the binary) by using the GUID as a unique id for matching the application with an icon stored in a theme.

For a technology demo and screenshots visit [http://www.compholio.com/elficon/].

To discuss this topic please visit [http://brainstorm.ubuntu.com/idea/5744/].

Launchpad spec: https://blueprints.edge.launchpad.net/ubuntu/+spec/elficon

Bug report: https://bugs.launchpad.net/bugs/207141

Preliminary Spec

A library to handle resource files should be used in order to store images in a standardized way, this will also allow applications to store other data (such as graphics and libglade XML files). Handling the icon resource in this way results in the following architecture:

http://www.compholio.com/elficon/architecture.png

libr (sorry, librc was taken)

A proposed new library for handling adding, removing, and retrieving simple resource files from ELF binaries.

API Spec

Resource API

For generic resource handling the following API should be used:

  • int libr_clear(libr_file *handle, char *resourcename);

Remove the resource named "resourcename" from the ELF binary, the resource must exist. Returns 1 (true) on success, 0 (false) on failure.

  • void libr_close(libr_file *handle);

Close the specified file handle.

  • char *libr_errmsg(libr_file *handle);

Return a detailed string of the last error, this string should not be freed. Returns NULL if there have been no errors.

  • char *libr_list(libr_file *handle, unsigned int resourceid);

Obtain the name of a resource by id in the ELF binary, use libr_resources() to obtain the number of total resources (only libr-compatible resources are returned). The name string is allocated when this function is called, so it must be freed when the application no-longer requires it. Returns NULL on failure.

  • libr_file *libr_open(char *filename, libr_access_t access);

Open a file for the specified access (LIBR_READ, LIBR_WRITE, LIBR_READ_WRITE), the valid operations for the returned handle will be restricted based upon the requested access. Pass a NULL pointer to the filename parameter to access the calling binary, for obvious reasons the calling binary may only request LIBR_READ access. Returns NULL on failure.

  • int libr_read(libr_file *handle, char *resourcename, char *buffer);

Read the resource named "resourcename" from the ELF binary, the resource must be saved in compliance with the binary spec. "buffer" must contain a string buffer with enough storage to hold the uncompressed contents of the resource, use libr_size() to obtain the necessary storage size. Returns 1 (true) on success, 0 (false) on failure.

  • unsigned int libr_resources(libr_file *handle);

Returns the number of libr-compatible resources contained in the ELF binary.

  • int libr_size(libr_file *handle, char *resourcename, size_t *size);

Returns the uncompressed size of the specified resource ("resourcename"), use in conjuction with libr_read(). Returns 1 (true) on success, 0 (false) on failure.

  • int libr_write(libr_file *handle, char *resourcename, char *buffer, size_t size, libr_type_t type, libr_overwrite_t overwrite);

Writes the resource named "resourcename" to the ELF binary, the resource should not exist unless "overwrite" is set to 1 (true). "buffer" must contain a string buffer with "size" bytes to write to the ELF binary. "type" specifies whether the data should be compressed by libr (LIBR_UNCOMPRESSED, LIBR_COMPRESSED), and "overwrite" indicates whether overwriting an existing resource should be permitted (LIBR_NOOVERWRITE, LIBR_OVERWRITE). Returns 1 (true) on success, 0 (false) on failure.

Icon API

In order to allow applications to easily access their own icon for display, an icon-specific API is exported. For accessing icon data the following API should be used:

  • int libr_icon_close(libr_icon *icon);

Release the icon resource allocated by a call to libr_icon_geticon_byid(), libr_icon_geticon_byname(), libr_icon_geticon_bysize(), libr_icon_newicon_byfile(), or libr_icon_newicon_frombuffer().

  • libr_icon *libr_icon_geticon_byid(libr_file *handle, unsigned int iconid);

Return a resource handle to an icon stored in an ELF binary that is of an id less than the value returned by libr_icon_num(). Returns NULL on failure.

  • libr_icon *libr_icon_geticon_byname(libr_file *handle, char *iconname);

Return a resource handle to an icon stored in an ELF binary that is named exactly "iconname". Returns NULL on failure.

  • libr_icon *libr_icon_geticon_bysize(libr_file *handle, int iconsize);

Return a resource handle to an icon stored in an ELF binary that is closest to the size "iconsize", use size '0' to request an SVG icon. Returns NULL on failure.

  • int libr_icon_getguid(libr_file *handle, char *guid);

Returns the icon GUID in hex notation (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX), requires a 37 character buffer (36 data characters and a NULL terminator). Returns 1 (true) on success, 0 (false) on failure.

  • libr_icon *libr_icon_newicon_frombuffer(libr_icontype_t type, int iconsize, char *buffer, size_t size);

Create an icon handle to represent an icon file stored in the buffer "buffer". The file should be the same type as specified by "type" (LIBR_SVG, LIBR_PNG), where "iconsize" is ignored for SVG icons. Returns NULL on failure.

  • libr_icon *libr_icon_newicon_byfile(libr_icontype_t type, int iconsize, char *iconfile);

Create an icon handle to represent an icon file stored on disk. The file should be the same type as specified by "type" (LIBR_SVG, LIBR_PNG), where "iconsize" is ignored for SVG icons. Returns NULL on failure.

  • unsigned int libr_icon_num(libr_file *handle);

Returns the number of icons contained within the ELF binary. Returns 0 (false) on failure or when there are no icons.

  • int libr_icon_read(libr_icon *icon, char *buffer);

Stores the uncompressed buffer of the icon represented by the resource handle "icon" in "buffer". "buffer" must contain enough memory to hold the entire icon, use libr_icon_size() to discover how much memory is needed. Returns 1 (true) on success, 0 (false) on failure.

  • int libr_icon_size(libr_icon *icon, int *size);

Returns the uncompressed size of the icon represented by the resource handle "icon" in "size". Returns 1 (true) on success, 0 (false) on failure.

  • int libr_icon_save(libr_icon *icon, char *filename);

Save the icon represented by the resource handle "icon" to a file. Returns 1 (true) on success, 0 (false) on failure.

  • int libr_icon_setguid(libr_file *handle, char *guid);

Sets the icon GUID, the string should be in hex notation (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX) and contain 37 characters (36 data characters and a NULL terminator). Returns 1 (true) on success, 0 (false) on failure.

  • int libr_icon_write(libr_file *handle, libr_icon *icon, char *iconname, int overwrite);

Add the icon represented by the icon handle "icon" to the ELF binary as the icon resource named "iconname". The file should not exist unless overwrite is set to 1 (true). The ELF binary must have a GUID set by libr_icon_setguid() before calling this function. Returns 1 (true) on success, 0 (false) on failure.

Binary Spec

libbfd should be the primary backend library for adding these sections into ELF files, libelf can also be used but at this time libelf has the tendency to corrupt some executables. Each resource stored in the ELF file should be named in the ELF string table using the selected backend and have the following header structure within the respective section:

R

E

S

<Version>

<Type>

At this time only "1" is supported for a version code, two binary "Type" values are supported:

  • 0 --- Uncompressed data follows
  • 1 --- Compressed data follows

If the data is compressed, then a 4-byte little-endian uncompressed size follows. After the header should contain zlib-compressed data, this results in the following format:

R

E

S

1

\001

<S1>

<S2>

<S3>

<S4>

...

In order to handle different icon sizes and possible access types, a special section should define how all icon resources are stored. This section should be named ".icon" and initially created by a call to libr_icon_setguid(). The section should contain a header, in addition to the header added by libr, with the little-endian representation of the number of entries (E*) and the "icon guid" (G*):

<E1>

<E2>

<E3>

<E4>

<G1>

<G2>

<G3>

<G4>

<G5>

<G6>

<G7>

<G8>

<G9>

<G10>

<G11>

<G12>

<G13>

<G14>

<G15>

<G16>

The "icon guid" is meant to be used by distributions to assign an icon to an application and keep that icon consistent between all ways to access the application, this field IS required even if you are not a distributor and may be generated using the application "uuid. The number of entries should be used to indicate the number of different icons stored in the ELF file, these entries should follow the header and should be structured as follows (S* is the entry size):

  • SVG Icon:

<S1>

<S2>

<S3>

<S4>

\000

<Icon Resource Name>

\000

  • PNG Icon:

<S1>

<S2>

<S3>

<S4>

\001

<I1>

<I2>

<I3>

<I4>

<Icon Resource Name>

\000

I* is a little-endian representation of the square icon size (16: 16x16, 32: 32x32, 48: 48x48, etc.)

elfrc | elficon

An application for accessing the icons and resources stored in ELF binaries is necessary for GNOME and for scripts to add and remove ELF resources. The application "elfrc" should be created to fulfull this role, with an alias "elficon" that is specifically for working with icons. Below is a preliminary attempt at how this application might work:

elfrc

  • elfrc -a <elf-file> <resource-name> <resource-file>

Add the file "resource-file" as a resource named "resource-name" in the ELF binary.

  • elfrc -c <elf-file> <resource-name>

Clear the resource named "resource-name" from the ELF binary.

  • elfrc -i

Open a graphic interface for editing ELF binaries (and showcases libr), this is the default when called with no TERM environment variable.

  • elfrc -l <elf-file>

List all of the libr-compatible resources contained within the ELF binary.

  • elfrc -r <elf-file> <resource-name> <output-file>

Retrieve the resource named "resource-name" from the ELF binary and store it in "output-file".

elficon

  • elficon -a <elf-file> <icon-name> <icon-file>

Add the file "icon-file" as an icon resource named "icon-name" in the ELF binary, the binary must have an icon GUID before adding an icon. Icon size and type are automatically determined.

  • elficon -c <elf-file>

Clear all of the icon resources contained within an ELF binary.

  • elficon -f <elf-file> <icon-size> <icon-file>

Find the icon that most closely matches the size specified by "icon-size" from the ELF binary and store it in "icon-file".

  • elficon -g <elf-file> <guid>

Get the icon GUID of an ELF binary. Returned in hex form (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX).

  • elficon -r <elf-file> <icon-name> <icon-file>

Retrieve the icon resource named "icon-name" from the ELF binary and store it in "icon-file".

  • elficon -s <elf-file> <guid>

Set an icon GUID for the ELF binary, requires that the GUID be in hex form (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX).

Comments

Old comments:

  • Do we really need that? Do we want to make Unixes more Windows like? Does Mac OS X have icons in its executables? -- AzraelNightwalker DateTime(2008-03-27T23:20:51Z)

    • I believe this to be a convenience issue (for everyone: users, developers, and packagers), see brainstorm -- Compholio DateTime(2008-03-27T23:37:32Z)

  • Also what's the point of having icons in ELFs when most people will download new software in debs, not in binary executables? Especially when people ideally should just use apt and not download any debs manually. -- AzraelNightwalker DateTime(2008-03-27T23:24:33Z)

    • For one, not all applications are available this way. If applications included their icons already it would not be necessary for packagers to set the icon, so applications benefit whether they are distributed in the repo or not. -- Compholio DateTime(2008-03-27T23:37:32Z)

To discuss this topic please visit [http://brainstorm.ubuntu.com/idea/5744/].