summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am39
-rw-r--r--src/config.h94
-rw-r--r--src/cvtendian.h48
-rw-r--r--src/gettext.h271
-rw-r--r--src/libr-backends.h22
-rw-r--r--src/libr-bfd.c533
-rw-r--r--src/libr-bfd.h40
-rw-r--r--src/libr-elf.c412
-rw-r--r--src/libr-elf.h24
-rw-r--r--src/libr-gtk.c443
-rw-r--r--src/libr-gtk.h55
-rw-r--r--src/libr-i18n.c84
-rw-r--r--src/libr-i18n.h14
-rw-r--r--src/libr-icons.c643
-rw-r--r--src/libr-icons.h201
-rw-r--r--src/libr-internal.h34
-rw-r--r--src/libr-link.h26
-rw-r--r--src/libr-ro.c351
-rw-r--r--src/libr-ro.h62
-rw-r--r--src/libr.c489
-rw-r--r--src/libr.h416
-rw-r--r--src/onecanvas.c446
-rw-r--r--src/onecanvas.h6
-rw-r--r--src/tempfiles.c317
-rw-r--r--src/tempfiles.h13
25 files changed, 5083 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..5fbf00b
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,39 @@
+libr_la_includedir = $(includedir)/libr
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+
+INCLUDES = \
+ -D__LIBR_BACKEND_@BACKEND_NAME@__ \
+ -D__LIBR_BUILD__ \
+ @LIBGLADE_CFLAGS@ \
+ @BACKEND_CFLAGS@ \
+ @EXTRA_CFLAGS@
+
+lib_LTLIBRARIES = \
+ libr.la
+
+libr_la_SOURCES = \
+ libr-@LIBR_BACKEND@.c \
+ tempfiles.c \
+ onecanvas.c \
+ libr-icons.c \
+ libr-i18n.c \
+ libr-gtk.c \
+ libr.c
+
+libr_la_include_HEADERS = \
+ gettext.h \
+ libr-icons.h \
+ libr-i18n.h \
+ libr-gtk.h \
+ libr.h
+
+libr_la_LIBADD = \
+ @BACKEND_LIBS@ \
+ @EXTRA_LIBS@
+
+# If not in a fakeroot environment then run ldconfig
+install: install-am
+ @if [ ! -n "${FAKEROOTKEY}" ]; then \
+ echo "Regenerating system dependencies..."; \
+ ldconfig; \
+ fi
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..a51743e
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,94 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if translation of program messages to the user's native
+ language is requested. */
+#define ENABLE_NLS 1
+
+/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
+ CoreFoundation framework. */
+/* #undef HAVE_CFLOCALECOPYCURRENT */
+
+/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
+ the CoreFoundation framework. */
+/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+ */
+#define HAVE_DCGETTEXT 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#define HAVE_GETTEXT 1
+
+/* Define if you have the iconv() function and it works. */
+/* #undef HAVE_ICONV */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <math.h> header file. */
+#define HAVE_MATH_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#define HAVE_PTHREAD_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "libr"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.4.0"
diff --git a/src/cvtendian.h b/src/cvtendian.h
new file mode 100644
index 0000000..d69158b
--- /dev/null
+++ b/src/cvtendian.h
@@ -0,0 +1,48 @@
+#ifndef __CVTENDIAN_H
+#define __CVTENDIAN_H
+
+/* Support for swapping bytes (endian conversion) */
+#include <byteswap.h>
+
+/* For obtaining the host endian type */
+#include <endian.h>
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+# define HOST_ENDIAN ELFDATA2LSB
+#elif (__BYTE_ORDER == __BIG_ENDIAN)
+# define HOST_ENDIAN ELFDATA2MSB
+#else
+# error "Failed to detect host endian type"
+#endif
+
+/*
+ * Convert the endian of a parameter
+ */
+static int ConvertEndian(void *ptr, int bytes)
+{
+ switch(bytes)
+ {
+ case 2:
+ {
+ uint16_t *value = (uint16_t *) ptr;
+
+ *value = bswap_16(*value);
+ } return 1;
+ case 4:
+ {
+ uint32_t *value = (uint32_t *) ptr;
+
+ *value = bswap_32(*value);
+ } return 1;
+ case 8:
+ {
+ uint64_t *value = (uint64_t *) ptr;
+
+ *value = bswap_64(*value);
+ } return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+#endif /* __CVTENDIAN_H */
diff --git a/src/gettext.h b/src/gettext.h
new file mode 100644
index 0000000..209921e
--- /dev/null
+++ b/src/gettext.h
@@ -0,0 +1,271 @@
+/* Convenience header for conditional use of GNU <libintl.h>.
+ Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA. */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+/* NLS can be disabled through the configure --disable-nls option. */
+#if ENABLE_NLS
+
+/* Get declarations of GNU message catalog functions. */
+# include <libintl.h>
+
+/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
+ the gettext() and ngettext() macros. This is an alternative to calling
+ textdomain(), and is useful for libraries. */
+# ifdef DEFAULT_TEXT_DOMAIN
+# undef gettext
+# define gettext(Msgid) \
+ dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
+# undef ngettext
+# define ngettext(Msgid1, Msgid2, N) \
+ dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
+# endif
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+ chokes if dcgettext is defined as a macro. So include it now, to make
+ later inclusions of <locale.h> a NOP. We don't include <libintl.h>
+ as well because people using "gettext.h" will not include <libintl.h>,
+ and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+ is OK. */
+#if defined(__sun)
+# include <locale.h>
+#endif
+
+/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
+ <libintl.h>, which chokes if dcgettext is defined as a macro. So include
+ it now, to make later inclusions of <libintl.h> a NOP. */
+#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
+# include <cstdlib>
+# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H
+# include <libintl.h>
+# endif
+#endif
+
+/* Disabled NLS.
+ The casts to 'const char *' serve the purpose of producing warnings
+ for invalid uses of the value returned from these functions.
+ On pre-ANSI systems without 'const', the config.h file is supposed to
+ contain "#define const". */
+# define gettext(Msgid) ((const char *) (Msgid))
+# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
+# define dcgettext(Domainname, Msgid, Category) \
+ ((void) (Category), dgettext (Domainname, Msgid))
+# define ngettext(Msgid1, Msgid2, N) \
+ ((N) == 1 \
+ ? ((void) (Msgid2), (const char *) (Msgid1)) \
+ : ((void) (Msgid1), (const char *) (Msgid2)))
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+ ((void) (Domainname), ngettext (Msgid1, Msgid2, N))
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+ ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) \
+ ((void) (Domainname), (const char *) (Dirname))
+# define bind_textdomain_codeset(Domainname, Codeset) \
+ ((void) (Domainname), (const char *) (Codeset))
+
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+ extraction of messages, but does not call gettext(). The run-time
+ translation is done at a different place in the code.
+ The argument, String, should be a literal string. Concatenated strings
+ and other string expressions won't work.
+ The macro's expansion is not parenthesized, so that it is suitable as
+ initializer for static 'char[]' or 'const char[]' variables. */
+#define gettext_noop(String) String
+
+/* The separator between msgctxt and msgid in a .mo file. */
+#define GETTEXT_CONTEXT_GLUE "\004"
+
+/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
+ MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be
+ short and rarely need to change.
+ The letter 'p' stands for 'particular' or 'special'. */
+#ifdef DEFAULT_TEXT_DOMAIN
+# define pgettext(Msgctxt, Msgid) \
+ pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
+#else
+# define pgettext(Msgctxt, Msgid) \
+ pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
+#endif
+#define dpgettext(Domainname, Msgctxt, Msgid) \
+ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
+#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \
+ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category)
+#ifdef DEFAULT_TEXT_DOMAIN
+# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
+ npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
+#else
+# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
+ npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
+#endif
+#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
+ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
+#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \
+ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category)
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+pgettext_aux (const char *domain,
+ const char *msg_ctxt_id, const char *msgid,
+ int category)
+{
+ const char *translation = dcgettext (domain, msg_ctxt_id, category);
+ if (translation == msg_ctxt_id)
+ return msgid;
+ else
+ return translation;
+}
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+npgettext_aux (const char *domain,
+ const char *msg_ctxt_id, const char *msgid,
+ const char *msgid_plural, unsigned long int n,
+ int category)
+{
+ const char *translation =
+ dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
+ if (translation == msg_ctxt_id || translation == msgid_plural)
+ return (n == 1 ? msgid : msgid_plural);
+ else
+ return translation;
+}
+
+/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID
+ can be arbitrary expressions. But for string literals these macros are
+ less efficient than those above. */
+
+#include <string.h>
+
+#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \
+ (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \
+ /* || __STDC_VERSION__ >= 199901L */ )
+
+#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+#include <stdlib.h>
+#endif
+
+#define pgettext_expr(Msgctxt, Msgid) \
+ dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES)
+#define dpgettext_expr(Domainname, Msgctxt, Msgid) \
+ dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES)
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+dcpgettext_expr (const char *domain,
+ const char *msgctxt, const char *msgid,
+ int category)
+{
+ size_t msgctxt_len = strlen (msgctxt) + 1;
+ size_t msgid_len = strlen (msgid) + 1;
+ const char *translation;
+#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+ char msg_ctxt_id[msgctxt_len + msgid_len];
+#else
+ char buf[1024];
+ char *msg_ctxt_id =
+ (msgctxt_len + msgid_len <= sizeof (buf)
+ ? buf
+ : (char *) malloc (msgctxt_len + msgid_len));
+ if (msg_ctxt_id != NULL)
+#endif
+ {
+ memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
+ msg_ctxt_id[msgctxt_len - 1] = '\004';
+ memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
+ translation = dcgettext (domain, msg_ctxt_id, category);
+#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+ if (msg_ctxt_id != buf)
+ free (msg_ctxt_id);
+#endif
+ if (translation != msg_ctxt_id)
+ return translation;
+ }
+ return msgid;
+}
+
+#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
+ dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
+#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
+ dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+dcnpgettext_expr (const char *domain,
+ const char *msgctxt, const char *msgid,
+ const char *msgid_plural, unsigned long int n,
+ int category)
+{
+ size_t msgctxt_len = strlen (msgctxt) + 1;
+ size_t msgid_len = strlen (msgid) + 1;
+ const char *translation;
+#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+ char msg_ctxt_id[msgctxt_len + msgid_len];
+#else
+ char buf[1024];
+ char *msg_ctxt_id =
+ (msgctxt_len + msgid_len <= sizeof (buf)
+ ? buf
+ : (char *) malloc (msgctxt_len + msgid_len));
+ if (msg_ctxt_id != NULL)
+#endif
+ {
+ memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
+ msg_ctxt_id[msgctxt_len - 1] = '\004';
+ memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
+ translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
+#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+ if (msg_ctxt_id != buf)
+ free (msg_ctxt_id);
+#endif
+ if (!(translation == msg_ctxt_id || translation == msgid_plural))
+ return translation;
+ }
+ return (n == 1 ? msgid : msgid_plural);
+}
+
+#endif /* _LIBGETTEXT_H */
diff --git a/src/libr-backends.h b/src/libr-backends.h
new file mode 100644
index 0000000..a0cd59c
--- /dev/null
+++ b/src/libr-backends.h
@@ -0,0 +1,22 @@
+#ifndef __LIBR_BACKENDS_H
+#define __LIBR_BACKENDS_H
+
+/*
+ * All of the backend functions are explicitly declared internal to prevent any custom backend
+ * from leaving out one of these critical functions.
+ */
+INTERNAL_FN libr_intstatus add_section(libr_file *file_handle, char *resource_name, libr_section **retscn);
+INTERNAL_FN void *data_pointer(libr_section *scn, libr_data *data);
+INTERNAL_FN size_t data_size(libr_section *scn, libr_data *data);
+INTERNAL_FN libr_intstatus find_section(libr_file *file_handle, char *section, libr_section **retscn);
+INTERNAL_FN libr_data *get_data(libr_file *file_handle, libr_section *scn);
+INTERNAL_FN void initialize_backend(void);
+INTERNAL_FN libr_data *new_data(libr_file *file_handle, libr_section *scn);
+INTERNAL_FN libr_section *next_section(libr_file *file_handle, libr_section *scn);
+INTERNAL_FN libr_intstatus remove_section(libr_file *file_handle, libr_section *scn);
+INTERNAL_FN char *section_name(libr_file *file_handle, libr_section *scn);
+INTERNAL_FN libr_intstatus set_data(libr_file *file_handle, libr_section *scn, libr_data *data, off_t offset, char *buffer, size_t size);
+INTERNAL_FN libr_intstatus open_handles(libr_file *file_handle, char *filename, libr_access_t access);
+INTERNAL_FN void write_output(libr_file *file_handle);
+
+#endif /* __LIBR_BACKENDS_H */
diff --git a/src/libr-bfd.c b/src/libr-bfd.c
new file mode 100644
index 0000000..c4bc8b1
--- /dev/null
+++ b/src/libr-bfd.c
@@ -0,0 +1,533 @@
+/*
+ *
+ * Copyright (c) 2008-2011 Erich Hoover
+ *
+ * libr libbfd Backend - Add resources into ELF binaries using libbfd
+ *
+ * *** PLEASE READ THE README FILE FOR LICENSE DETAILS SPECIFIC TO THIS FILE ***
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+/* Include compile-time parameters */
+#include "config.h"
+
+#include "libr.h"
+#include "libr-internal.h"
+
+/* File access */
+#include <fcntl.h>
+
+/* Safe rename requires some errno() knowledge */
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * Build the libr_file handle for processing with libbfd
+ */
+libr_intstatus open_handles(libr_file *file_handle, char *filename, libr_access_t access)
+{
+ bfd *handle = NULL;
+
+ handle = bfd_openr(filename, "default");
+ if(!handle)
+ RETURN(LIBR_ERROR_OPENFAILED, "Failed to open input file");
+ if(!bfd_check_format(handle, bfd_object))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: not a libbfd object");
+ if(bfd_get_flavour(handle) != bfd_target_elf_flavour)
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: not an ELF file");
+ bfd_set_error(bfd_error_no_error);
+ file_handle->filename = filename;
+ file_handle->bfd_read = handle;
+ file_handle->access = access;
+ if(access == LIBR_READ_WRITE)
+ {
+ struct stat file_stat;
+ int fd;
+
+ /* Check for write permission on the file */
+ fd = open(filename, O_WRONLY);
+ if(fd == ERROR)
+ RETURN(LIBR_ERROR_WRITEPERM, "No write permission for file");
+ close(fd);
+ /* Obtain the access mode of the input file */
+ if(stat(filename, &file_stat) == ERROR)
+ RETURN(LIBR_ERROR_NOSIZE, "Failed to obtain file size");
+ file_handle->filemode = file_stat.st_mode;
+ file_handle->fileowner = file_stat.st_uid;
+ file_handle->filegroup = file_stat.st_gid;
+ /* Open a temporary file with the same settings as the input file */
+ strcpy(file_handle->tempfile, LIBR_TEMPFILE);
+ file_handle->fd_handle = mkstemp(file_handle->tempfile);
+ handle = bfd_openw(file_handle->tempfile, bfd_get_target(file_handle->bfd_read));
+ if(!bfd_set_format(handle, bfd_get_format(file_handle->bfd_read)))
+ RETURN(LIBR_ERROR_SETFORMAT, "Failed to set output file format to input file format");
+ if(!bfd_set_arch_mach(handle, bfd_get_arch(file_handle->bfd_read), bfd_get_mach(file_handle->bfd_read)))
+ RETURN(LIBR_ERROR_SETARCH, "Failed to set output file architecture to input file architecture");
+ /* twice needed ? */
+ if(!bfd_set_format(handle, bfd_get_format(file_handle->bfd_read)))
+ RETURN(LIBR_ERROR_SETFORMAT, "Failed to set output file format to input file format");
+ file_handle->bfd_write = handle;
+ }
+ else
+ {
+ file_handle->fd_handle = 0;
+ file_handle->bfd_write = NULL;
+ }
+ RETURN_OK;
+}
+
+/*
+ * Check to see if a symbol should be kept
+ */
+int keep_symbol(libr_section *sections, libr_section *chkscn)
+{
+ libr_section *scn;
+
+ /* Check that the section is publicly exposed */
+ for(scn = sections; scn != NULL; scn = scn->next)
+ {
+ if(scn == chkscn)
+ {
+ /* if it is, and has size zero, then it was marked for deletion */
+ if(bfd_get_section_size(chkscn) == 0)
+ return false;
+ return true;
+ }
+ }
+ return true;
+}
+
+/*
+ * Remove the symbol corresponding to a deleted section
+ */
+void remove_sections(libr_section *sections, void *symtab_buffer, long *symtab_count)
+{
+ asymbol **symtab = (asymbol **) symtab_buffer;
+ long i, cnt = *symtab_count;
+
+ for(i=0;i<cnt;i++)
+ {
+ libr_section *chkscn = NULL;
+ asymbol *symbol = symtab[i];
+
+ if(symbol != NULL)
+ chkscn = bfd_get_section(symbol);
+ if(chkscn != NULL && !keep_symbol(sections, chkscn))
+ {
+ /* remove the symbol from the table */
+ asymbol **tmp = (asymbol **) malloc(sizeof(asymbol *) * (cnt-(i+1)));
+ memcpy(&tmp[0], &symtab[i+1], sizeof(asymbol *) * (cnt-(i+1)));
+ memcpy(&symtab[i], &tmp[0], sizeof(asymbol *) * (cnt-(i+1)));
+ free(tmp);
+ cnt--;
+ }
+ }
+ *symtab_count = cnt;
+}
+
+int setup_sections(bfd *ihandle, bfd *ohandle)
+{
+ libr_section *iscn, *oscn;
+ bfd_vma vma;
+
+ for(iscn = ihandle->sections; iscn != NULL; iscn = iscn->next)
+ {
+ if(bfd_get_section_size(iscn) == 0)
+ {
+ continue; /* Section has been marked for deletion */
+ }
+ /* Use SEC_LINKER_CREATED to ask the libbfd backend to take care of configuring the section */
+
+ // Keep the ARM_ATTRIBUTES section type intact on armhf systems
+ // If this is not done, readelf -A will not print any architecture information for the modified library,
+ // and ldd will report that the library cannot be found
+ if (strcmp(iscn->name, ".ARM.attributes") == 0)
+ {
+ oscn = bfd_make_section_anyway_with_flags(ohandle, iscn->name, iscn->flags);
+ }
+ else
+ {
+ oscn = bfd_make_section_anyway_with_flags(ohandle, iscn->name, iscn->flags | SEC_LINKER_CREATED);
+ }
+ if(oscn == NULL)
+ {
+ printf("failed to create out section: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ if(!bfd_set_section_size(ohandle, oscn, iscn->size))
+ {
+ printf("failed to set data size: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ vma = bfd_section_vma(ihandle, iscn);
+ if(!bfd_set_section_vma(ohandle, oscn, vma))
+ {
+ printf("failed to set virtual memory address: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ oscn->lma = iscn->lma;
+ if(!bfd_set_section_alignment(ohandle, oscn, bfd_section_alignment(ihandle, iscn)))
+ {
+ printf("failed to compute section alignment: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ oscn->entsize = iscn->entsize;
+ iscn->output_section = oscn;
+ iscn->output_offset = vma;
+ if(!bfd_copy_private_section_data(ihandle, iscn, ohandle, oscn))
+ {
+ printf("failed to compute section alignment: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * Go through the rather complicated process of using libbfd to build the output file
+ */
+int build_output(libr_file *file_handle)
+{
+ void *symtab_buffer = NULL, *reloc_buffer = NULL, *buffer = NULL;
+ bfd_size_type symtab_size, reloc_size, size;
+ bfd *ohandle = file_handle->bfd_write;
+ bfd *ihandle = file_handle->bfd_read;
+ long symtab_count, reloc_count;
+ libr_section *iscn, *oscn;
+
+ if(!bfd_set_start_address(ohandle, bfd_get_start_address(ihandle)))
+ {
+ printf("failed to set start address: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ if(!bfd_set_file_flags(ohandle, bfd_get_file_flags(ihandle)))
+ {
+ printf("failed to set file flags: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ /* Setup the sections in the output file */
+ if(!setup_sections(ihandle, ohandle))
+ return false; /* error already printed */
+ if(!bfd_copy_private_header_data(ihandle, ohandle))
+ {
+ printf("failed to copy header: %s\n", bfd_errmsg(bfd_get_error()));
+ return false; /* failed to create section */
+ }
+ /* Get the old symbol table */
+ if((bfd_get_file_flags(ihandle) & HAS_SYMS) == 0)
+ {
+ printf("file has no symbol table: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ symtab_size = bfd_get_symtab_upper_bound(ihandle);
+ if((signed)symtab_size < 0)
+ {
+ printf("failed to get symbol table size: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ symtab_buffer = malloc(symtab_size);
+ symtab_count = bfd_canonicalize_symtab(ihandle, symtab_buffer);
+ if(symtab_count < 0)
+ {
+ printf("failed to get symbol table number of entries: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ /* Tweak the symbol table to remove sections that no-longer exist */
+ remove_sections(ihandle->sections, symtab_buffer, &symtab_count);
+ bfd_set_symtab(ohandle, symtab_buffer, symtab_count);
+ /* Actually copy section data */
+ for(iscn = ihandle->sections; iscn != NULL; iscn = iscn->next)
+ {
+ size = bfd_get_section_size(iscn);
+ if(size == 0)
+ continue; /* Section has been marked for deletion */
+ oscn = iscn->output_section;
+ reloc_size = bfd_get_reloc_upper_bound(ihandle, iscn);
+ if(reloc_size == 0)
+ bfd_set_reloc(ohandle, oscn, NULL, 0);
+ else
+ {
+ reloc_buffer = malloc(reloc_size);
+ reloc_count = bfd_canonicalize_reloc(ihandle, iscn, reloc_buffer, symtab_buffer);
+ bfd_set_reloc(ohandle, oscn, reloc_buffer, reloc_count);
+ }
+
+ if(bfd_get_section_flags(ihandle, iscn) & SEC_HAS_CONTENTS)
+ {
+ /* NOTE: if the section is just being copied then do that, otherwise grab
+ * the user data for the section (stored previously by set_data)
+ */
+ if(iscn->userdata == NULL)
+ {
+ buffer = malloc(size);
+ if(!bfd_get_section_contents(ihandle, iscn, buffer, 0, size))
+ {
+ printf("failed to get section contents: %s\n", bfd_errmsg(bfd_get_error()));
+ free(buffer);
+ return false;
+ }
+ }
+ else
+ buffer = iscn->userdata;
+ if(!bfd_set_section_contents(ohandle, oscn, buffer, 0, size))
+ {
+ printf("failed to set section contents: %s\n", bfd_errmsg(bfd_get_error()));
+ free(buffer);
+ return false;
+ }
+ free(buffer);
+ if(!bfd_copy_private_section_data(ihandle, iscn, ohandle, oscn))
+ {
+ printf("failed to copy private section data: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ }
+ }
+ if(!bfd_copy_private_bfd_data(ihandle, ohandle))
+ {
+ printf("failed to copy private data: %s\n", bfd_errmsg(bfd_get_error()));
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Perform a cross-device safe rename
+ */
+int safe_rename(const char *old, const char *new)
+{
+ char buffer[1024];
+ FILE *in, *out;
+ int read;
+
+ in = fopen(old, "r");
+ if(!in)
+ return -1;
+ out = fopen(new, "w");
+ if(!out)
+ return -1;
+ while(!feof(in) && !ferror(in))
+ {
+ read = fread(buffer, 1, sizeof(buffer), in);
+ fwrite(buffer, read, 1, out);
+ }
+ fclose(in);
+ fclose(out);
+ if(ferror(in))
+ {
+ remove(new);
+ return -1;
+ }
+ return remove(old);
+}
+
+/*
+ * Write the output file using the libbfd method
+ */
+void write_output(libr_file *file_handle)
+{
+ int write_ok = false;
+
+ if(file_handle->bfd_write != NULL)
+ {
+ write_ok = true;
+ if(!build_output(file_handle))
+ {
+ printf("failed to build output file.\n");
+ write_ok = false;
+ }
+ if(!bfd_close(file_handle->bfd_write))
+ {
+ printf("failed to close write handle.\n");
+ write_ok = false;
+ }
+ if(file_handle->fd_handle != 0 && close(file_handle->fd_handle))
+ {
+ write_ok = false;
+ printf("failed to close write file descriptor.\n");
+ }
+ }
+ /* The read handle must be closed last since it is used in the write process */
+ if(!bfd_close(file_handle->bfd_read))
+ printf("failed to close read handle.\n");
+ /* Copy the temporary output over the input */
+ if(write_ok)
+ {
+ if(rename(file_handle->tempfile, file_handle->filename) < 0)
+ {
+ if(errno != EXDEV || safe_rename(file_handle->tempfile, file_handle->filename) < 0)
+ printf("failed to rename output file: %m\n");
+ }
+ if(chmod(file_handle->filename, file_handle->filemode) < 0)
+ printf("failed to set file mode.\n");
+ if(chown(file_handle->filename, file_handle->fileowner, file_handle->filegroup) < 0)
+ printf("failed to set file ownership.\n");
+ }
+}
+
+/*
+ * Find a named section from the ELF file using libbfd
+ */
+libr_intstatus find_section(libr_file *file_handle, char *section_name, libr_section **retscn)
+{
+ libr_section *scn;
+
+ for(scn = file_handle->bfd_read->sections; scn != NULL; scn = scn->next)
+ {
+ if(strcmp(scn->name, section_name) == 0)
+ {
+ *retscn = scn;
+ RETURN_OK;
+ }
+ }
+ RETURN(LIBR_ERROR_NOSECTION, "ELF resource section not found");
+}
+
+/*
+ * Obtain the data from a section using libbfd
+ */
+libr_data *get_data(libr_file *file_handle, libr_section *scn)
+{
+ libr_data *data = malloc(scn->size);
+
+ if(!bfd_get_section_contents(file_handle->bfd_read, scn, data, 0, scn->size))
+ {
+ free(data);
+ data = NULL;
+ }
+ scn->userdata = data;
+ return data;
+}
+
+/*
+ * Create new data for a section using libbfd
+ */
+libr_data *new_data(libr_file *file_handle, libr_section *scn)
+{
+ /* NOTE: expanding data is handled by set_data for libbfd */
+ if(scn->userdata != NULL)
+ return scn->userdata;
+ scn->size = 0;
+ scn->userdata = malloc(0);
+ return scn->userdata;
+}
+
+/*
+ * Create new data for a section using libbfd (at least, do so memory-wise)
+ */
+libr_intstatus set_data(libr_file *file_handle, libr_section *scn, libr_data *data, off_t offset, char *buffer, size_t size)
+{
+ char *intbuffer = NULL;
+
+ /* special case: clear buffer */
+ if(buffer == NULL)
+ {
+ scn->size = 0;
+ if(scn->userdata != NULL)
+ free(scn->userdata);
+ RETURN_OK;
+ }
+ /* normal case: add new data to the buffer */
+ scn->size = offset + size;
+ scn->userdata = realloc(data, scn->size);
+ if(scn->userdata == NULL)
+ RETURN(LIBR_ERROR_MEMALLOC, "Failed to allocate memory for data");
+ intbuffer = scn->userdata;
+ memcpy(&intbuffer[offset], buffer, size);
+ RETURN_OK;
+}
+
+/*
+ * Create a new section using libbfd
+ */
+libr_intstatus add_section(libr_file *file_handle, char *resource_name, libr_section **retscn)
+{
+ libr_section *scn = NULL;
+
+ scn = bfd_make_section(file_handle->bfd_read, resource_name);
+ if(scn == NULL)
+ RETURN(LIBR_ERROR_NEWSECTION, "Failed to create new section");
+ if(!bfd_set_section_flags(file_handle->bfd_read, scn, SEC_HAS_CONTENTS | SEC_DATA | SEC_IN_MEMORY))
+ RETURN(LIBR_ERROR_SETFLAGS, "Failed to set flags for section");
+ *retscn = scn;
+ RETURN_OK;
+}
+
+/*
+ * Remove a section and eliminate it from the ELF string table using libbfd
+ */
+libr_intstatus remove_section(libr_file *file_handle, libr_section *scn)
+{
+ scn->size = 0;
+ RETURN_OK;
+}
+
+/*
+ * Return the pointer to the actual data in the section
+ */
+void *data_pointer(libr_section *scn, libr_data *data)
+{
+ return data;
+}
+
+/*
+ * Return the size of the data in the section
+ */
+size_t data_size(libr_section *scn, libr_data *data)
+{
+ return scn->size;
+}
+
+/*
+ * Return the next section in the ELF file
+ */
+libr_section *next_section(libr_file *file_handle, libr_section *scn)
+{
+ /* get the first section */
+ if(scn == NULL)
+ {
+ if(file_handle->bfd_read == NULL)
+ return NULL;
+ return file_handle->bfd_read->sections;
+ }
+ return scn->next;
+}
+
+/*
+ * Return the name of a section
+ */
+char *section_name(libr_file *file_handle, libr_section *scn)
+{
+ return (char *) scn->name;
+}
+
+/*
+ * Initialize libbfd
+ */
+void initialize_backend(void)
+{
+ bfd_init();
+}
+
diff --git a/src/libr-bfd.h b/src/libr-bfd.h
new file mode 100644
index 0000000..7b6ea3e
--- /dev/null
+++ b/src/libr-bfd.h
@@ -0,0 +1,40 @@
+#ifndef __LIBR_BFD_H
+#define __LIBR_BFD_H
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <bfd.h>
+
+#if BFD_HOST_64BIT_LONG
+ #if defined(__i386)
+ #error "Using incorrect binutils header file for architecture."
+ #endif
+#else
+ #if defined(__amd64)
+ #error "Using incorrect binutils header file for architecture."
+ #endif
+#endif
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+typedef struct _libr_file {
+ int fd_handle;
+ bfd *bfd_read;
+ bfd *bfd_write;
+ char *filename;
+ mode_t filemode;
+ uid_t fileowner;
+ gid_t filegroup;
+ char tempfile[LIBR_TEMPFILE_LEN];
+ libr_access_t access;
+} libr_file;
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+/* for a clean internal API */
+typedef asection libr_section;
+typedef void libr_data;
+
+#endif /* __LIBR_BFD_H */
diff --git a/src/libr-elf.c b/src/libr-elf.c
new file mode 100644
index 0000000..be2daae
--- /dev/null
+++ b/src/libr-elf.c
@@ -0,0 +1,412 @@
+/*
+ *
+ * Copyright (c) 2008 Erich Hoover
+ *
+ * libr libelf Backend - Add resources into ELF binaries using libelf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+/* Include compile-time parameters */
+#include "config.h"
+
+#include "libr.h"
+
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+//#define MANUAL_LAYOUT true
+
+extern void libr_set_error(libr_intstatus error);
+
+/*
+ * Write the output file using libelf
+ */
+void write_output(libr_file *file_handle)
+{
+ /* Update the ELF file on the disk */
+ if(elf_update(file_handle->elf_handle, ELF_C_NULL) < 0)
+ {
+ printf("elf_update() failed: %s.", elf_errmsg(-1));
+ return;
+ }
+ if(elf_update(file_handle->elf_handle, ELF_C_WRITE) < 0)
+ {
+ printf("elf_update() failed: %s.", elf_errmsg(-1));
+ return;
+ }
+ /* Close the handles */
+ elf_end(file_handle->elf_handle);
+ close(file_handle->fd_handle);
+}
+
+/*
+ * Return the size of the file represented by the file descriptor
+ */
+off_t file_size(int fd)
+{
+ struct stat file_stat;
+
+ if(fstat(fd, &file_stat) == ERROR)
+ return ERROR;
+ return file_stat.st_size;
+}
+
+/*
+ * Open the handles for working with the file using libelf
+ */
+libr_intstatus open_handles(libr_file *file_handle, char *filename, libr_access_t access)
+{
+ const int elf_access[2] = {ELF_C_READ, ELF_C_RDWR};
+ const int fd_access[2] = {O_RDONLY, O_RDWR};
+ Elf *e = NULL;
+ int fd = 0;
+
+ if((fd = open(filename, fd_access[access], 0)) < 0)
+ RETURN(LIBR_ERROR_OPENFAILED, "Failed to open input file");
+ if((e = elf_begin(fd, elf_access[access], NULL)) == NULL)
+ RETURN(LIBR_ERROR_BEGINFAILED, "Failed to open ELF file: %s.", elf_errmsg(-1));
+ if(elf_kind(e) != ELF_K_ELF)
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format");
+
+ file_handle->access = access;
+ file_handle->fd_handle = fd;
+ file_handle->elf_handle = e;
+ file_handle->file_size = file_size(fd);
+ file_handle->version = EV_CURRENT; /* This should probably match the rest of the file */
+ RETURN_OK;
+}
+
+/*
+ * Expand a section
+ * (Only used when manually controlling ELF layout)
+ */
+#ifdef MANUAL_LAYOUT
+libr_intstatus expand_section(Elf *e, Elf_Scn *scn, size_t size, int reset)
+{
+ size_t offset = 0, delta = 0;
+ Elf_Scn *tmpscn = NULL;
+ GElf_Shdr shdr;
+
+ if(gelf_getshdr(scn, &shdr) != &shdr)
+ RETURN(LIBR_INTERROR_GETSHDR, "Failed to obtain ELF header: %s", elf_errmsg(-1));
+ if(reset)
+ {
+ delta = (size-shdr.sh_size);
+ shdr.sh_size = size;
+ }
+ else
+ {
+ delta = size;
+ shdr.sh_size += size;
+ }
+ offset = shdr.sh_offset;
+ if(gelf_update_shdr(scn, &shdr) < 0)
+ RETURN(LIBR_ERROR_UPDATE, "Failed to perform dynamic update: %s.", elf_errmsg(-1));
+ if(elf_update(e, ELF_C_NULL) < 0)
+ RETURN(LIBR_ERROR_UPDATE, "Failed to perform dynamic update: %s.", elf_errmsg(-1));
+ /* Update any section that follows this one data-wise */
+/*
+****** This does not work yet
+ while((tmpscn = elf_nextscn(e, tmpscn)) != NULL)
+ {
+ if(tmpscn == scn)
+ continue;
+ if(gelf_getshdr(tmpscn, &shdr) != &shdr)
+ return LIBR_INTERROR_GETSHDR;
+ if(offset < shdr.sh_offset)
+ {
+ if((name = elf_strptr(e, ehdr.e_shstrndx, shdr.sh_name)) == NULL)
+ RETURN(LIBR_ERROR_STRPTR, "Failed to obtain section string pointer: %s.", elf_errmsg(-1));
+ shdr.sh_offset += delta;
+ if(gelf_update_shdr(tmpscn, &shdr) < 0)
+ RETURN(LIBR_ERROR_UPDATE, "Failed to perform dynamic update: %s.", elf_errmsg(-1));
+ if(elf_update(e, ELF_C_NULL) < 0)
+ RETURN(LIBR_ERROR_UPDATE, "Failed to perform dynamic update: %s.", elf_errmsg(-1));
+ }
+ }
+*/
+ return LIBR_OK;
+}
+#endif /* MANUAL_LAYOUT */
+
+/*
+ * Obtain the data from a section using libelf
+ */
+libr_data *get_data(libr_file *file_handle, libr_section *scn)
+{
+ return elf_getdata(scn, NULL);
+}
+
+/*
+ * Create new data for a section using libelf
+ */
+libr_data *new_data(libr_file *file_handle, libr_section *scn)
+{
+ return elf_newdata(scn);
+}
+
+/*
+ * Set data for a section using libelf (not written yet)
+ */
+libr_intstatus set_data(libr_file *file_handle, libr_section *scn, libr_data *data, off_t offset, char *buffer, size_t size)
+{
+ data->d_align = 1;
+ data->d_off = offset;
+ data->d_buf = buffer;
+ data->d_type = ELF_T_BYTE;
+ data->d_size = size;
+ data->d_version = file_handle->version;
+#ifdef MANUAL_LAYOUT
+ if(expand_section(file_handle->elf_handle, scn, data->d_size, true) != LIBR_OK)
+ RETURN(LIBR_ERROR_EXPANDSECTION, "Failed to expand section");
+#else
+ if(elf_update(file_handle->elf_handle, ELF_C_NULL) < 0)
+ RETURN(LIBR_ERROR_UPDATE, "Failed to perform dynamic update: %s.", elf_errmsg(-1));
+ if(elf_update(file_handle->elf_handle, ELF_C_WRITE) < 0)
+ RETURN(LIBR_ERROR_UPDATE, "Failed to perform dynamic update: %s.", elf_errmsg(-1));
+#endif /* MANUAL_LAYOUT */
+ RETURN_OK;
+}
+
+/*
+ * Find a named section from the ELF file using libelf
+ */
+libr_intstatus find_section(libr_file *file_handle, char *section, libr_section **retscn)
+{
+ Elf *e = file_handle->elf_handle;
+ Elf_Scn *scn = NULL;
+ char *name = NULL;
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+ uintmax_t si;
+
+ if(gelf_getehdr(e, &ehdr) == NULL)
+ RETURN(LIBR_ERROR_GETEHDR, "Failed to obtain ELF header: %s", elf_errmsg(-1));
+ while((scn = elf_nextscn(e, scn)) != NULL)
+ {
+ if(gelf_getshdr(scn, &shdr) != &shdr)
+ RETURN(LIBR_ERROR_GETSHDR, "Failed to obtain ELF section header: %s", elf_errmsg(-1));
+ if((name = elf_strptr(e, ehdr.e_shstrndx, shdr.sh_name)) == NULL)
+ RETURN(LIBR_ERROR_STRPTR, "Failed to obtain section string pointer: %s.", elf_errmsg(-1));
+
+ si = (uintmax_t) elf_ndxscn(scn);
+/*
+printf("%d: %s (%d %d)\n", (long) si, name, (long) shdr.sh_offset, (long) shdr.sh_size);
+*/
+ if(strcmp(name, section) == 0)
+ {
+ *retscn = scn;
+ RETURN_OK;
+ }
+ }
+ RETURN(LIBR_ERROR_NOSECTION, "ELF resource section not found");
+}
+
+/*
+ * Add a new section and create a name for it in the ELF string table using libelf
+ */
+libr_intstatus add_section(libr_file *file_handle, char *section, Elf_Scn **retscn)
+{
+ Elf_Scn *scn = NULL, *strscn = NULL;
+ Elf *e = file_handle->elf_handle;
+#ifdef MANUAL_LAYOUT
+ size_t tblsize = 0;
+#endif /* MANUAL_LAYOUT */
+ Elf_Data *data;
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+
+ if(gelf_getehdr(e, &ehdr) == NULL)
+ RETURN(LIBR_ERROR_GETEHDR, "Failed to obtain ELF header: %s", elf_errmsg(-1));
+ /* TODO: Support creating a string table for objects that don't have one */
+ if(!ehdr.e_shstrndx)
+ RETURN(LIBR_ERROR_NOTABLE, "No ELF string table");
+ strscn = elf_getscn(e, ehdr.e_shstrndx);
+ if(strscn == NULL)
+ RETURN(LIBR_ERROR_TABLE, "Failed to open string table: %s.", elf_errmsg(-1));
+ data = elf_newdata(strscn);
+ if(data == NULL)
+ RETURN(LIBR_ERROR_NEWDATA, "Failed to create data for section");
+ data->d_align = 1;
+
+#ifdef MANUAL_LAYOUT
+{
+ GElf_Shdr strshdr;
+
+ if(gelf_getshdr(strscn, &strshdr) != &strshdr)
+ RETURN(LIBR_ERROR_GETSHDR, "Failed to obtain ELF section header: %s", elf_errmsg(-1));
+ data->d_off = strshdr.sh_size;
+#endif /* MANUAL_LAYOUT */
+
+ data->d_size = (size_t) strlen(section)+1;
+ data->d_type = ELF_T_BYTE;
+ data->d_buf = section;
+ data->d_version = file_handle->version;
+
+#ifdef MANUAL_LAYOUT
+ if(expand_section(e, strscn, data->d_size, false) != LIBR_OK)
+ return false;
+}
+#else
+ /* Update the internal offset information */
+ if(elf_update(e, ELF_C_NULL) < 0)
+ RETURN(LIBR_ERROR_UPDATE, "Failed to perform dynamic update: %s.", elf_errmsg(-1));
+#endif /* MANUAL_LAYOUT */
+
+ /* seek to the end of the section data */
+ if((scn = elf_newscn(e)) == NULL)
+ RETURN(LIBR_ERROR_NEWSECTION, "Failed to create new section");
+ if(gelf_getshdr(scn, &shdr) != &shdr)
+ RETURN(LIBR_ERROR_GETSHDR, "Failed to obtain ELF section header: %s", elf_errmsg(-1));
+ shdr.sh_addralign = 1;
+#ifdef MANUAL_LAYOUT
+ shdr.sh_offset = file_handle->file_size;
+#endif /* MANUAL_LAYOUT */
+ shdr.sh_size = 0;
+ shdr.sh_name = data->d_off;
+ shdr.sh_type = SHT_NOTE; /* TODO: Does "NOTE" type fit best? */
+ shdr.sh_flags = SHF_WRITE;
+ shdr.sh_entsize = 0;
+ if(gelf_update_shdr(scn, &shdr) < 0)
+ RETURN(LIBR_ERROR_UPDATE, "Failed to perform dynamic update: %s.", elf_errmsg(-1));
+ *retscn = scn;
+ RETURN_OK;
+}
+
+/*
+ * Remove a section and eliminate it from the ELF string table using libelf
+ */
+libr_intstatus remove_section(libr_file *file_handle, libr_section *scn)
+{
+ unsigned int table_size, str_size;
+ char *buffer = NULL, *tmp = NULL;
+ Elf *e = file_handle->elf_handle;
+ int remaining_size;
+ Elf_Scn *strscn;
+ Elf_Data *data;
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+
+ if(gelf_getehdr(e, &ehdr) == NULL)
+ RETURN(LIBR_ERROR_GETEHDR, "Failed to obtain ELF header: %s", elf_errmsg(-1));
+ /* Grab the string table */
+ if(!ehdr.e_shstrndx)
+ RETURN(LIBR_ERROR_NOTABLE, "No ELF string table");
+ strscn = elf_getscn(e, ehdr.e_shstrndx);
+ if(strscn == NULL)
+ RETURN(LIBR_ERROR_TABLE, "Failed to open string table: %s.", elf_errmsg(-1));
+ if((data = elf_getdata(strscn, NULL)) == NULL)
+ RETURN(LIBR_ERROR_GETDATA, "Failed to obtain data of section");
+ /* Find where the section name is in the string table */
+ if(gelf_getshdr(scn, &shdr) != &shdr)
+ RETURN(LIBR_ERROR_GETSHDR, "Failed to obtain ELF section header: %s", elf_errmsg(-1));
+ table_size = data->d_size;
+ buffer = (char *) data->d_buf;
+ /* Excise the string from the table */
+ str_size = strlen(&buffer[shdr.sh_name])+1;
+ remaining_size = table_size-(shdr.sh_name+str_size);
+ if(remaining_size < 0)
+ RETURN(LIBR_ERROR_SIZEMISMATCH, "Section's data size does not make sense");
+ if(remaining_size > 0)
+ {
+ /* If there is data after our icon entry in the table then it must be moved before resizing
+ * NOTE: Using memcpy with overlapping addresses is not allowed, use temporary buffer.
+ */
+ tmp = (char *) malloc(remaining_size);
+ memcpy(tmp, &buffer[shdr.sh_name+str_size], remaining_size);
+ memcpy(&buffer[shdr.sh_name], tmp, remaining_size);
+ free(tmp);
+ }
+ data->d_size -= str_size;
+ /* Update the internal offset information */
+ if(elf_update(e, ELF_C_NULL) < 0)
+ RETURN(LIBR_ERROR_UPDATE, "Failed to perform dynamic update: %s.", elf_errmsg(-1));
+#ifdef MANUAL_LAYOUT
+{
+ GElf_Shdr strshdr;
+
+ if(gelf_getshdr(strscn, &strshdr) != &strshdr)
+ RETURN(LIBR_ERROR_GETSHDR, "Failed to obtain ELF section header: %s", elf_errmsg(-1));
+ strshdr.sh_size -= str_size;
+ if(gelf_update_shdr(strscn, &strshdr) < 0)
+ RETURN(LIBR_ERROR_UPDATE, "Failed to perform dynamic update: %s.", elf_errmsg(-1));
+}
+#endif /* MANUAL_LAYOUT */
+
+ /* Clear the section itself and update the offsets */
+ if(elfx_remscn(e, scn) == 0)
+ RETURN(LIBR_ERROR_REMOVESECTION, "Failed to remove section: %s.", elf_errmsg(-1));
+ RETURN_OK;
+}
+
+/*
+ * Return the pointer to the actual data in the section
+ */
+void *data_pointer(libr_section *scn, libr_data *data)
+{
+ return data->d_buf;
+}
+
+/*
+ * Return the size of the data in the section
+ */
+size_t data_size(libr_section *scn, libr_data *data)
+{
+ return data->d_size;
+}
+
+/*
+ * Return the next section in the ELF file
+ */
+libr_section *next_section(libr_file *file_handle, libr_section *scn)
+{
+ return elf_nextscn(file_handle->elf_handle, scn);
+}
+
+/*
+ * Retrieve the name of a section
+ */
+char *section_name(libr_file *file_handle, libr_section *scn)
+{
+ char *name = NULL;
+ GElf_Shdr shdr;
+ GElf_Ehdr ehdr;
+
+ if(gelf_getehdr(file_handle->elf_handle, &ehdr) == NULL)
+ return NULL;
+ if(gelf_getshdr(scn, &shdr) != &shdr)
+ return NULL;
+ if((name = elf_strptr(file_handle->elf_handle, ehdr.e_shstrndx, shdr.sh_name)) == NULL)
+ return NULL;
+ return strdup(name);
+}
+
+/*
+ * Initialize the libelf backend
+ */
+void initialize_backend(void)
+{
+ if(elf_version(EV_CURRENT) == EV_NONE)
+ return; //errx(EX_SOFTWARE, "ELF library initialization failed: %s", elf_errmsg(-1));
+}
diff --git a/src/libr-elf.h b/src/libr-elf.h
new file mode 100644
index 0000000..4c632e8
--- /dev/null
+++ b/src/libr-elf.h
@@ -0,0 +1,24 @@
+#ifndef __LIBR_ELF_H
+#define __LIBR_ELF_H
+
+/* Handle ELF files */
+#include <libelf.h>
+#include <gelf.h>
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+typedef struct _libr_file {
+ int fd_handle;
+ Elf *elf_handle;
+ size_t file_size;
+ libr_access_t access;
+ unsigned int version;
+} libr_file;
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+/* for a clean internal API */
+typedef Elf_Scn libr_section;
+typedef Elf_Data libr_data;
+
+#endif /* __LIBR_ELF_H */
diff --git a/src/libr-gtk.c b/src/libr-gtk.c
new file mode 100644
index 0000000..f746aa8
--- /dev/null
+++ b/src/libr-gtk.c
@@ -0,0 +1,443 @@
+/*
+ *
+ * Copyright (c) 2008-2009 Erich Hoover
+ *
+ * libr GTK support - Convenience functions for using resources in GTK applications
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+/* Include compile-time parameters */
+#include "config.h"
+
+#include "libr.h"
+#include "libr-gtk.h"
+#include "libr-icons.h"
+#include "tempfiles.h"
+
+/* For loading GTK/GDK images */
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <glib.h>
+
+/* For loading GLADE files */
+#include <glade/glade.h>
+
+/* For loading GTK+ Builder files */
+#include <gtk/gtk.h>
+
+/* For malloc/free */
+#include <stdlib.h>
+
+/* For string handling */
+#include <string.h>
+
+typedef gchar * (*GladeFileCallback)(GladeXML *, const gchar *, guint *);
+GladeFileCallback glade_set_file_callback(GladeFileCallback callback, gpointer user_data);
+
+/* Use weak binding for all glade and GTK+ requirements */
+#pragma weak glade_set_file_callback
+
+#pragma weak gtk_window_set_default_icon_list
+#pragma weak gdk_pixbuf_loader_get_pixbuf
+#pragma weak gtk_builder_add_from_string
+#pragma weak gdk_pixbuf_loader_set_size
+#pragma weak g_type_check_instance_cast
+#pragma weak gtk_builder_add_from_file
+#pragma weak glade_xml_new_from_buffer
+#pragma weak gdk_pixbuf_loader_write
+#pragma weak gdk_pixbuf_loader_close
+#pragma weak gdk_pixbuf_loader_new
+#pragma weak g_signal_connect_data
+#pragma weak g_signal_connect
+#pragma weak gtk_builder_new
+#pragma weak g_object_unref
+#pragma weak glade_xml_new
+#pragma weak g_list_append
+#pragma weak glade_init
+#pragma weak gtk_init
+#pragma weak g_free
+
+#define GLADE_SECTION ".glade"
+#define BUILDER_SECTION ".ui"
+
+/*
+ * Handle the resource request from libglade
+ */
+gchar *libr_glade_read_resource(GladeXML *gladefile, const gchar *filename, guint *size, gpointer user_data)
+{
+ return libr_malloc((libr_file *) user_data, (char *) filename, (size_t *) size);
+}
+
+/*
+ * Handle the resource request from GtkBuilder
+ */
+gboolean libr_gtk_read_resource(GtkBuilder *builder, const gchar *filename, gchar **data, gsize *size, GError **error, gpointer user_data)
+{
+ if(data == NULL)
+ return FALSE;
+ *data = libr_malloc((libr_file *) user_data, (char *) filename, (size_t *) size);
+ if(*data == NULL)
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Load the libglade resource appropriately for the currently installed version
+ * (AKA, hurray hacks!)
+ */
+GladeXML *libr_new_glade(libr_file *handle, char *gladefile, size_t gladefile_size)
+{
+ if(glade_set_file_callback) /* The not-yet (ever?) existing way */
+ {
+ /* Register a callback for libglade to load our resources */
+ if(glade_set_file_callback((GladeFileCallback) libr_glade_read_resource, handle) != NULL)
+ printf("warning: over-wrote an application callback!\n");
+ /* Initialize libglade almost as usual, just use a buffer instead of a file */
+ return glade_xml_new_from_buffer(gladefile, gladefile_size, NULL, NULL);
+ }
+ else /* The hacky way */
+ {
+ char *glade_file[PATH_MAX];
+ GladeXML *ret = NULL;
+ char *temp_folder;
+
+ temp_folder = libr_extract_resources(handle);
+ if(temp_folder == NULL)
+ return NULL;
+ strcpy((char*)glade_file, temp_folder);
+ strcat((char*)glade_file, "/");
+ strcat((char*)glade_file, GLADE_SECTION);
+ ret = glade_xml_new((char*)glade_file, NULL, NULL);
+ if(ret == NULL)
+ cleanup_folder(temp_folder);
+ else
+ register_folder_cleanup(temp_folder);
+ return ret;
+ }
+}
+
+/*
+ * Load the GtkBuilder resource appropriately for the currently installed version
+ * (AKA, hurray hacks!)
+ */
+int libr_new_builder(libr_file *handle, char *builderfile, size_t builderfile_size, GtkBuilder *builder)
+{
+ /* Register a callback for GtkBuilder to load our resources */
+ if(g_signal_connect(builder, "load-resource", (GCallback) libr_gtk_read_resource, handle))
+ {
+ /* Initialize GtkBuilder almost as usual, just use a buffer instead of a file */
+ if(gtk_builder_add_from_string(builder, builderfile, builderfile_size, NULL) == 0)
+ return false;
+ return true;
+ }
+ else /* The hacky way */
+ {
+ char *builder_file[PATH_MAX];
+ char *temp_folder;
+ int ret = false;
+
+ temp_folder = libr_extract_resources(handle);
+ if(temp_folder == NULL)
+ return false;
+ strcpy((char*)builder_file, temp_folder);
+ strcat((char*)builder_file, "/");
+ strcat((char*)builder_file, BUILDER_SECTION);
+ ret = gtk_builder_add_from_file(builder, (char*)builder_file, NULL);
+ if(ret == 0)
+ cleanup_folder(temp_folder);
+ else
+ register_folder_cleanup(temp_folder);
+ g_free(temp_folder);
+ return (ret != 0);
+ }
+}
+
+/*
+ * Return a GTK icon list
+ */
+EXPORT_FN IconList *libr_gtk_iconlist(libr_file *handle)
+{
+ int sizes[] = {16, 32, 48, 96, 128};
+ IconList *icons = NULL;
+ GdkPixbuf *icon = NULL;
+ int sizes_len = 5, i;
+
+ if(handle == NULL)
+ {
+ /* Must pass a file handle to obtain the icons from */
+ return NULL;
+ }
+ if(gtk_init == NULL)
+ {
+ /* GTK+ was not linked with the application */
+ return false;
+ }
+ /* Go through the list of GTK "required" image sizes and build the icons */
+ for(i=0;i<sizes_len;i++)
+ {
+ libr_icon *icon_handle = libr_icon_geticon_bysize(handle, sizes[i]);
+ GdkPixbufLoader *stream = gdk_pixbuf_loader_new();
+ char *iconfile = NULL;
+ size_t iconfile_size;
+
+ if(icon_handle == NULL)
+ {
+ /* Failed to find an icon */
+ printf("Failed to find an icon\n");
+ continue;
+ }
+ iconfile = libr_icon_malloc(icon_handle, &iconfile_size);
+ if(iconfile == NULL)
+ {
+ /* Failed to obtain embedded icon */
+ continue;
+ }
+ libr_icon_close(icon_handle);
+ /* TODO: Use the "size-prepared" signal to properly scale the width and height
+void user_function (GdkPixbufLoader *loader, gint width, gint height, gpointer user_data)
+ */
+ gdk_pixbuf_loader_set_size(stream, sizes[i], sizes[i]);
+ if(!gdk_pixbuf_loader_write(stream, (unsigned char *)iconfile, iconfile_size, NULL))
+ {
+ /* Failed to process image */
+ continue;
+ }
+ if(!gdk_pixbuf_loader_close(stream, NULL))
+ {
+ /* Failed to create image */
+ continue;
+ }
+ icon = gdk_pixbuf_loader_get_pixbuf(stream);
+ if(icon == NULL)
+ {
+ /* Failed to convert image to pixbuf */
+ continue;
+ }
+ icons = g_list_append(icons, icon);
+ }
+ return icons;
+}
+
+/*
+ * Shared GtkBuilder resource loading
+ */
+GtkBuilder *libr_gtk_load_internal(libr_file *handle, char *resource_name)
+{
+ GtkBuilder *builder = NULL;
+ size_t builder_length;
+ char *builder_data;
+
+ /* Obtain the GtkBuilder XML definition */
+ builder_data = libr_malloc(handle, resource_name, &builder_length);
+ if(builder_data == NULL)
+ {
+ /* Failed to obtain embedded GtkBuilder definition file */
+ goto failed;
+ }
+ /* Setup the GtkBuilder environment */
+ builder = gtk_builder_new();
+ if(builder == NULL)
+ goto failed;
+ if(!libr_new_builder(handle, builder_data, builder_length, builder))
+ {
+ /* Failed to build interface from resource file */
+ g_object_unref(G_OBJECT(builder));
+ goto failed;
+ }
+failed:
+ free(builder_data);
+ return builder;
+}
+
+/*
+ * Load the requested GtkBuilder resource and any applicable icons
+ */
+EXPORT_FN int libr_gtk_load(BuilderHandle **gtk_ret, char *resource_name)
+{
+ libr_file *handle;
+ int ret = false;
+
+ if(gtk_ret == NULL)
+ {
+ /* Why on earth would you call this without obtaining the handle to the resource? */
+ return false;
+ }
+ if(gtk_builder_new == NULL)
+ {
+ /* GtkBuilder was not linked with the application */
+ return false;
+ }
+ /* Obtain the handle to the executable */
+ if((handle = libr_open(NULL, LIBR_READ)) == NULL)
+ {
+ /* "Failed to open this executable (%s) for resources", progname() */
+ return false;
+ }
+ register_internal_handle(handle);
+ *gtk_ret = libr_gtk_load_internal(handle, resource_name);
+ if(*gtk_ret == NULL)
+ goto failed;
+ ret = true;
+failed:
+ if(!ret)
+ libr_close(handle);
+ return ret;
+}
+
+/*
+ * Automatically load the ".ui" GtkBuilder resource and any applicable icons
+ */
+EXPORT_FN int libr_gtk_autoload(BuilderHandle **gtk_ret, IconList **icons_ret, int set_default_icon)
+{
+ GList *icons = NULL;
+ libr_file *handle;
+ int ret = false;
+
+ if(gtk_ret == NULL)
+ {
+ /* Why on earth would you call this without obtaining the handle to the resource? */
+ return false;
+ }
+ if(gtk_builder_new == NULL)
+ {
+ /* GtkBuilder was not linked with the application */
+ return false;
+ }
+ /* Obtain the handle to the executable */
+ if((handle = libr_open(NULL, LIBR_READ)) == NULL)
+ {
+ /* "Failed to open this executable (%s) for resources", progname() */
+ return false;
+ }
+ register_internal_handle(handle);
+ /* Obtain the icons from the ELF binary */
+ icons = libr_gtk_iconlist(handle);
+ /* Set the embedded icons as the default icon list (if requested) */
+ if(icons != NULL && set_default_icon)
+ gtk_window_set_default_icon_list(icons);
+ *gtk_ret = libr_gtk_load_internal(handle, BUILDER_SECTION);
+ if(*gtk_ret == NULL)
+ goto failed;
+ if(icons_ret)
+ *icons_ret = icons;
+ ret = true;
+failed:
+ if(!ret)
+ libr_close(handle);
+ return ret;
+}
+
+/*
+ * Shared libglade resource loading
+ */
+GladeXML *libr_glade_load_internal(libr_file *handle, char *resource_name)
+{
+ GladeXML *glade = NULL;
+ size_t glade_length;
+ char *glade_data;
+
+ /* Obtain the GLADE XML definition */
+ glade_data = libr_malloc(handle, resource_name, &glade_length);
+ if(glade_data == NULL)
+ {
+ /* Failed to obtain embedded glade file */
+ goto failed;
+ }
+ /* Initialize libglade appropriate for the available version */
+ glade = libr_new_glade(handle, glade_data, glade_length);
+ if(glade == NULL)
+ {
+ /* Failed to initialize embedded glade file */
+ goto failed;
+ }
+failed:
+ free(glade_data);
+ return glade;
+}
+
+/*
+ * Load the requested libglade resource and any applicable icons
+ */
+EXPORT_FN int libr_glade_load(GladeHandle **glade_ret, char *resource_name)
+{
+ libr_file *handle;
+ int ret = false;
+
+ if(glade_ret == NULL)
+ {
+ /* Why on earth would you call this without obtaining the handle to the resource? */
+ return false;
+ }
+ if(glade_init == NULL)
+ {
+ /* libglade was not linked with the application */
+ return false;
+ }
+ /* Obtain the handle to the executable */
+ if((handle = libr_open(NULL, LIBR_READ)) == NULL)
+ {
+ /* "Failed to open this executable (%s) for resources", progname() */
+ return false;
+ }
+ register_internal_handle(handle);
+ *glade_ret = libr_glade_load_internal(handle, resource_name);
+ if(*glade_ret == NULL)
+ goto failed;
+ ret = true;
+failed:
+ if(!ret)
+ libr_close(handle);
+ return ret;
+}
+
+/*
+ * Automatically load the ".glade" resource and any applicable icons
+ */
+EXPORT_FN int libr_glade_autoload(GladeHandle **glade_ret, IconList **icons_ret, int set_default_icon)
+{
+ libr_file *handle = NULL;
+ GList *icons = NULL;
+
+ if(glade_ret == NULL)
+ {
+ /* Why on earth would you call this without obtaining the handle to the resource? */
+ return false;
+ }
+ if(glade_init == NULL)
+ {
+ /* libglade was not linked with the application */
+ return false;
+ }
+ /* Obtain the handle to the executable */
+ if((handle = libr_open(NULL, LIBR_READ)) == NULL)
+ {
+ /* "Failed to open this executable (%s) for resources", progname() */
+ return false;
+ }
+ register_internal_handle(handle);
+ icons = libr_gtk_iconlist(handle);
+ /* Set the embedded icons as the default icon list (if requested) */
+ if(icons != NULL && set_default_icon)
+ gtk_window_set_default_icon_list(icons);
+ /* Return the libglade and icon handles for the application */
+ *glade_ret = libr_glade_load_internal(handle, GLADE_SECTION);
+ if(icons_ret)
+ *icons_ret = icons;
+ return true;
+}
diff --git a/src/libr-gtk.h b/src/libr-gtk.h
new file mode 100644
index 0000000..fa6ba1b
--- /dev/null
+++ b/src/libr-gtk.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright (c) 2008 Erich Hoover
+ *
+ * libr-gtk - Convenience support for GTK+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+#ifndef __LIBR_GTK_H
+#define __LIBR_GTK_H
+
+#include "libr.h"
+
+#ifndef GLADE_H
+ typedef void GladeHandle;
+#else
+ typedef GladeXML GladeHandle;
+#endif
+#ifndef __GTK_BUILDER_H__
+ typedef void BuilderHandle;
+#else
+ typedef GtkBuilder BuilderHandle;
+#endif
+#ifndef __G_LIB_H__
+ typedef void IconList;
+#else
+ typedef GList IconList;
+#endif
+
+/* GTK Convenience API */
+IconList *libr_gtk_iconlist(libr_file *handle);
+int libr_gtk_autoload(BuilderHandle **gtk_ret, IconList **icons_ret, int set_default_icon);
+int libr_gtk_load(BuilderHandle **gtk_ret, char *resource_name);
+int libr_glade_autoload(GladeHandle **glade_ret, IconList **icons_ret, int set_default_icon);
+int libr_glade_load(GladeHandle **glade_ret, char *resource_name);
+
+#endif /* __LIBR_GTK_H */
+
diff --git a/src/libr-i18n.c b/src/libr-i18n.c
new file mode 100644
index 0000000..25e5664
--- /dev/null
+++ b/src/libr-i18n.c
@@ -0,0 +1,84 @@
+/*
+ *
+ * Copyright (c) 2009 Erich Hoover
+ *
+ * libr i18n - Add language resources into ELF binaries
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+/* Include compile-time parameters */
+#include "config.h"
+
+#include "libr-i18n.h"
+#include "tempfiles.h"
+
+/* Internationalization support */
+#include <locale.h>
+
+/* For string handling */
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Extract the internationalization resources from the binary
+ * and setup gettext with the extracted folder.
+ */
+EXPORT_FN int libr_i18n_load(libr_file *handle, const char *domain)
+{
+ char *temp_folder;
+ int ret = true;
+
+ temp_folder = libr_extract_resources(handle);
+ if(temp_folder == NULL)
+ return false;
+ if(!setlocale(LC_ALL, ""))
+ ret = false;
+ if(!bindtextdomain(domain, temp_folder))
+ ret = false;
+ if(!textdomain(domain))
+ ret = false;
+ if(!ret)
+ cleanup_folder(temp_folder);
+ else
+ register_folder_cleanup(temp_folder);
+ return ret;
+}
+
+EXPORT_FN int libr_i18n_autoload(const char *domain)
+{
+ libr_file *handle;
+
+ /* Obtain the handle to the executable */
+ if((handle = libr_open(NULL, LIBR_READ)) == NULL)
+ {
+ /* "Failed to open this executable (%s) for resources", progname() */
+ return false;
+ }
+ /* Obtain the language files from the ELF binary */
+ if(!libr_i18n_load(handle, domain))
+ {
+ /* "Failed to load language resources!" */
+ goto failed;
+ }
+
+failed:
+ libr_close(handle);
+ return true;
+}
diff --git a/src/libr-i18n.h b/src/libr-i18n.h
new file mode 100644
index 0000000..5b61546
--- /dev/null
+++ b/src/libr-i18n.h
@@ -0,0 +1,14 @@
+#ifndef __LIBR_I18N_H
+#define __LIBR_I18N_H
+
+#include "libr.h"
+#include "gettext.h"
+
+#define _(string) gettext(string)
+/* for strings used in structures (must manually call gettext!): */
+#define N_(string) (string)
+
+int libr_i18n_autoload(const char *domain);
+int libr_i18n_load(libr_file *handle, const char *domain);
+
+#endif /* __LIBR_I18N_H */
diff --git a/src/libr-icons.c b/src/libr-icons.c
new file mode 100644
index 0000000..18dc536
--- /dev/null
+++ b/src/libr-icons.c
@@ -0,0 +1,643 @@
+/*
+ *
+ * Copyright (c) 2008-2011 Erich Hoover
+ *
+ * libr icons - Add icon resources into ELF binaries
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+/* Include compile-time parameters */
+#include "config.h"
+
+#include "libr-icons.h"
+
+/* For "one canvas" SVG documents */
+#include "onecanvas.h"
+
+/* For string manipulation */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+/* For handling files */
+#include <sys/stat.h>
+
+/* For C99 number types */
+#include <stdint.h>
+
+#define ICON_SECTION ".icon"
+#define TERM_LEN 1
+
+#define OFFSET_ENTRIES 0
+#define OFFSET_GUID OFFSET_ENTRIES+sizeof(uint32_t)
+
+#if defined(__i386)
+ #define ID12FORMAT "%012llx"
+#elif defined(__x86_64)
+ #define ID12FORMAT "%012lx"
+#else
+ #define ID12FORMAT "%012lx"
+ #warning "string formatting may be incorrect on this architecture."
+#endif
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+typedef uint32_t ID8;
+typedef uint16_t ID4;
+typedef struct {uint64_t p:48;} __attribute__((__packed__)) ID12;
+
+typedef struct {
+ ID8 g1;
+ ID4 g2;
+ ID4 g3;
+ ID4 g4;
+ ID12 g5;
+} __attribute__((__packed__)) UUID;
+
+typedef struct {
+ char *name;
+ size_t offset;
+ size_t entry_size;
+ libr_icontype_t type;
+ unsigned int icon_size;
+} iconentry;
+
+typedef struct{
+ size_t size;
+ char *buffer;
+ iconentry entry;
+} iconlist;
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+/*
+ * Decode a UUID to its binary representation
+ *
+ * NOTE: The last 12-bit parameter cannot be obtained using (uint64_t *) with
+ * some versions of GCC using some optimization levels. This problem is very
+ * frustrating to debug, so I do not recommend playing with it yourself.
+ */
+UUID guid_decode(char *guid)
+{
+ UUID id = {0x00000000, 0x0000, 0x0000, 0x0000, {0x000000000000} };
+ uint64_t tmp12;
+
+ sscanf(guid, "%08x-%04hx-%04hx-%04hx-" ID12FORMAT, &id.g1, &id.g2, &id.g3, &id.g4, &tmp12);
+ id.g5.p = tmp12;
+ return id;
+}
+
+/*
+ * Return the size of the file represented by the file stream
+ */
+off_t fsize(FILE *handle)
+{
+ struct stat file_stat;
+
+ if(fstat(fileno(handle), &file_stat) == ERROR)
+ return ERROR;
+ return file_stat.st_size;
+}
+
+/*
+ * Create a new icon handle
+ */
+libr_icon *new_icon_handle(libr_icontype_t type, unsigned int icon_size, char *buffer, size_t buffer_size)
+{
+ libr_icon *icon_handle = (libr_icon *) malloc(sizeof(libr_icon));
+
+ icon_handle->type = type;
+ icon_handle->buffer = buffer;
+ icon_handle->icon_size = icon_size;
+ icon_handle->buffer_size = buffer_size;
+ return icon_handle;
+}
+
+/*
+ * Obtain an existing icon resource list
+ */
+int get_iconlist(libr_file *file_handle, iconlist *icons)
+{
+ if(icons == NULL)
+ {
+ /* Need to be able to return SOMETHING */
+ return false;
+ }
+ /* Obtain the icon resource list */
+ icons->buffer = libr_malloc(file_handle, ICON_SECTION, &(icons->size));
+ if(icons->buffer == NULL)
+ return false;
+ return true;
+}
+
+/*
+ * Get the next entry in an icon resource list
+ */
+iconentry *get_nexticon(iconlist *icons, iconentry *last_entry)
+{
+ size_t i;
+
+ /* The icon list is needed both for the data buffer and for a call-specific iconentry instance */
+ if(icons == NULL)
+ return NULL;
+ /* If this is the first call (last_entry == NULL) then return the first entry */
+ if(last_entry == NULL)
+ icons->entry.offset = sizeof(uint32_t)+sizeof(UUID);
+ else
+ icons->entry.offset += icons->entry.entry_size;
+ /* Check to see if we've run out of entries */
+ if(icons->entry.offset >= icons->size)
+ return NULL;
+ i = icons->entry.offset;
+ memcpy(&(icons->entry.entry_size), &(icons->buffer[i]), sizeof(uint32_t));
+ i += sizeof(uint32_t);
+ icons->entry.type = icons->buffer[i];
+ i += sizeof(unsigned char);
+ switch(icons->entry.type)
+ {
+ case LIBR_SVG:
+ icons->entry.icon_size = 0;
+ icons->entry.name = &(icons->buffer[i]);
+ break;
+ case LIBR_PNG:
+ memcpy(&(icons->entry.icon_size), &(icons->buffer[i]), sizeof(uint32_t));
+ i += sizeof(uint32_t);
+ icons->entry.name = &(icons->buffer[i]);
+ break;
+ default:
+ /* Invalid entry type */
+ return NULL;
+ }
+ return &(icons->entry);
+}
+
+/*
+ * Free an icon handle
+ */
+EXPORT_FN int libr_icon_close(libr_icon *icon)
+{
+ if(icon == NULL)
+ return false;
+ if(icon->buffer == NULL)
+ return false;
+ free(icon->buffer);
+ free(icon);
+ return true;
+}
+
+/*
+ * Read an icon resource from an ELF file by name
+ */
+EXPORT_FN libr_icon *libr_icon_geticon_byname(libr_file *handle, char *icon_name)
+{
+ iconentry *entry = NULL;
+ libr_icon *icon = NULL;
+ size_t buffer_size = 0;
+ unsigned int icon_size;
+ libr_icontype_t type;
+ char *buffer = NULL;
+ int inlist = false;
+ iconlist icons;
+
+ if(!get_iconlist(handle, &icons))
+ {
+ /* Failed to obtain a list of ELF icons */
+ return NULL;
+ }
+ /* Look for the icon name in the entry list */
+ while((entry = get_nexticon(&icons, entry)) != NULL)
+ {
+ if(!strcmp(entry->name, icon_name))
+ {
+ type = entry->type;
+ icon_size = entry->icon_size;
+ inlist = true;
+ break;
+ }
+ }
+ if(!inlist)
+ {
+ /* Could not find icon name in the list of icons */
+ return false;
+ }
+ /* Get the icon from the ELF binary */
+ if(!libr_size(handle, icon_name, &buffer_size))
+ {
+ /* Failed to obtain ELF icon size */
+ return NULL;
+ }
+ /* Allocate memory for the icon */
+ buffer = (char *) malloc(buffer_size);
+ if(buffer == NULL)
+ {
+ /* Failed to allocate memory for icon */
+ return NULL;
+ }
+ /* Get the compressed icon from the ELF file */
+ if(!libr_read(handle, icon_name, buffer))
+ {
+ /* Failed to obtain ELF icon */
+ goto geticon_byname_complete;
+ }
+ icon = new_icon_handle(type, icon_size, buffer, buffer_size);
+
+geticon_byname_complete:
+ if(icon == NULL)
+ free(buffer);
+ return icon;
+}
+
+/*
+ * Read an icon resource from an ELF file by the square icon size
+ */
+EXPORT_FN libr_icon *libr_icon_geticon_bysize(libr_file *handle, unsigned int iconsize)
+{
+ unsigned int closest_id = 0, i = 0, j = 0;
+ int found_png = false, found_svg = false;
+ unsigned long closest_size = 0;
+ iconentry *entry = NULL;
+ iconlist icons;
+
+ if(!get_iconlist(handle, &icons))
+ {
+ /* Failed to obtain a list of ELF icons */
+ return NULL;
+ }
+ /* Look for the closest size match, ignore SVG in case there are multiple icons */
+ while((entry = get_nexticon(&icons, entry)) != NULL)
+ {
+ if(entry->type == LIBR_SVG)
+ found_svg = true;
+ if(entry->type == LIBR_PNG)
+ {
+ if(j == 0)
+ {
+ closest_size = entry->icon_size;
+ found_png = true;
+ }
+ if(abs(iconsize-entry->icon_size) < closest_size)
+ {
+ closest_size = entry->icon_size;
+ closest_id = i;
+ }
+ j++;
+ }
+ i++;
+ }
+ /* If any PNG files were found then use the file if:
+ * 1) There are no SVG files <OR>
+ * 2) The PNG is an EXACT size match
+ */
+ if(found_png)
+ {
+ i=0;
+ entry = NULL;
+ while((entry = get_nexticon(&icons, entry)) != NULL)
+ {
+ if(i == closest_id)
+ {
+ if(entry->icon_size == iconsize || !found_svg)
+ return libr_icon_geticon_byname(handle, entry->name);
+ break;
+ }
+ i++;
+ }
+ }
+ /* Otherwise use the SVG (provided that there is one) */
+ if(found_svg)
+ {
+ entry = NULL;
+ while((entry = get_nexticon(&icons, entry)) != NULL)
+ {
+ if(entry->type == LIBR_SVG)
+ {
+ libr_icon *icon = libr_icon_geticon_byname(handle, entry->name);
+ if (icon) {
+ libr_icon *icon_onecanvas;
+ char *buffer;
+
+ /* should we report the requested size for SVG? */
+ icon->icon_size = iconsize;
+
+ /* if the SVG is a "one canvas" document then extract the correctly sized icon */
+ if((buffer = onecanvas_geticon_bysize(icon->buffer, iconsize)) != NULL)
+ {
+ libr_icon_close(icon);
+ icon_onecanvas = new_icon_handle(LIBR_SVG, iconsize, buffer, strlen(buffer));
+ return icon_onecanvas;
+ }
+ }
+ return icon;
+ }
+ }
+ }
+ /* Give up */
+ return NULL;
+}
+
+/*
+ * Obtains the icon UUID for the ELF file
+ */
+EXPORT_FN int libr_icon_getuuid(libr_file *handle, char *uuid)
+{
+ UUID id = {0x00000000, 0x0000, 0x0000, 0x0000, {0x000000000000} };
+ iconlist icons;
+
+ if(!get_iconlist(handle, &icons))
+ {
+ /* Failed to obtain the list of ELF icons */
+ return false;
+ }
+ /* Now store the GUID to the return string */
+ memcpy(&id, &(icons.buffer[OFFSET_GUID]), sizeof(UUID));
+ snprintf(uuid, GUIDSTR_LENGTH, "%08x-%04hx-%04hx-%04hx-" ID12FORMAT "\n", id.g1, id.g2, id.g3, id.g4, (uint64_t) id.g5.p);
+ free(icons.buffer);
+ return true;
+}
+EXPORT_FN int libr_icon_getguid(libr_file *handle, char *uuid) ALIAS_FN(libr_icon_getuuid);
+
+/*
+ * Allocate a buffer containing the data of an icon
+ */
+EXPORT_FN char *libr_icon_malloc(libr_icon *icon, size_t *size)
+{
+ char *iconfile = NULL;
+
+ if(size == NULL)
+ {
+ /* No return size passed */
+ return NULL;
+ }
+ if(!libr_icon_size(icon, size))
+ {
+ /* Failed to obtain embedded icon file size */
+ return NULL;
+ }
+ iconfile = (char *) malloc(*size);
+ if(!libr_icon_read(icon, iconfile))
+ {
+ /* Failed to obtain embedded icon file */
+ free(iconfile);
+ return NULL;
+ }
+ return iconfile;
+}
+
+/*
+ * Create an icon resource to represent a file on the hard disk
+ */
+EXPORT_FN libr_icon *libr_icon_newicon_byfile(libr_icontype_t type, unsigned int icon_size, char *icon_file)
+{
+ libr_icon *icon_handle = NULL;
+ size_t len, buffer_size = 0;
+ char *buffer = NULL;
+ FILE *handle = NULL;
+
+ /* Open a handle to the icon file */
+ if((handle = fopen(icon_file, "r")) == NULL)
+ {
+ /* Failed to open icon file */
+ return NULL;
+ }
+ /* Get the size of the icon file */
+ if((buffer_size = fsize(handle)) == ERROR)
+ {
+ /* Failed to obtain the icon's file size */
+ return NULL;
+ }
+ /* Allocate a buffer for the uncompressed icon */
+ buffer = (char *) malloc(buffer_size);
+ if(buffer == NULL)
+ {
+ /* Failed to allocate a buffer for the icon data */
+ return NULL;
+ }
+ /* Read the uncompressed image from the disk */
+ if((len = fread(buffer, 1, buffer_size, handle)) <= 0)
+ {
+ /* Failed to read icon from disk */
+ goto newicon_complete;
+ }
+ fclose(handle);
+ if(len != buffer_size)
+ {
+ /* Failed to read the entire icon */
+ goto newicon_complete;
+ }
+ /* Allocate the icon handle */
+ icon_handle = new_icon_handle(type, icon_size, buffer, buffer_size);
+
+newicon_complete:
+ if(icon_handle == NULL)
+ free(buffer);
+ return icon_handle;
+}
+
+/*
+ * Copy the icon resource into a buffer
+ */
+EXPORT_FN int libr_icon_read(libr_icon *icon, char *buffer)
+{
+ if(icon == NULL)
+ return false;
+ memcpy(buffer, icon->buffer, icon->buffer_size);
+ return true;
+}
+
+/*
+ * Get the memory size of an icon resource
+ */
+EXPORT_FN int libr_icon_size(libr_icon *icon, size_t *size)
+{
+ if(icon == NULL)
+ return false;
+ *size = icon->buffer_size;
+ return true;
+}
+
+/*
+ * Save the icon resource to a file
+ */
+EXPORT_FN int libr_icon_save(libr_icon *icon, char *filename)
+{
+ FILE *file = NULL;
+ int ret = false;
+ size_t len;
+
+ if(icon == NULL)
+ return false;
+ /* Open the file to store the image */
+ if((file = fopen(filename, "w")) == NULL)
+ {
+ /* Failed to open file to write the icon */
+ return false;
+ }
+ /* Store the uncompressed icon to disk */
+ if((len = fwrite(icon->buffer, 1, icon->buffer_size, file)) <= 0)
+ {
+ /* Failed to write output file */
+ goto saveicon_complete;
+ }
+ if(len != icon->buffer_size)
+ {
+ /* Did not write the entire file */
+ goto saveicon_complete;
+ }
+ ret = true;
+
+saveicon_complete:
+ /* Close remaining resources */
+ fclose(file);
+ return ret;
+}
+
+/*
+ * Sets the icon GUID for the ELF file
+ */
+EXPORT_FN int libr_icon_setuuid(libr_file *handle, char *guid)
+{
+ int ret = false;
+ iconlist icons;
+ UUID id;
+ int i;
+
+ /* First check the GUID string */
+ for(i=0;i<strlen(guid);i++)
+ {
+ if(!isxdigit(guid[i]))
+ {
+ if(guid[i] == '-' && (i == 8 || i == 13 || i == 18 || i == 23))
+ continue;
+ /* not a valid GUID string */
+ return false;
+ }
+ }
+ id = guid_decode(guid);
+ /* Now check existing resources */
+ if(!get_iconlist(handle, &icons))
+ {
+ /* No icons exist in the file, create a new icon section with the GUID */
+ uint32_t entries = 0;
+
+ icons.size = sizeof(uint32_t)+sizeof(UUID);
+ icons.buffer = (char *) malloc(icons.size);
+ memcpy(&(icons.buffer[OFFSET_ENTRIES]), &entries, sizeof(uint32_t));
+ }
+ /* Set the GUID and write the resource */
+ if(!libr_write(handle, ICON_SECTION, icons.buffer, icons.size, LIBR_UNCOMPRESSED, LIBR_OVERWRITE))
+ {
+ /* failed to write icon resource */
+ goto setguid_complete;
+ }
+ ret = true;
+
+setguid_complete:
+ free(icons.buffer);
+ return ret;
+}
+EXPORT_FN int libr_icon_setguid(libr_file *handle, char *uuid) ALIAS_FN(libr_icon_setuuid);
+
+/*
+ * Add an icon resource to an ELF file
+ */
+EXPORT_FN int libr_icon_write(libr_file *handle, libr_icon *icon, char *icon_name, libr_overwrite_t overwrite)
+{
+ size_t entry_size, i;
+ iconentry *entry = NULL;
+ iconlist icons;
+ int ret = false;
+
+ /* Check to make sure the user did not make a poor name choice */
+ if(!strcmp(icon_name, ICON_SECTION))
+ {
+ /* ".icon" is a reserved section name */
+ return false;
+
+ }
+ /* Check to make sure the file supports icon resources */
+ if(!get_iconlist(handle, &icons))
+ {
+ /* A GUID must be set first */
+ return false;
+ }
+ /* First add the icon as a new named section */
+ if(!libr_write(handle, icon_name, icon->buffer, icon->buffer_size, LIBR_COMPRESSED, overwrite))
+ {
+ /* Failed to add the icon as a resource */
+ goto writeicon_complete;
+ }
+ /* Look to see if the icon already has an entry */
+ while((entry = get_nexticon(&icons, entry)) != NULL)
+ {
+ if(!strcmp(entry->name, icon_name))
+ {
+ ret = true;
+ goto writeicon_complete;
+ }
+ }
+ /* Now add the icon to the list of icon resources in the ".icon" section */
+ switch(icon->type)
+ {
+ case LIBR_SVG:
+ entry_size = sizeof(uint32_t)+sizeof(unsigned char)+strlen(icon_name)+TERM_LEN;
+ break;
+ case LIBR_PNG:
+ entry_size = sizeof(uint32_t)+sizeof(unsigned char)+sizeof(uint32_t)+strlen(icon_name)+TERM_LEN;
+ break;
+ default:
+ /* Unhandled icon type */
+ goto writeicon_complete;
+ }
+ icons.buffer = (char *) realloc(icons.buffer, icons.size+entry_size);
+ if(icons.buffer == NULL)
+ {
+ /* Failed to expand memory size */
+ goto writeicon_complete;
+ }
+ i = icons.size;
+ memcpy(&(icons.buffer[i]), &entry_size, sizeof(uint32_t));
+ i+=sizeof(uint32_t);
+ icons.buffer[i] = icon->type;
+ i+=sizeof(unsigned char);
+ if(icon->type == LIBR_PNG)
+ {
+ memcpy(&(icons.buffer[i]), &icon->icon_size, sizeof(uint32_t));
+ i+=sizeof(uint32_t);
+ }
+ memcpy(&(icons.buffer[i]), icon_name, strlen(icon_name));
+ i+=strlen(icon_name);
+ icons.buffer[i] = '\0';
+ icons.size += entry_size;
+ if(i != (icons.size-1))
+ printf("Really dangerous, buffer size mismatch!\n");
+ /* Write the updated icon table */
+ if(!libr_write(handle, ICON_SECTION, icons.buffer, icons.size, LIBR_UNCOMPRESSED, LIBR_OVERWRITE))
+ {
+ /* failed to write icon resource */
+ goto writeicon_complete;
+ }
+ ret = true;
+
+writeicon_complete:
+ if(icons.buffer)
+ free(icons.buffer);
+ return ret;
+}
diff --git a/src/libr-icons.h b/src/libr-icons.h
new file mode 100644
index 0000000..779fef3
--- /dev/null
+++ b/src/libr-icons.h
@@ -0,0 +1,201 @@
+/*
+ *
+ * Copyright (c) 2008-2010 Erich Hoover
+ *
+ * libr-icons - Handle icon resources in ELF binaries
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+#ifndef __LIBR_ICONS_H
+#define __LIBR_ICONS_H
+
+#include "libr.h"
+
+typedef enum {
+ LIBR_SVG = 0,
+ LIBR_PNG = 1
+} libr_icontype_t;
+
+#define UUIDSTR_LENGTH 37
+#define GUIDSTR_LENGTH UUIDSTR_LENGTH
+
+#ifdef __LIBR_BUILD__
+ typedef struct {
+ char *buffer;
+ size_t buffer_size;
+ libr_icontype_t type;
+ unsigned int icon_size;
+ } libr_icon;
+#else
+ typedef void libr_icon;
+#endif
+
+/*************************************************************************
+ * libr Icon API
+ *************************************************************************/
+
+/**
+ * @page libr_icon_close Release an icon resource handle.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>int libr_icon_close(libr_icon *icon);</b>
+ *
+ * @section DESCRIPTION
+ * Release the icon resource allocated by a call to
+ * <b>libr_icon_geticon_byid</b>(3), <b>libr_icon_geticon_byname</b>(3),
+ * <b>libr_icon_geticon_bysize</b>(3), <b>libr_icon_newicon_byfile</b>(3),
+ * or <b>libr_icon_newicon_frombuffer</b>(3).
+ *
+ * @param icon The icon handle to release.
+ * @return Returns 1 on success, 0 on failure.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_icon_geticon_byid</b>(3), <b>libr_icon_geticon_byname</b>(3),
+ * <b>libr_icon_geticon_bysize</b>(3), <b>libr_icon_newicon_byfile</b>(3),
+ * <b>libr_icon_newicon_frombuffer</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+int libr_icon_close(libr_icon *icon);
+
+/*
+libr_icon *libr_icon_geticon_byid(libr_file *handle, unsigned int iconid);
+*/
+
+/**
+ * @page libr_icon_geticon_byname Retrieve an icon resource from an ELF
+ * binary (by the icon resource's name).
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>libr_icon *libr_icon_geticon_byname(libr_file *handle, char *iconname);</b>
+ *
+ * @section DESCRIPTION
+ * Return a resource handle to an icon stored in a libr-compatible ELF
+ * binary. When this handle is no-longer needed it must be unallocated
+ * using <b>libr_icon_close</b>(3).
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @param iconname The exact name of the resource to return.
+ * @return Returns a handle on success, NULL on failure.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3), <b>libr_icon_close</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+libr_icon *libr_icon_geticon_byname(libr_file *handle, char *iconname);
+
+/**
+ * @page libr_icon_geticon_bysize Retrieve an icon resource from an ELF
+ * binary (by the desired icon size).
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>libr_icon *libr_icon_geticon_bysize(libr_file *handle, unsigned int iconsize);</b>
+ *
+ * @section DESCRIPTION
+ * Return a resource handle to the closest requested size icon stored
+ * in a libr-compatible ELF binary. When this handle is no-longer
+ * needed it must be unallocated using <b>libr_icon_close</b>(3).
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @param iconsize The size of the resource to return, use 0
+ * to request an SVG icon.
+ * @return Returns a handle on success, NULL on failure.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3), <b>libr_icon_close</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+libr_icon *libr_icon_geticon_bysize(libr_file *handle, unsigned int iconsize);
+
+/**
+ * @page libr_icon_getuuid Retrieve the UUID of an application.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>int libr_icon_getuuid(libr_file *handle, char *uuid);</b>
+ *
+ * @section DESCRIPTION
+ * Returns the icon UUID corresponding to the ELF binary in hex notation
+ * (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX), which requires a 37 character
+ * buffer (36 data characters and a NULL terminator).
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @param uuid A buffer to store the UUID of the application.
+ * @return Returns 1 on success, 0 on failure.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3), <b>libr_icon_close</b>(3),
+ * <b>libr_icon_setuuid</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+int libr_icon_getuuid(libr_file *handle, char *uuid);
+DEPRECATED_FN int libr_icon_getguid(libr_file *handle, char *uuid);
+
+char *libr_icon_malloc(libr_icon *icon, size_t *size);
+/*
+libr_icon *libr_icon_newicon_frombuffer(libr_icontype_t type, int iconsize, char *buffer, size_t size);
+*/
+libr_icon *libr_icon_newicon_byfile(libr_icontype_t type, unsigned int iconsize, char *iconfile);
+/*
+unsigned int libr_icon_num(libr_file *handle);
+*/
+int libr_icon_read(libr_icon *icon, char *buffer);
+int libr_icon_size(libr_icon *icon, size_t *size);
+int libr_icon_save(libr_icon *icon, char *filename);
+
+/**
+ * @page libr_icon_setuuid Write a UUID into an application binary.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>int libr_icon_setuuid(libr_file *handle, char *uuid);</b>
+ *
+ * @section DESCRIPTION
+ * Sets the icon UUID corresponding to the ELF binary in hex notation
+ * (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX), which requires a 37 character
+ * buffer (36 data characters and a NULL terminator).
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @param uuid A UUID to set for the application, can be generated by
+ * the terminal program "uuid".
+ * @return Returns 1 on success, 0 on failure.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3), <b>libr_icon_close</b>(3),
+ * <b>libr_icon_getuuid</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+int libr_icon_setuuid(libr_file *handle, char *uuid);
+DEPRECATED_FN int libr_icon_setguid(libr_file *handle, char *guid);
+int libr_icon_write(libr_file *handle, libr_icon *icon, char *iconname, libr_overwrite_t overwrite);
+
+#endif /* __LIBR_ICONS_H */
diff --git a/src/libr-internal.h b/src/libr-internal.h
new file mode 100644
index 0000000..f7008a4
--- /dev/null
+++ b/src/libr-internal.h
@@ -0,0 +1,34 @@
+#ifndef __LIBR_INTERNAL_H
+#define __LIBR_INTERNAL_H
+
+#define false 0
+#define true 1
+#define ERROR -1
+#define EXPORT_FN __attribute__((visibility ("protected")))
+#define INTERNAL_FN __attribute__ ((visibility ("internal")))
+#define LIBR_TEMPFILE "/tmp/libr-temp.XXXXXX"
+#define LIBR_TEMPFILE_LEN 22
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+typedef struct {
+ char *message;
+ libr_status status;
+ const char *function;
+} libr_intstatus;
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+struct _libr_file;
+
+void libr_set_error(libr_intstatus error);
+libr_intstatus make_status(const char *function, libr_status code, char *message, ...);
+/* Only called directly by cleanup routine, all other calls should be through libr_close */
+void libr_close_internal(struct _libr_file *file_handle);
+
+#define SET_ERROR(code,...) make_status(__FUNCTION__, code, __VA_ARGS__)
+#define RETURN(code,...) return SET_ERROR(code, __VA_ARGS__)
+#define RETURN_OK return SET_ERROR(LIBR_OK, NULL)
+#define PUBLIC_RETURN(code,message) {SET_ERROR(code, message); return (code == LIBR_OK);}
+
+#endif /* __LIBR_INTERNAL_H */
diff --git a/src/libr-link.h b/src/libr-link.h
new file mode 100644
index 0000000..b1bdb54
--- /dev/null
+++ b/src/libr-link.h
@@ -0,0 +1,26 @@
+#ifndef __LIBR_LINK_H
+#define __LIBR_LINK_H
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+typedef struct {
+ void **symbol;
+ char *name;
+} symbol_table;
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+#define SYMBOL_TABLE(tbl, ...) \
+const symbol_table tbl[] = { \
+ __VA_ARGS__ \
+ {NULL, NULL} \
+}
+
+#define OVERRIDE_SYMBOL(a) FN_##a
+#define SYMBOL(sym) {(void **)&FN_##sym, #sym}
+#define DEFINE_SYMBOL(ret, fn, ...) ret (*OVERRIDE_SYMBOL(fn))(__VA_ARGS__)
+#define LOAD_SYMBOLS(lib, tbl) load_symbols(lib, tbl, sizeof(tbl)/sizeof(symbol_table))
+
+int load_symbols(const char *library, const symbol_table *table, int entries);
+
+#endif /* __LIBR_LINK_H */
diff --git a/src/libr-ro.c b/src/libr-ro.c
new file mode 100644
index 0000000..c3de28d
--- /dev/null
+++ b/src/libr-ro.c
@@ -0,0 +1,351 @@
+/*
+ *
+ * Copyright (c) 2009 Erich Hoover
+ * Copyright (c) 2008-2009 Martin Rosenau
+ *
+ * libr read-only Backend - Read resources from ELF binaries
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+/* Include compile-time parameters */
+#include "config.h"
+
+#include "libr.h"
+#include "libr-internal.h"
+
+/* malloc/free */
+#include <stdlib.h>
+
+/* For memory byte-wise compare */
+#include <string.h>
+
+/* For endian conversion */
+#include "cvtendian.h"
+
+#define RETURN_UNSUPPORTED RETURN(LIBR_ERROR_UNSUPPORTED, "The read-only backend does not support this operation");
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+typedef struct {
+ unsigned char magic[4];
+ eClass byte_size;
+ eEncoding endian;
+ unsigned char version;
+ unsigned char padding[9];
+} ElfPreHeader;
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+#define ELF_HALF(b) sizeof(uint16_t)
+#define ELF_WORD(b) sizeof(uint32_t)
+#define ELF_XWORD(b) ((b == ELFCLASS32) ? sizeof(uint32_t) : sizeof(uint64_t))
+#define ELF_ADDR(b) ELF_XWORD(b)
+#define ELF_OFF(b) ELF_XWORD(b)
+
+/* ELF Header Offsets */
+#define HDROFF_TYPE(b) sizeof(ElfPreHeader) /* ElfXX_Half e_type; */
+#define HDROFF_MACHINE(b) HDROFF_TYPE(b)+ELF_HALF(b) /* ElfXX_Half e_machine; */
+#define HDROFF_VERSION(b) HDROFF_MACHINE(b)+ELF_HALF(b) /* ElfXX_Word e_version; */
+#define HDROFF_ENTRY(b) HDROFF_VERSION(b)+ELF_WORD(b) /* ElfXX_Addr e_entry; */
+#define HDROFF_PHOFF(b) HDROFF_ENTRY(b)+ELF_ADDR(b) /* ElfXX_Off e_phoff; */
+#define HDROFF_SHOFF(b) HDROFF_PHOFF(b)+ELF_OFF(b) /* ElfXX_Off e_shoff; */
+#define HDROFF_FLAGS(b) HDROFF_SHOFF(b)+ELF_OFF(b) /* ElfXX_Word e_flags; */
+#define HDROFF_EHSIZE(b) HDROFF_FLAGS(b)+ELF_WORD(b) /* ElfXX_Half e_ehsize; */
+#define HDROFF_PHENTSIZE(b) HDROFF_EHSIZE(b)+ELF_HALF(b) /* ElfXX_Half e_phentsize; */
+#define HDROFF_PHNUM(b) HDROFF_PHENTSIZE(b)+ELF_HALF(b) /* ElfXX_Half e_phnum; */
+#define HDROFF_SHENTSIZE(b) HDROFF_PHNUM(b)+ELF_HALF(b) /* ElfXX_Half e_shentsize; */
+#define HDROFF_SHNUM(b) HDROFF_SHENTSIZE(b)+ELF_HALF(b) /* ElfXX_Half e_shnum; */
+#define HDROFF_SHSTRNDX(b) HDROFF_SHNUM(b)+ELF_HALF(b) /* ElfXX_Half e_shstrndx; */
+
+/* ELF Section Offsets */
+#define SECOFF_NAME(b) 0 /* ElfXX_Word sh_name; */
+#define SECOFF_TYPE(b) SECOFF_NAME(b)+ELF_WORD(b) /* ElfXX_Word sh_type; */
+#define SECOFF_FLAGS(b) SECOFF_TYPE(b)+ELF_WORD(b) /* ElfXX_XWord sh_flags; */
+#define SECOFF_ADDR(b) SECOFF_FLAGS(b)+ELF_XWORD(b) /* ElfXX_Addr sh_addr; */
+#define SECOFF_OFFSET(b) SECOFF_ADDR(b)+ELF_ADDR(b) /* ElfXX_Off sh_offset; */
+#define SECOFF_SIZE(b) SECOFF_OFFSET(b)+ELF_OFF(b) /* ElfXX_XWord sh_size; */
+#define SECOFF_LINK(b) SECOFF_SIZE(b)+ELF_XWORD(b) /* ElfXX_Word sh_link; */
+#define SECOFF_INFO(b) SECOFF_LINK(b)+ELF_WORD(b) /* ElfXX_Word sh_info; */
+#define SECOFF_ADDRALIGN SECOFF_INFO(b)+ELF_WORD(b) /* ElfXX_XWord sh_addralign; */
+#define SECOFF_ENTSIZE SECOFF_ADDRALIGN(b)+ELF_XWORD(b) /* ElfXX_XWord sh_entsize; */
+
+/*
+ * Safely read a parameter from the ELF binary
+ */
+static int read_param(FILE *handle, void *result, size_t bytes, eClass endian)
+{
+ if(fread(result, 1, bytes, handle) != bytes)
+ return 0;
+ if(ferror(handle))
+ return 0;
+ if(endian != HOST_ENDIAN && !ConvertEndian(result, bytes))
+ return 0;
+ return 1;
+}
+
+/*
+ * The read-only backend requires no initialization
+ */
+void initialize_backend(void)
+{
+ if(sizeof(ElfPreHeader) != 16)
+ fprintf(stderr, "WARNING: Your compiler did not properly pack important structures!\n");
+}
+
+/*
+ * The read-only backend cannot write an output file
+ */
+void write_output(libr_file *file_handle) {}
+
+/*
+ * The read-only backend cannot add sections
+ */
+libr_intstatus add_section(libr_file *file_handle, char *resource_name, libr_section **retscn)
+{
+ RETURN_UNSUPPORTED;
+}
+
+/*
+ * Return the name of a section
+ */
+char *section_name(libr_file *file_handle, libr_section *scn)
+{
+ if(scn == NULL)
+ return NULL;
+ return scn->name;
+}
+
+/*
+ * Return the pointer to the actual data in the section
+ */
+void *data_pointer(libr_section *scn, libr_data *data)
+{
+ return (void *) data;
+}
+
+/*
+ * Return the size of the data in the section
+ */
+size_t data_size(libr_section *scn, libr_data *data)
+{
+ return scn->size;
+}
+
+/*
+ * Find the resource stored in the ELF binary
+ */
+libr_intstatus find_section(libr_file *file_handle, char *section, libr_section **retscn)
+{
+ char *test_name;
+ int i;
+
+ for(i=0; i<file_handle->total_sections; i++)
+ {
+ test_name = section_name(file_handle, &(file_handle->secdata[i]));
+ if(test_name != NULL && strcmp(test_name, section) == 0)
+ break;
+ }
+ if(i >= file_handle->total_sections)
+ RETURN(LIBR_ERROR_NOSECTION, "ELF resource section not found");
+
+ /* Found the resource, hurray! */
+ *retscn = &(file_handle->secdata[i]);
+ RETURN_OK;
+}
+
+/*
+ * Read the section from the ELF binary
+ */
+libr_data *get_data(libr_file *file_handle, libr_section *scn)
+{
+ FILE *handle = file_handle->handle;
+ libr_data *data = NULL;
+ size_t n;
+
+ fseek(handle, scn->data_offset, SEEK_SET);
+ data = (libr_data *) malloc(scn->size);
+ n = fread(data, 1, scn->size, handle);
+ if(n == 0)
+ goto failed; /* Empty section? */
+ if(ferror(handle))
+ goto failed;
+
+ /* Succeeded in reading the data */
+ return data;
+failed:
+ free(data);
+ return NULL;
+}
+
+/*
+ * UNSUPORTED BY BACKEND: Create a new data section
+ */
+libr_data *new_data(libr_file *file_handle, libr_section *scn)
+{
+ return NULL;
+}
+
+/*
+ * Find the next section given a section pointer
+ */
+libr_section *next_section(libr_file *file_handle, libr_section *scn)
+{
+ int total_sections = file_handle->total_sections;
+ libr_section *test_scn = NULL;
+ int i;
+
+ if(total_sections == 0)
+ return NULL;
+ /* Requesting the first section */
+ if(scn == NULL)
+ {
+ i = 0;
+ /* Do not return an empty section */
+ while(test_scn == NULL || test_scn->size == 0)
+ {
+ if(i > total_sections)
+ return NULL;
+ test_scn = &(file_handle->secdata[i++]);
+ }
+ return test_scn;
+ }
+ /* Return the next section given a section pointer */
+ for(i=0; i<total_sections; i++)
+ {
+ test_scn = &(file_handle->secdata[i]);
+
+ if(test_scn == scn && (i+1) < total_sections)
+ {
+ libr_section *next_scn = &(file_handle->secdata[i+1]);
+
+ /* Returning empty sections is pointless */
+ if(next_scn->size != 0)
+ return next_scn;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * UNSUPORTED BY BACKEND: Remove a section
+ */
+libr_intstatus remove_section(libr_file *file_handle, libr_section *scn)
+{
+ RETURN_UNSUPPORTED;
+}
+
+/*
+ * UNSUPORTED BY BACKEND: Set the data for a section
+ */
+libr_intstatus set_data(libr_file *file_handle, libr_section *scn, libr_data *data, off_t offset, char *buffer, size_t size)
+{
+ RETURN_UNSUPPORTED;
+}
+
+/*
+ * Open a handle to the ELF binary (provided that read-only access is requested)
+ */
+libr_intstatus open_handles(libr_file *file_handle, char *filename, libr_access_t access)
+{
+ const char elf_magic[] = {'\x7F','E','L','F'};
+ uint16_t total_sections, sh_size, strings_sec;
+ ElfPreHeader file_info;
+ libr_section *secdata;
+ FILE *handle = NULL;
+ uint64_t sh_offset;
+ unsigned long i;
+
+ if(access == LIBR_READ_WRITE)
+ RETURN_UNSUPPORTED;
+ handle = fopen(filename, "rb");
+ if(!handle)
+ RETURN(LIBR_ERROR_OPENFAILED, "Failed to open input file");
+ if(fread(&file_info, 1, sizeof(ElfPreHeader), handle) != sizeof(ElfPreHeader))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Failed to read pre-header bytes from input file");
+ if(memcmp(file_info.magic, elf_magic, sizeof(elf_magic)) != 0)
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: not an ELF binary");
+
+ /* Confirm processor (byte size) and packing (endian) */
+ if(!enum_valid(file_info.byte_size, ELFCLASS))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: invalid byte size");
+ if(!enum_valid(file_info.endian, ELFDATA))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: invalid endian type");
+
+ /* Get the file offset to the Section Header tables */
+ fseek(handle, HDROFF_SHOFF(file_info.byte_size), SEEK_SET);
+ if(!read_param(handle, &sh_offset, ELF_OFF(file_info.byte_size), file_info.endian))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: failed to read section header offset");
+ /* Get the size of the Section Header tables */
+ fseek(handle, HDROFF_SHENTSIZE(file_info.byte_size), SEEK_SET);
+ if(!read_param(handle, &sh_size, ELF_HALF(file_info.byte_size), file_info.endian))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: failed to read section header size");
+ /* Get the total number of sections */
+ fseek(handle, HDROFF_SHNUM(file_info.byte_size), SEEK_SET);
+ if(!read_param(handle, &total_sections, ELF_HALF(file_info.byte_size), file_info.endian))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: failed to read total number of sections");
+ /* Get the ID of the "strings" section */
+ fseek(handle, HDROFF_SHSTRNDX(file_info.byte_size), SEEK_SET);
+ if(!read_param(handle, &strings_sec, ELF_HALF(file_info.byte_size), file_info.endian))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: failed to read string section ID");
+ if(strings_sec >= total_sections)
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: invalid string section ID");
+ secdata = (libr_section *) malloc(sizeof(libr_section)*total_sections);
+
+ /* Load section information */
+ for(i=0; i<total_sections; i++)
+ {
+ long sec_start = sh_offset+sh_size*i;
+
+ /* Grab the offset in the string table to the name of the section */
+ fseek(handle, sec_start+SECOFF_NAME(file_info.byte_size), SEEK_SET);
+ if(!read_param(handle, &(secdata[i].name_offset), ELF_WORD(file_info.byte_size), file_info.endian))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: failed to read section name offset");
+ /* Grab the offset to the data for the section */
+ fseek(handle, sec_start+SECOFF_OFFSET(file_info.byte_size), SEEK_SET);
+ if(!read_param(handle, &(secdata[i].data_offset), ELF_OFF(file_info.byte_size), file_info.endian))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: failed to read section data offset");
+ /* Grab the size of the data for the section */
+ fseek(handle, sec_start+SECOFF_SIZE(file_info.byte_size), SEEK_SET);
+ if(!read_param(handle, &(secdata[i].size), ELF_XWORD(file_info.byte_size), file_info.endian))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: failed to read section size");
+ }
+ /* Locate the name offset within the "strings" section and load the string */
+ for(i=0; i<total_sections; i++)
+ {
+ long stringsec_start = secdata[strings_sec].data_offset;
+ size_t n;
+
+ fseek(handle, stringsec_start+secdata[i].name_offset, SEEK_SET);
+ n = fread(secdata[i].name, 1, ELFSTRING_MAX-1, handle);
+ if(ferror(handle))
+ RETURN(LIBR_ERROR_WRONGFORMAT, "Invalid input file format: failed to read string");
+ secdata[i].name[n] = '\0';
+ }
+
+ /* Hold onto the important parameters */
+ file_handle->secdata = secdata;
+ file_handle->total_sections = total_sections;
+ file_handle->endian = file_info.endian;
+ file_handle->byte_size = file_info.byte_size;
+ file_handle->handle = handle;
+ file_handle->filename = filename;
+ file_handle->access = access;
+ RETURN_OK;
+}
diff --git a/src/libr-ro.h b/src/libr-ro.h
new file mode 100644
index 0000000..8b8e41a
--- /dev/null
+++ b/src/libr-ro.h
@@ -0,0 +1,62 @@
+#ifndef __LIBRRO_H
+#define __LIBRRO_H
+
+/* For file handle support */
+#include <stdio.h>
+
+/* For integer types with set bit-sizes */
+#include <stdint.h>
+
+/*
+ * NOTE: Packing the enum uses the smallest number of bytes
+ * possible to represent the value. This packing does not
+ * guarantee that a "short enum" will be 8 bits, however,
+ * for the small enumerations in the ELF specification this
+ * IS the case (no enum requires more than 8 bits).
+ */
+#define SHORT_ENUM __attribute__ ((__packed__))
+
+/* Type of byte-packing (endian) */
+typedef enum SHORT_ENUM {
+ ELFDATANONE, /* Invalid */
+ ELFDATA2LSB, /* Least Significant Byte First */
+ ELFDATA2MSB, /* Most Significant Byte First */
+ ELFDATAMAX, /* Invalid */
+} eEncoding;
+
+/* Type of target processor */
+typedef enum SHORT_ENUM {
+ ELFCLASSNONE, /* Invalid */
+ ELFCLASS32, /* 32-bit Field Alignment */
+ ELFCLASS64, /* 64-bit Field Alignment */
+ ELFCLASSMAX, /* Invalid */
+} eClass;
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+#define ELFSTRING_MAX 200
+typedef struct _libr_section {
+ uint64_t size;
+ uint64_t data_offset;
+ uint32_t name_offset;
+ char name[ELFSTRING_MAX];
+} libr_section;
+
+typedef struct _libr_file {
+ FILE *handle;
+ char *filename;
+ eEncoding endian;
+ eClass byte_size;
+ libr_access_t access;
+ libr_section *secdata;
+ unsigned long total_sections;
+} libr_file;
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+/* for a clean internal API */
+typedef void libr_data;
+
+#define enum_valid(val, name) (val > name##NONE && val < name##MAX)
+
+#endif /* __LIBRRO_H */
diff --git a/src/libr.c b/src/libr.c
new file mode 100644
index 0000000..d038594
--- /dev/null
+++ b/src/libr.c
@@ -0,0 +1,489 @@
+/*
+ *
+ * Copyright (c) 2008-2009 Erich Hoover
+ *
+ * libr - Add resources into ELF binaries
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+/* Include compile-time parameters */
+#include "config.h"
+
+#include "libr.h"
+#include "tempfiles.h"
+
+/* Obtain file information */
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Compress files */
+#include <zlib.h>
+#include <math.h> /* for ceil */
+
+/* Handle strings and variable arguments*/
+#include <string.h>
+#include <stdarg.h>
+
+/* For C99 number types */
+#include <stdint.h>
+
+/* Handle status codes for multiple threads */
+#include <pthread.h>
+
+#define SPEC_VERSION '1'
+#define OFFSET_TYPE ((unsigned long) 4)
+#define OFFSET_UNCOMPRESSED ((unsigned long) OFFSET_TYPE+sizeof(unsigned char))
+#define OFFSET_UNCOMPRESSED_SIZE ((unsigned long) OFFSET_TYPE+sizeof(unsigned char))
+#define OFFSET_COMPRESSED ((unsigned long) OFFSET_UNCOMPRESSED_SIZE+sizeof(uint32_t))
+
+#if 0
+ extern const char * __progname_full;
+ #define progpath() (char *) __progname_full
+#endif
+#define getself() ((char *) "/proc/self/exe")
+
+pthread_key_t error_key;
+
+/*
+ * Free the error status code/message structure
+ * (called on thread destruction or when a new code is set)
+ */
+void free_error_key(void *_m)
+{
+ libr_intstatus *error = (libr_intstatus *) _m;
+
+ if(error != NULL)
+ {
+ /* Free the error structure */
+ if(error->message != NULL)
+ free(error->message);
+ free(error);
+ }
+}
+
+/*
+ * Set the error code and message for retrieval
+ */
+void libr_set_error(libr_intstatus error)
+{
+ static int thread_key_initialized = false;
+ libr_intstatus *status = NULL;
+
+ if(!thread_key_initialized)
+ {
+ if(pthread_key_create(&error_key, free_error_key) != 0)
+ return; /* a serious pthread-related error occurred */
+ if(pthread_setspecific(error_key, NULL) != 0)
+ return; /* a serious pthread-related error occurred */
+ thread_key_initialized = true;
+ }
+ free_error_key(pthread_getspecific(error_key));
+ status = (libr_intstatus *) malloc(sizeof(libr_intstatus));
+ memcpy(status, &error, sizeof(libr_intstatus));
+ if(pthread_setspecific(error_key, (void *) status) != 0)
+ return; /* a serious pthread-related error occurred */
+}
+
+/*
+ * Make an internal status passing structure, set the error code with this status
+ * if the status is not LIBR_OK.
+ */
+libr_intstatus make_status(const char *function, libr_status code, char *message, ...)
+{
+ libr_intstatus status = {NULL, code, function};
+ va_list args;
+
+ if(message != NULL)
+ {
+ status.message = (char *) malloc(1024);
+ va_start(args, message);
+ vsnprintf(status.message, 1024, message, args);
+ va_end(args);
+ }
+
+ libr_set_error(status);
+ return status;
+}
+
+/*
+ * Make sure that the section is libr-compatible
+ */
+libr_intstatus section_ok(libr_section *scn, libr_data *data)
+{
+ char required_header[5], test_header[4] = {'R', 'E', 'S', SPEC_VERSION};
+ void *ptr = data_pointer(scn, data);
+ size_t size = data_size(scn, data);
+
+ if(ptr == NULL || size < sizeof(required_header))
+ RETURN(LIBR_ERROR_NOTRESOURCE, "Not a valid libr-resource");
+ memcpy(required_header, ptr, sizeof(required_header));
+ if(strncmp(required_header, test_header, sizeof(test_header)) != 0)
+ RETURN(LIBR_ERROR_NOTRESOURCE, "Not a valid libr-resource");
+ RETURN_OK;
+}
+
+/*
+ * Remove a resourcefrom the ELF binary handle
+ */
+EXPORT_FN int libr_clear(libr_file *file_handle, char *resource_name)
+{
+ libr_data *data = NULL;
+ libr_section *scn = NULL;
+
+ /* Ensure valid inputs */
+ if(file_handle == NULL || resource_name == NULL)
+ PUBLIC_RETURN(LIBR_ERROR_INVALIDPARAMS, "Invalid parameters passed to function");
+ if(file_handle->access != LIBR_READ_WRITE)
+ PUBLIC_RETURN(LIBR_ERROR_NOPERM, "Open handle with LIBR_READ_WRITE access");
+ /* Find the section containing the icon */
+ if(find_section(file_handle, resource_name, &scn).status != LIBR_OK)
+ return false; /* error already set */
+ /* Get the section data (interested in header) */
+ if((data = get_data(file_handle, scn)) == NULL)
+ PUBLIC_RETURN(LIBR_ERROR_GETDATA, "Failed to obtain data of section");
+ /* Confirm that this resource is libr-compatible */
+ if(section_ok(scn, data).status != LIBR_OK)
+ return false; /* error already set */
+ /* Clear the data resource */
+ if(set_data(file_handle, scn, data, 0, NULL, 0).status != LIBR_OK)
+ return false; /* error already set */
+ /* Remove the section */
+ if(remove_section(file_handle, scn).status != LIBR_OK)
+ return false; /* error already set */
+ return true;
+}
+
+/*
+ * Close the specified ELF binary handle
+ */
+EXPORT_FN void libr_close(libr_file *file_handle)
+{
+ unregister_handle_cleanup(file_handle);
+ libr_close_internal(file_handle);
+}
+/* Only called directly by cleanup routine, all other calls should be through libr_close */
+void libr_close_internal(libr_file *file_handle)
+{
+ write_output(file_handle);
+ free(file_handle);
+}
+
+/*
+ * Return the last error message for the active thread
+ */
+EXPORT_FN char *libr_errmsg(void)
+{
+ libr_intstatus *error = (libr_intstatus *) pthread_getspecific(error_key);
+
+ if(error == NULL)
+ return NULL;
+ return error->message;
+}
+
+/*
+ * Return the last error code for the active thread (or LIBR_OK for no error)
+ */
+EXPORT_FN libr_status libr_errno(void)
+{
+ libr_intstatus *error = (libr_intstatus *) pthread_getspecific(error_key);
+
+ if(error == NULL) /* Nothing has happened yet */
+ return LIBR_OK;
+ return error->status;
+}
+
+/*
+ * Return the name of a libr-compatible resource
+ */
+EXPORT_FN char *libr_list(libr_file *file_handle, unsigned int resourceid)
+{
+ libr_section *scn = NULL;
+ libr_data *data = NULL;
+ int i = 0;
+
+ while((scn = next_section(file_handle, scn)) != NULL)
+ {
+ /* Get the section data (interested in header) */
+ if((data = get_data(file_handle, scn)) == NULL)
+ return NULL;
+ if(section_ok(scn, data).status == LIBR_OK)
+ {
+ if(i == resourceid)
+ return strdup(section_name(file_handle, scn));
+ i++;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Allocate a buffer containing the data of a resource
+ */
+EXPORT_FN char *libr_malloc(libr_file *file_handle, char *resource_name, size_t *size)
+{
+ char *buffer = NULL;
+ size_t size_local;
+
+ if(size == NULL)
+ size = &size_local;
+ if(!libr_size(file_handle, resource_name, size))
+ return NULL; /* error already set */
+ buffer = (char *) malloc(*size);
+ if(!libr_read(file_handle, resource_name, buffer))
+ {
+ free(buffer);
+ return NULL; /* error already set */
+ }
+ return buffer;
+}
+
+/*
+ * Open the specified ELF binary (caller if filename is NULL)
+ */
+EXPORT_FN libr_file *libr_open(char *filename, libr_access_t access)
+{
+ libr_file *file_handle = NULL;
+ static int initialized = false;
+
+ if(!initialized)
+ {
+ if(strncmp(zlibVersion(), ZLIB_VERSION, 1) != 0)
+ {
+ SET_ERROR(LIBR_ERROR_ZLIBINIT, "zlib library initialization failed");
+ return NULL;
+ }
+ initialize_backend();
+ initialized = true;
+ }
+
+ if(filename == NULL)
+ filename = getself();
+ file_handle = (libr_file *) malloc(sizeof(libr_file));
+ memset(file_handle, 0, sizeof(libr_file));
+ if(open_handles(file_handle, filename, access).status != LIBR_OK)
+ {
+ /* failed to open file for processing, error already set */
+ free(file_handle);
+ file_handle = NULL;
+ }
+ /* Cleanup handles automatically when libr exits memory */
+ if(file_handle != NULL)
+ register_handle_cleanup(file_handle);
+ return file_handle;
+}
+
+/*
+ * Read a resource from the specified ELF binary handle
+ */
+EXPORT_FN int libr_read(libr_file *file_handle, char *resource_name, char *buffer)
+{
+ unsigned long uncompressed_size = 0, compressed_size = 0;
+ char *data_buffer = NULL;
+ libr_section *scn = NULL;
+ libr_data *data = NULL;
+ libr_type_t type;
+
+ /* Find the section containing the icon */
+ if(find_section(file_handle, resource_name, &scn).status != LIBR_OK)
+ return false; /* error already set */
+ /* Get the section data (interested in header) */
+ if((data = get_data(file_handle, scn)) == NULL)
+ PUBLIC_RETURN(LIBR_ERROR_GETDATA, "Failed to obtain data of section");
+ /* Confirm that this resource is libr-compatible */
+ if(section_ok(scn, data).status != LIBR_OK)
+ return false; /* error already set */
+ data_buffer = (char *) data_pointer(scn, data);
+ /* Get the size of the data resource */
+ type = (libr_type_t) data_buffer[OFFSET_TYPE];
+ switch(type)
+ {
+ case LIBR_UNCOMPRESSED:
+ { if(data_size(scn, data)-OFFSET_UNCOMPRESSED < 0)
+ PUBLIC_RETURN(LIBR_ERROR_SIZEMISMATCH, "Section's data size does not make sense");
+ uncompressed_size = data_size(scn, data)-OFFSET_UNCOMPRESSED;
+ memcpy(buffer, &data_buffer[OFFSET_UNCOMPRESSED], uncompressed_size);
+ } break;
+ case LIBR_COMPRESSED:
+ {
+ uint32_t size_temp;
+
+ memcpy(&size_temp, &data_buffer[OFFSET_UNCOMPRESSED_SIZE], sizeof(uint32_t));
+ uncompressed_size = size_temp;
+ compressed_size = data_size(scn, data)-OFFSET_COMPRESSED;
+ if(uncompress((unsigned char *)buffer, &uncompressed_size, (unsigned char *)&data_buffer[OFFSET_COMPRESSED], compressed_size) != Z_OK)
+ PUBLIC_RETURN(LIBR_ERROR_UNCOMPRESS, "Failed to uncompress resource data");
+ } break;
+ default:
+ PUBLIC_RETURN(LIBR_ERROR_INVALIDTYPE, "Invalid data storage type specified");
+ }
+ return true;
+}
+
+/*
+ * Retrieve the number of libr-compatible resources
+ */
+EXPORT_FN unsigned int libr_resources(libr_file *file_handle)
+{
+ libr_section *scn = NULL;
+ libr_data *data = NULL;
+ int i = 0;
+
+ while((scn = next_section(file_handle, scn)) != NULL)
+ {
+ if((data = get_data(file_handle, scn)) == NULL)
+ continue;
+ if(section_ok(scn, data).status == LIBR_OK)
+ i++;
+ }
+ return i;
+}
+
+/*
+ * Get the size of a resource from the specified ELF binary handle
+ */
+EXPORT_FN int libr_size(libr_file *file_handle, char *resource_name, size_t *retsize)
+{
+ char *data_buffer = NULL;
+ libr_section *scn = NULL;
+ libr_data *data = NULL;
+ unsigned long size = 0;
+ libr_type_t type;
+
+ /* Find the section containing the icon */
+ if(find_section(file_handle, resource_name, &scn).status != LIBR_OK)
+ return false; /* error already set */
+ /* Get the section data (interested in header) */
+ if((data = get_data(file_handle, scn)) == NULL)
+ PUBLIC_RETURN(LIBR_ERROR_GETDATA, "Failed to obtain data of section");
+ /* Confirm that this resource is libr-compatible */
+ if(section_ok(scn, data).status != LIBR_OK)
+ return false; /* error already set */
+ data_buffer = (char *) data_pointer(scn, data);
+ /* Get the size of the data resource */
+ type = (libr_type_t) data_buffer[OFFSET_TYPE];
+ switch(type)
+ {
+ case LIBR_UNCOMPRESSED:
+ {
+ size_t full_size = data_size(scn, data);
+
+ if(full_size-OFFSET_UNCOMPRESSED < 0)
+ PUBLIC_RETURN(LIBR_ERROR_SIZEMISMATCH, "Section's data size does not make sense");
+ size = full_size - OFFSET_UNCOMPRESSED;
+ } break;
+ case LIBR_COMPRESSED:
+ {
+ memcpy(&size, &data_buffer[OFFSET_UNCOMPRESSED_SIZE], sizeof(uint32_t));
+ } break;
+ default:
+ PUBLIC_RETURN(LIBR_ERROR_INVALIDTYPE, "Invalid data storage type specified");
+ }
+ *retsize = size;
+ return true;
+}
+
+/*
+ * Write a resource to the specified ELF binary handle
+ */
+EXPORT_FN int libr_write(libr_file *file_handle, char *resource_name, char *buffer, size_t size, libr_type_t type, libr_overwrite_t overwrite)
+{
+ char header[9] = {'R', 'E', 'S', SPEC_VERSION};
+ unsigned int header_size = 4;
+ libr_section *scn = NULL;
+ libr_data *data = NULL;
+ libr_intstatus ret;
+
+ /* Ensure valid inputs */
+ if(file_handle == NULL || resource_name == NULL || buffer == NULL)
+ PUBLIC_RETURN(LIBR_ERROR_INVALIDPARAMS, "Invalid parameters passed to function");
+ if(file_handle->access != LIBR_READ_WRITE)
+ PUBLIC_RETURN(LIBR_ERROR_NOPERM, "Open handle with LIBR_READ_WRITE access");
+ /* Get the section if it already exists */
+ ret = find_section(file_handle, resource_name, &scn);
+ if(ret.status == LIBR_OK)
+ {
+ /* If the section exists (and overwrite is not specified) then fail */
+ if(!overwrite)
+ PUBLIC_RETURN(LIBR_ERROR_OVERWRITE, "Section already exists, over-write not specified");
+ /* Grab the existing data section for overwriting */
+ if((data = get_data(file_handle, scn)) == NULL)
+ PUBLIC_RETURN(LIBR_ERROR_GETDATA, "Failed to obtain data of section");
+ }
+ else if(ret.status == LIBR_ERROR_NOSECTION)
+ {
+ /* Create a new section named "resource_name" */
+ if(add_section(file_handle, resource_name, &scn).status != LIBR_OK)
+ return false; /* error already set */
+ /* Create a data segment to store the compressed image */
+ if((data = new_data(file_handle, scn)) == NULL)
+ PUBLIC_RETURN(LIBR_ERROR_NEWDATA, "Failed to create data for section");
+ }
+ else
+ return false; /* error already set */
+
+ header[header_size++] = (char) type;
+ switch(type)
+ {
+ case LIBR_UNCOMPRESSED:
+ /* Do nothing, just stick the data in */
+ break;
+ case LIBR_COMPRESSED:
+ {
+ char *compressed_buffer = NULL, *uncompressed_buffer = buffer;
+ unsigned long compressed_size = 0, uncompressed_size = size;
+ uint32_t size_temp;
+
+ /* Store the uncompressed size to the header */
+ size_temp = uncompressed_size;
+ memcpy(&header[header_size], &size_temp, sizeof(uint32_t));
+ header_size += sizeof(uint32_t);
+ /* Compress the data for storage */
+ compressed_size = ceil((uncompressed_size+12)*1.1);
+ compressed_buffer = (char *) malloc(compressed_size);
+ if(compress((unsigned char *)compressed_buffer, &compressed_size, (unsigned char *)uncompressed_buffer, uncompressed_size) != Z_OK)
+ {
+ free(compressed_buffer);
+ PUBLIC_RETURN(LIBR_ERROR_COMPRESS, "Failed to compress resource data");
+ }
+ /* From here on treat the compressed buffer as the data */
+ buffer = compressed_buffer;
+ size = compressed_size;
+ } break;
+ default:
+ PUBLIC_RETURN(LIBR_ERROR_INVALIDTYPE, "Invalid data storage type specified");
+ }
+ /* Store the resource header data */
+ if(set_data(file_handle, scn, data, 0, &header[0], header_size).status != LIBR_OK)
+ return false; /* error already set */
+ /* Create a data segment to store the post-header data
+ * NOTE: For existing files the data of the section is represented as a continuous stream
+ * (so calling elf_getdata now WILL NOT return the post-header data)
+ */
+ if((data = new_data(file_handle, scn)) == NULL)
+ PUBLIC_RETURN(LIBR_ERROR_NEWDATA, "Failed to create data for section");
+ /* Store the actual user data to the section */
+ if(set_data(file_handle, scn, data, header_size, buffer, size).status != LIBR_OK)
+ return false; /* error already set */
+ /* Close compression resources */
+ if(type == LIBR_COMPRESSED)
+ free(buffer);
+ return true;
+}
diff --git a/src/libr.h b/src/libr.h
new file mode 100644
index 0000000..b1aa1d7
--- /dev/null
+++ b/src/libr.h
@@ -0,0 +1,416 @@
+/*
+ *
+ * Copyright (c) 2008-2011 Erich Hoover
+ *
+ * libr - Add resources into ELF binaries
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+#ifndef __LIBR_H
+#define __LIBR_H
+
+#include <sys/types.h>
+
+#define DEPRECATED_FN __attribute__ ((deprecated))
+#define ALIAS_FN(fn) __attribute__ ((weak, alias (#fn)))
+
+/**
+ * @addtogroup libr_status libr_status
+ * @brief Enumeration of possible libr status values.
+ * @{
+ * \#include <libr.h>
+ */
+/** Possible libr status values */
+typedef enum {
+ LIBR_OK = 0, /**< Success */
+ LIBR_ERROR_GETEHDR = -1, /**< Failed to obtain ELF header: */
+ LIBR_ERROR_NOTABLE = -2, /**< No ELF string table */
+ LIBR_ERROR_TABLE = -3, /**< Failed to open string table: */
+ LIBR_ERROR_GETDATA = -4, /**< Failed to obtain data of section */
+ LIBR_ERROR_GETSHDR = -5, /**< Failed to obtain ELF section header: */
+ LIBR_ERROR_SIZEMISMATCH = -6, /**< Section's data size does not make sense */
+ LIBR_ERROR_UPDATE = -7, /**< Failed to perform dynamic update: */
+ LIBR_ERROR_NEWSECTION = -8, /**< Failed to create new section */
+ LIBR_ERROR_NEWDATA = -9, /**< Failed to create data for section */
+ LIBR_ERROR_REMOVESECTION = -10, /**< Failed to remove section: */
+ LIBR_ERROR_NOSECTION = -11, /**< ELF resource section not found */
+ LIBR_ERROR_STRPTR = -12, /**< Failed to obtain section string pointer: */
+ LIBR_ERROR_NOTRESOURCE = -13, /**< Not a valid libr-resource */
+ LIBR_ERROR_EXPANDSECTION = -14, /**< Failed to expand section */
+ LIBR_ERROR_WRONGFORMAT = -15, /**< Invalid input file format */
+ LIBR_ERROR_SETFLAGS = -16, /**< Failed to set flags for section */
+ LIBR_ERROR_NOPERM = -17, /**< Open handle with LIBR_READ_WRITE access */
+ LIBR_ERROR_NOSIZE = -18, /**< Failed to obtain file size */
+ LIBR_ERROR_SETFORMAT = -19, /**< Failed to set output file format to input file format */
+ LIBR_ERROR_SETARCH = -20, /**< Failed to set output file architecture to input file architecture */
+ LIBR_ERROR_OVERWRITE = -21, /**< Section already exists, over-write not specified */
+ LIBR_ERROR_COMPRESS = -22, /**< Failed to compress resource data */
+ LIBR_ERROR_INVALIDTYPE = -23, /**< Invalid data storage type specified */
+ LIBR_ERROR_MEMALLOC = -24, /**< Failed to allocate memory for data */
+ LIBR_ERROR_INVALIDPARAMS = -25, /**< Invalid parameters passed to function */
+ LIBR_ERROR_UNCOMPRESS = -26, /**< Failed to uncompress resource data */
+ LIBR_ERROR_ZLIBINIT = -27, /**< zlib library initialization failed */
+ LIBR_ERROR_OPENFAILED = -28, /**< Failed to open input file */
+ LIBR_ERROR_BEGINFAILED = -29, /**< Failed to open ELF file: */
+ LIBR_ERROR_WRITEPERM = -30, /**< No write permission for file */
+ LIBR_ERROR_UNSUPPORTED = -31, /**< The requested operation is not supported by the backend */
+} libr_status;
+/**
+ * @}
+ */
+
+typedef enum {
+ LIBR_READ = 0,
+ LIBR_READ_WRITE = 1,
+} libr_access_t;
+
+typedef enum {
+ LIBR_UNCOMPRESSED = 0,
+ LIBR_COMPRESSED = 1
+} libr_type_t;
+
+typedef enum {
+ LIBR_NOOVERWRITE = 0,
+ LIBR_OVERWRITE = 1
+} libr_overwrite_t;
+
+#ifdef __LIBR_BUILD__
+ #include "libr-internal.h"
+ #if __LIBR_BACKEND_libbfd__
+ #include "libr-bfd.h"
+ #elif __LIBR_BACKEND_libelf__
+ #include "libr-elf.h"
+ #elif __LIBR_BACKEND_readonly__
+ #include "libr-ro.h"
+ #else /* LIBR_BACKEND */
+ #error "Unhandled backend"
+ #endif /* LIBR_BACKEND */
+ #include "libr-backends.h"
+#else
+ struct _libr_file;
+ typedef struct _libr_file libr_file;
+#endif /* __LIBR_BUILD__ */
+
+/*************************************************************************
+ * libr Resource Management API
+ *************************************************************************/
+
+/**
+ * @page libr_clear Remove a resource from an ELF executable.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>int libr_clear(libr_file *handle, char *resourcename);</b>
+ *
+ * @section DESCRIPTION
+ * Removes a libr-compatible resource from an ELF executable. The handle
+ * must be opened using <b>libr_open</b>(3) with either <b>LIBR_WRITE</b>
+ * or <b>LIBR_READ_WRITE</b> access in order to remove a resource.
+ *
+ * Please note that resource removal does not occur until the handle is
+ * closed using <b>libr_close</b>(3).
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @param resourcename The name of the libr-compatible resource to remove.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3), <b>libr_close</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+int libr_clear(libr_file *handle, char *resourcename);
+
+/**
+ * @page libr_close Close a handle to an ELF executable.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>void libr_close(libr_file *handle);</b>
+ *
+ * @section DESCRIPTION
+ * Handles opened with <b>libr_open</b>(3) should be closed with
+ * <b>libr_close</b>() when they are no-longer needed by the calling
+ * application.
+ *
+ * @param handle The handle to close.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+void libr_close(libr_file *handle);
+
+/**
+ * @page libr_errmsg Return a detailed description of the last
+ * libr-related error.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>char *libr_errmsg(void);</b>
+ *
+ * @section DESCRIPTION
+ * Returns a detailed string describing the last error encountered by
+ * the libr resource library. The string is an internal error
+ * description, so it should not be freed.
+ *
+ * If no errors have been encountered then NULL is returned.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_errno</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+char *libr_errmsg(void);
+
+/**
+ * @page libr_errno Return a status code describing the last
+ * libr-related error.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>libr_status libr_errno(void);</b>
+ *
+ * @section DESCRIPTION
+ * Returns a code corresponding to the last error encountered by
+ * the libr resource library. For a detailed description of possible
+ * return values see <b>libr_status</b>(3).
+ *
+ * To get a user-readable string corresponding to the last error the
+ * <b>libr_errmsg</b>(3) function should be used instead.
+ *
+ * If no errors have been encountered then <b>LIBR_OK</b> is returned.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_errmsg</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+libr_status libr_errno(void);
+
+/**
+ * @page libr_list Obtain the name of a libr ELF resource (by index).
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>char *libr_list(libr_file *file_handle, unsigned int resourceid);</b>
+ *
+ * @section DESCRIPTION
+ * Returns the name of a libr-compatible resource stored in an ELF binary
+ * corresponding to the given resource index. The index value ranges from
+ * 0 to the value returned by <b>libr_resources</b>(3), which returns the
+ * total number of libr-compatible resources stored in the ELF binary.
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @param resourceid The index of the libr-compatible resource for which
+ * the name will be returned.
+ *
+ * @return Returns a string containing the name of the resource section. This
+ * string is allocated when the function is called, so it <i>must be
+ * unallocated</i> with a call to <b>free</b>(3) when it is no-longer
+ * needed. NULL is returned on failure.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3), <b>free</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+char *libr_list(libr_file *file_handle, unsigned int resourceid);
+
+/**
+ * @page libr_malloc Obtain the data corresponding to a libr ELF resource.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>char *libr_malloc(libr_file *handle, char *resourcename, size_t *size);</b>
+ *
+ * @section DESCRIPTION
+ * Returns the contents of a libr-compatible resource stored in an ELF binary
+ * corresponding to the given resource name.
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @param resourcename The name of the libr-compatible resource for which
+ * the data will be returned.
+ * @param size A pointer for storing the length of the data contained in the
+ * the resource. May be NULL.
+ *
+ * @return Returns NULL on failure, the pointer to a buffer containing the data
+ * for the resource on success. When the buffer is no-longer used it must
+ * be unallocated using a call to <b>free</b>(3).
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3), <b>free</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+char *libr_malloc(libr_file *handle, char *resourcename, size_t *size);
+
+/**
+ * @page libr_open Open an ELF executable file for resource management.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>libr_file *libr_open(char *filename, libr_access_t access);</b>
+ *
+ * @section DESCRIPTION
+ * <b>libr_open</b>() can be used on any ELF executable, however,
+ * <b>libr_open</b>() called with <b>LIBR_READ</b> access is only useful
+ * for executables that already contain libr-compatible stored resources.
+ *
+ * An application can easily access its own resources by passing NULL for
+ * the filename and requesting <b>LIBR_READ</b> access. For the obvious
+ * reason that an actively-open application cannot edit itself, the
+ * calling binary may only request <b>LIBR_READ</b> access.
+ *
+ * @param filename ELF executable to manage. Pass a NULL pointer as the
+ * filename in order to access the calling binary (<b>LIBR_READ</b>
+ * access only) @param access Requested access type (<b>LIBR_READ</b>,
+ * <b>LIBR_WRITE</b>, <b>LIBR_READ_WRITE</b>), the valid operations for
+ * the returned handle will be restricted based upon the requested access.
+ * @return Returns a libr file handle on success, NULL on failure. The
+ * handle should be freed with <b>libr_close</b>(3) when no-longer used.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_close</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+libr_file *libr_open(char *filename, libr_access_t access);
+
+/**
+ * @page libr_read Read out the contents of a libr ELF resource.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>int libr_read(libr_file *handle, char *resourcename, char *buffer);</b>
+ *
+ * @section WARNING
+ * This function does not allocate memory for the buffer, so the buffer must
+ * be large enough to fit the resource data. For this reason it is suggested
+ * that <b>libr_malloc</b>(3) be used in preference over this function.
+ *
+ * @section DESCRIPTION
+ * Reads the contents of a resource embedded in an ELF binary, the resource
+ * must be compatible with the libr specification.
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @return Returns 1 on success, 0 on failure.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+int libr_read(libr_file *handle, char *resourcename, char *buffer);
+
+/**
+ * @page libr_resources Returns the number of resources contained in
+ * the ELF binary.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>unsigned int libr_resources(libr_file *handle);</b>
+ *
+ * @section DESCRIPTION
+ * Returns the total number of libr-compatible resources contained
+ * in the ELF binary. Intended to be used with <b>libr_list</b>(3)
+ * to return the full list of resources contained in the binary.
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @return The total number of libr resources in the binary.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3), <b>libr_list</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+unsigned int libr_resources(libr_file *handle);
+
+/**
+ * @page libr_size Returns the uncompressed size of a libr resource.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>int libr_size(libr_file *handle, char *resourcename, size_t *size);</b>
+ *
+ * @section DESCRIPTION
+ * Obtain the total number of bytes consumed by the uncompressed
+ * version of the specific libr-resource. Intended to be used with
+ * <b>libr_read</b>(3) in order to allocate a large enough buffer
+ * for the resource.
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @param resourcename The name of the resource for which the
+ * size of the data section will be returned.
+ * @param size A pointer for storing the size of the data section.
+ * This pointer cannot be NULL.
+ * @return Returns 1 on success, 0 on failure.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3), <b>libr_read</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+int libr_size(libr_file *handle, char *resourcename, size_t *size);
+
+/**
+ * @page libr_write Adds a libr resource to an ELF binary.
+ * @section SYNOPSIS
+ * \#include <libr.h>
+ *
+ * <b>int libr_write(libr_file *handle, char *resourcename, char *buffer, size_t size, libr_type_t type, libr_overwrite_t overwrite);</b>
+ *
+ * @section DESCRIPTION
+ * Adds a libr-compatible resource into the ELF binary. The handle
+ * must be opened using <b>libr_open</b>(3) with either <b>LIBR_WRITE</b>
+ * or <b>LIBR_READ_WRITE</b> access in order to add a resource.
+ *
+ * @param handle A handle returned by <b>libr_open</b>(3).
+ * @param resourcename The name of the resource to create.
+ * @param buffer A string containing the data of the resource.
+ * @param size The total size of the buffer.
+ * @param type The method which should be used for storing the
+ * data (either <b>LIBR_UNCOMPRESSED</b> or
+ * <b>LIBR_COMPRESSED</b>).
+ * @param overwrite Whether overwriting an existing resource
+ * should be permitted (either <b>LIBR_NOOVERWRITE</b> or
+ * <b>LIBR_OVERWRITE</b>).
+ * @return Returns 1 on success, 0 on failure.
+ *
+ * @section SA SEE ALSO
+ * <b>libr_open</b>(3)
+ *
+ * @section AUTHOR
+ * Erich Hoover <ehoover@mines.edu>
+ */
+int libr_write(libr_file *handle, char *resourcename, char *buffer, size_t size, libr_type_t type, libr_overwrite_t overwrite);
+
+#endif /* __LIBR_H */
+
diff --git a/src/onecanvas.c b/src/onecanvas.c
new file mode 100644
index 0000000..e53ece7
--- /dev/null
+++ b/src/onecanvas.c
@@ -0,0 +1,446 @@
+/*
+ *
+ * Copyright (c) 2010 Erich Hoover
+ *
+ * libr "one canvas" - Handle multiple icons stored in a single "one canvas"
+ * SVG document.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define FALSE 0
+#define TRUE 1
+
+typedef struct {
+ double x;
+ double y;
+ double width;
+ double height;
+ int icon_width;
+ int icon_height;
+} IconSVG;
+
+typedef enum {
+ STATUS_FINDSVG,
+ STATUS_FINDMETADATA,
+ STATUS_FINDPUBLISHER_START,
+ STATUS_FINDPUBLISHER_STOP,
+ STATUS_FINDHIDDEN,
+ STATUS_FINDBOUNDS,
+ STATUS_FAILED,
+ STATUS_DONE,
+} eStatus;
+
+typedef struct {
+ IconSVG **iconlist;
+ int iconlist_num;
+ eStatus status;
+
+ char *hidden_stop;
+ char *hidden_start;
+ char *publisher_stop;
+ char *publisher_start;
+ char *coordinate_stop;
+ char *coordinate_start;
+} OneCanvasIconInfo;
+
+/*
+ * Find the start of the next XML tag (search for '<')
+ */
+static inline char *xml_nextTag(char *c)
+{
+ c++;
+ if(c == NULL)
+ return NULL;
+ return strchr(c, '<');
+}
+
+/*
+ * Pull out the name/type of a tag.
+ */
+static inline char *xml_getTagName(char *c)
+{
+ char *tag_end = NULL, *tag_space, *tag_close, *tag_feed, *tag_line;
+ static char tagname[20];
+ int tag_len;
+
+ if(++c == NULL)
+ return NULL;
+ tag_space = strchr(c, ' ');
+ tag_close = strchr(c, '>');
+ tag_feed = strchr(c, '\r');
+ tag_line = strchr(c, '\n');
+ if(tag_space)
+ tag_end = tag_space;
+ if(tag_close && tag_end > tag_close)
+ tag_end = tag_close;
+ if(tag_feed && tag_end > tag_feed)
+ tag_end = tag_feed;
+ if(tag_line && tag_end > tag_line)
+ tag_end = tag_line;
+ if(!tag_end)
+ return NULL;
+ tag_len = tag_end - c;
+ tag_len = tag_len > 19 ? 19 : tag_len;
+ strncpy(tagname, c, tag_len);
+ tagname[tag_len] = '\0';
+ return tagname;
+}
+
+/*
+ * Find the position in the string corresponding to a particular named attribute.
+ */
+static inline char *xml_getTagAttributePtr(char *c, char *attrname)
+{
+ char *end, *name;
+ int found;
+
+ if(++c == NULL)
+ return NULL;
+ end = strchr(c, '>');
+ while(c < end)
+ {
+ int name_len;
+ char *equal;
+
+ equal = c = strchr(c, '=');
+ if(c == NULL)
+ break;
+ c++;
+ name = equal;
+ while(name[0] != ' ' && name[0] != '\t' && name[0] != '\n')
+ name--;
+ name++; /* don't include the space */
+ name_len = equal-name;
+ if(name_len != strlen(attrname))
+ continue;
+ if(strncasecmp(attrname, name, name_len) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ if(!found)
+ return NULL;
+ return c-strlen(attrname)-1;
+}
+
+/*
+ * Return the value of an XML tag's named attribute.
+ */
+static inline char *xml_getTagAttribute(char *c, char *attrname)
+{
+ char *data_end;
+ int data_len;
+ char *attr;
+
+ c = xml_getTagAttributePtr(c, attrname);
+ if(c == NULL)
+ return NULL;
+ c+=strlen(attrname); /* skip the name */
+ c+=2; /* skip the equals sign and the quote */
+ data_end = strchr(c, '"');
+ data_len = data_end - c;
+ attr = (char *) malloc(data_len+1);
+ strncpy(attr, c, data_len);
+ attr[data_len] = '\0';
+ return attr;
+}
+
+/*
+ * Find the value of an XML tag attribute and convert it to a number.
+ */
+static inline double xml_getTagAttributeFloat(char *c, char *attrname)
+{
+ char *value = xml_getTagAttribute(c, attrname);
+ double ret;
+
+ if(!value)
+ return nan("nan");
+ sscanf(value, "%lf", &ret);
+ free(value);
+ return ret;
+}
+
+/*
+ * Match the beginning an XML tag by "id" (preferred) or Inkscape's
+ * label (undesireable but acceptable).
+ */
+static inline char *xml_idMatchStart(char *stream_pos, char *layer_name)
+{
+ char *id_acceptable = xml_getTagAttribute(stream_pos, "inkscape:label");
+ char *id_preferred = xml_getTagAttribute(stream_pos, "id");
+
+ if(id_preferred && strncasecmp(id_preferred, layer_name, strlen(layer_name)) == 0)
+ {
+ free(id_acceptable);
+ return id_preferred;
+ }
+ if(id_acceptable && strncasecmp(id_acceptable, layer_name, strlen(layer_name)) == 0)
+ {
+ free(id_preferred);
+ return id_acceptable;
+ }
+ free(id_acceptable);
+ free(id_preferred);
+ return NULL;
+}
+
+/*
+ * Match the entirety of an XML tag by "id" (preferred) or Inkscape's
+ * label (undesireable but acceptable).
+ */
+static inline int xml_idMatch(char *stream_pos, char *layer_name)
+{
+ char *id_acceptable = xml_getTagAttribute(stream_pos, "inkscape:label");
+ char *id_preferred = xml_getTagAttribute(stream_pos, "id");
+ int ret = FALSE;
+
+ if((id_preferred && strcasecmp(id_preferred, layer_name) == 0)
+ || (id_acceptable && strcasecmp(id_acceptable, layer_name) == 0))
+ ret = TRUE;
+ free(id_acceptable);
+ free(id_preferred);
+ return ret;
+}
+
+/*
+ * Strip all the XML tags from a string and return only the data not
+ * contained within any tags.
+ */
+static inline char *xml_stripTags(char *data, int len)
+{
+ char *ret = (char *) malloc(len+1);
+ char *tag_left, *tag_right;
+
+ memcpy(ret, data, len+1);
+ ret[len] = '\0';
+ while((tag_left = strchr(ret, '<')) != NULL)
+ {
+ tag_right = strchr(ret, '>');
+ memmove(tag_left, tag_right+1, strlen(ret)-(tag_right-ret));
+ }
+ return ret;
+}
+
+/*
+ * Return the information for all of the icons within a "one-canvas"
+ * data stream.
+ */
+OneCanvasIconInfo onecanvas_geticons(char *stream)
+{
+ eStatus status = STATUS_FINDSVG;
+ unsigned int stream_size = 0;
+ OneCanvasIconInfo info;
+ char *publisher = NULL;
+ char *stream_pos;
+ int i;
+
+ memset(&info, 0, sizeof(info));
+ stream_pos = stream;
+ while(stream_pos)
+ {
+ char *name = xml_getTagName(stream_pos);
+
+ if(!name)
+ {
+ stream_pos = xml_nextTag(stream_pos);
+ continue;
+ }
+ switch(status)
+ {
+ case STATUS_FINDSVG:
+ {
+ if(strcasecmp(name, "svg") == 0)
+ {
+ info.coordinate_start = xml_getTagAttributePtr(stream_pos, "x");
+ info.coordinate_stop = xml_getTagAttributePtr(stream_pos, "viewBox");
+ if(info.coordinate_start == NULL || info.coordinate_stop == NULL)
+ {
+ status = STATUS_FAILED;
+ break;
+ }
+ info.coordinate_stop = strchr(info.coordinate_stop, '"')+1;
+ info.coordinate_stop = strchr(info.coordinate_stop, '"')+1;
+ status = STATUS_FINDMETADATA;
+ }
+ } break;
+ case STATUS_FINDMETADATA:
+ {
+ if(strcasecmp(name, "metadata") == 0)
+ {
+ status = STATUS_FINDPUBLISHER_START;
+ }
+ else if(strcasecmp(name, "/svg") == 0)
+ {
+ status = STATUS_FAILED;
+ }
+ } break;
+ case STATUS_FINDPUBLISHER_START:
+ {
+ if(strcasecmp(name, "dc:publisher") == 0)
+ {
+ status = STATUS_FINDPUBLISHER_STOP;
+ info.publisher_start = stream_pos + strlen("<dc:publisher>");
+ }
+ else if(strcasecmp(name, "/metadata") == 0)
+ {
+ status = STATUS_FAILED;
+ }
+ } break;
+ case STATUS_FINDPUBLISHER_STOP:
+ {
+ if(strcasecmp(name, "/dc:publisher") == 0)
+ {
+ info.publisher_stop = stream_pos;
+ publisher = xml_stripTags(info.publisher_start, info.publisher_stop-info.publisher_start);
+ if(strcasecmp(publisher, "one-canvas") == 0)
+ status = STATUS_FINDHIDDEN;
+ else
+ status = STATUS_FAILED;
+ }
+ else if(strcasecmp(name, "/metadata") == 0)
+ {
+ status = STATUS_FAILED;
+ }
+ } break;
+ case STATUS_FINDHIDDEN:
+ {
+ if(strcasecmp(name, "g") == 0)
+ {
+ if(xml_idMatch(stream_pos, "hidden"))
+ {
+ char *style_start;
+
+ info.hidden_start = stream_pos;
+ info.hidden_stop = info.hidden_start;
+ style_start = xml_getTagAttributePtr(stream_pos, "style");
+ if(style_start)
+ {
+ info.hidden_start = style_start;
+ info.hidden_stop = strchr(style_start, '"')+1;
+ info.hidden_stop = strchr(info.hidden_stop, '"')+1;
+ }
+ else
+ {
+ info.hidden_start += strlen("<g ");
+ info.hidden_stop += strlen("<g ");
+ }
+ status = STATUS_FINDBOUNDS;
+ }
+ }
+ } break;
+ case STATUS_FINDBOUNDS:
+ {
+ if(strcasecmp(name, "rect") == 0)
+ {
+ char *layer_name = xml_idMatchStart(stream_pos, "iconlayer-");
+
+ if(layer_name != NULL)
+ {
+ IconSVG *icon = (IconSVG *) malloc(sizeof(IconSVG));
+
+ icon->x = xml_getTagAttributeFloat(stream_pos, "x");
+ icon->y = xml_getTagAttributeFloat(stream_pos, "y");
+ icon->width = xml_getTagAttributeFloat(stream_pos, "width");
+ icon->height = xml_getTagAttributeFloat(stream_pos, "height");
+ sscanf(layer_name, "iconlayer-%dx%d", &(icon->icon_width), &(icon->icon_height));
+ free(layer_name);
+ status = STATUS_FINDBOUNDS;
+ info.iconlist = (IconSVG **) realloc(info.iconlist, (info.iconlist_num+1)*sizeof(IconSVG *));
+ info.iconlist[info.iconlist_num] = icon;
+ info.iconlist_num++;
+ }
+ }
+ else if(strcasecmp(name, "/g") == 0)
+ {
+ status = STATUS_DONE;
+ }
+ } break;
+ default:
+ break;
+ }
+ if(status == STATUS_DONE || status == STATUS_FAILED)
+ break;
+ stream_pos = xml_nextTag(stream_pos);
+ }
+ free(publisher);
+ info.status = status;
+ return info;
+}
+
+/*
+ * Obtain a single icon from the "one-canvas" stream corresponding
+ * to a particular icon size.
+ */
+char *onecanvas_geticon_bysize(char *icon_data, int requested_size)
+{
+ OneCanvasIconInfo info = onecanvas_geticons(icon_data);
+ char *ret = NULL;
+ int i;
+
+ if(info.status == STATUS_DONE && info.iconlist_num > 0)
+ {
+ int closest_diff = abs(info.iconlist[0]->icon_width - requested_size);
+ int tocoord_length, topubl_length, tohidden_length;
+ int icon_id = 0;
+ IconSVG *icon;
+ int ret_max;
+
+ for(i=0;i<info.iconlist_num;i++)
+ {
+ int size_diff = abs(info.iconlist[i]->icon_width - requested_size);
+
+ if(size_diff < closest_diff)
+ {
+ closest_diff = size_diff;
+ icon_id = i;
+ }
+ }
+ icon = info.iconlist[icon_id];
+ /* Note: 200 characters is a very generous over estimate for the data we add in */
+ ret_max = strlen(icon_data)+1+200;
+ ret = (char *) malloc(ret_max);
+ tocoord_length = info.coordinate_start-icon_data;
+ snprintf(ret, ret_max, "%.*s", tocoord_length, icon_data);
+ /* Output the coordinates of the icon */
+ snprintf(&ret[strlen(ret)], ret_max-strlen(ret), "\nx=\"0px\"\ny=\"0px\"\n");
+ snprintf(&ret[strlen(ret)], ret_max-strlen(ret), "width=\"%d\"\n", icon->icon_width);
+ snprintf(&ret[strlen(ret)], ret_max-strlen(ret), "height=\"%d\"\n", icon->icon_height);
+ snprintf(&ret[strlen(ret)], ret_max-strlen(ret), "viewBox=\"%lf %lf %lf %lf\"\n", icon->x, icon->y, icon->width, icon->height);
+ topubl_length = info.publisher_start-info.coordinate_stop;
+ snprintf(&ret[strlen(ret)], ret_max-strlen(ret), "%.*s", topubl_length, info.coordinate_stop);
+ /* Hide the "hidden" layer */
+ tohidden_length = info.hidden_start-info.publisher_stop;
+ snprintf(&ret[strlen(ret)], ret_max-strlen(ret), "%.*s", tohidden_length, info.publisher_stop);
+ snprintf(&ret[strlen(ret)], ret_max-strlen(ret), "\ndisplay=\"none\"\n");
+ /* Output the rest of the document */
+ snprintf(&ret[strlen(ret)], ret_max-strlen(ret), "%s", info.hidden_stop);
+ }
+ for(i=0;i<info.iconlist_num;i++)
+ free(info.iconlist[i]);
+ free(info.iconlist);
+ return ret;
+} \ No newline at end of file
diff --git a/src/onecanvas.h b/src/onecanvas.h
new file mode 100644
index 0000000..e201417
--- /dev/null
+++ b/src/onecanvas.h
@@ -0,0 +1,6 @@
+#ifndef __ONECANVAS_H
+#define __ONECANVAS_H
+
+char *onecanvas_geticon_bysize(char *icon_data, int requested_size);
+
+#endif /* __ONECANVAS_H */
diff --git a/src/tempfiles.c b/src/tempfiles.c
new file mode 100644
index 0000000..edf72a1
--- /dev/null
+++ b/src/tempfiles.c
@@ -0,0 +1,317 @@
+/*
+ *
+ * Copyright (c) 2009 Erich Hoover
+ *
+ * libr temp files - Handle temporary files and handles that require cleanup
+ * when libr closes.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * To provide feedback, report bugs, or otherwise contact me:
+ * ehoover at mines dot edu
+ *
+ */
+
+#include "tempfiles.h"
+
+/* For malloc/free and mkdtemp */
+#include <stdlib.h>
+
+/* For string handling */
+#include <string.h>
+#include <stdio.h>
+
+/* For directory cleanup */
+#include <unistd.h>
+#include <dirent.h>
+
+/* For directory creation */
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+/* Hold on to folder names for cleanup when libr is removed from memory */
+typedef struct CLEANUPFOLDER {
+ char *folder;
+ struct CLEANUPFOLDER *next;
+} CleanupFolder;
+CleanupFolder *folders_to_remove = NULL;
+
+/* Hold on to libr handles for cleanup when libr is removed from memory */
+typedef struct CLEANUPHANDLE {
+ int internal; /* do not warn the user about cleaning this handle up */
+ libr_file *handle;
+ struct CLEANUPHANDLE *next;
+} CleanupHandle;
+CleanupHandle *handles_to_remove = NULL;
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+/*
+ * Register a folder for cleanup when libr is removed from memory
+ */
+void register_folder_cleanup(char *temp_folder)
+{
+ CleanupFolder *folder = malloc(sizeof(CleanupFolder));
+
+ folder->folder = strdup(temp_folder);
+ folder->next = NULL;
+ if(folders_to_remove != NULL)
+ {
+ CleanupFolder *f;
+
+ for(f = folders_to_remove; f->next != NULL; f = f->next) {}
+ f->next = folder;
+ }
+ else
+ folders_to_remove = folder;
+}
+
+/*
+ * Register a libr handle for cleanup when libr is removed from memory
+ */
+void register_handle_cleanup(libr_file *handle)
+{
+ CleanupHandle *h = malloc(sizeof(CleanupHandle));
+
+ h->handle = handle;
+ h->internal = FALSE;
+ h->next = NULL;
+ if(handles_to_remove != NULL)
+ {
+ CleanupHandle *i;
+
+ for(i = handles_to_remove; i->next != NULL; i = i->next) {}
+ i->next = h;
+ }
+ else
+ handles_to_remove = h;
+}
+
+/*
+ * Remove a libr handle from the cleanup list
+ */
+void unregister_handle_cleanup(libr_file *handle)
+{
+ CleanupHandle *i, *last = NULL;
+ int found = FALSE;
+
+ if(handles_to_remove == NULL)
+ {
+ printf("Unregistering handle with no list of cleanup handles!\n");
+ return;
+ }
+ for(i = handles_to_remove; i != NULL; last = i, i = i->next)
+ {
+ if(i->handle == handle)
+ {
+ if(last == NULL)
+ handles_to_remove = i->next;
+ else
+ last->next = i->next;
+ free(i);
+ found = TRUE;
+ break;
+ }
+ }
+ if(!found)
+ printf("Could not find handle to remove from cleanup list!\n");
+}
+
+/*
+ * Flag a handle as internal (do not warn about unsafe cleanup)
+ */
+void register_internal_handle(libr_file *handle)
+{
+ int found = FALSE;
+ CleanupHandle *i;
+
+ if(handles_to_remove == NULL)
+ {
+ printf("No cleanup list!\n");
+ return;
+ }
+ for(i = handles_to_remove; i != NULL; i = i->next)
+ {
+ if(i->handle == handle)
+ {
+ i->internal = TRUE;
+ found = TRUE;
+ break;
+ }
+ }
+ if(!found)
+ printf("Could not find handle in cleanup list!\n");
+}
+
+/*
+ * Cleanup a temporary folder used to hack the inability to load resources from a buffer
+ */
+void cleanup_folder(char *temp_folder)
+{
+ char *filepath = (char *) malloc(PATH_MAX);
+ DIR *dir = opendir(temp_folder);
+ struct dirent *file;
+
+ while((file = readdir(dir)) != NULL)
+ {
+ char *filename = file->d_name;
+
+ /* Do not delete "self" or "parent" directory entries */
+ if(!strcmp(filename, ".") || !strcmp(filename, ".."))
+ continue;
+ /* But delete anything else */
+ strcpy(filepath, temp_folder);
+ strcat(filepath, "/");
+ strcat(filepath, filename);
+ if(file->d_type == DT_DIR)
+ cleanup_folder(filepath);
+ else
+ {
+ if(unlink(filepath))
+ printf("libr failed to cleanup '%s' in temporary folder: %m\n", filename);
+ }
+ }
+ free(filepath);
+ closedir(dir);
+ if(rmdir(temp_folder) != 0)
+ printf("libr failed to remove temporary folder: %m\n");
+}
+
+/*
+ * Perform cleanup when libr is removed from memory
+ */
+void do_cleanup(void) __attribute__((destructor));
+void do_cleanup(void)
+{
+ CleanupFolder *f, *fnext;
+ CleanupHandle *h, *hnext;
+
+ /* Cleanup folders */
+ for(f = folders_to_remove; f != NULL; f = fnext)
+ {
+ folders_to_remove = NULL;
+ fnext = f->next;
+ cleanup_folder(f->folder);
+ free(f->folder);
+ free(f);
+ }
+ /* Cleanup handles */
+ for(h = handles_to_remove; h != NULL; h = hnext)
+ {
+ handles_to_remove = NULL;
+ hnext = h->next;
+ /* Unless the handle was created internally then warn the developer to cleanup their act */
+ if(!h->internal)
+ printf("Warning: Application did not cleanup resource handle: %p\n", h->handle);
+ libr_close_internal(h->handle);
+ free(h);
+ }
+}
+
+/*
+ * Build all the directories required by a resource
+ * (and construct the output string)
+ */
+int make_valid_path(char *out_path, size_t maxpath, char *start_folder, char *resource_name)
+{
+ char *a, *c = resource_name;
+
+ strcpy(out_path, start_folder);
+ while((a=strchr(c, '/')) != NULL)
+ {
+ strcat(out_path, "/");
+ strncat(out_path, c, (size_t) (a-c));
+ if(mkdir(out_path, S_IRUSR|S_IWUSR|S_IXUSR) != 0)
+ {
+ if(errno != EEXIST)
+ {
+ printf("failed to make directory: %s %m\n", out_path);
+ return false;
+ }
+ }
+ c = a+1;
+ }
+ strcat(out_path, "/");
+ strcat(out_path, c);
+ return true;
+}
+
+/*
+ * Extract all the resources from the ELF file for use by the resource loader
+ */
+char *libr_extract_resources(libr_file *handle)
+{
+ char *temp_mask = strdup(LIBR_TEMPFILE);
+ char *temp_folder;
+ int i = 0;
+
+ temp_folder = mkdtemp(temp_mask);
+ if(temp_folder == NULL)
+ {
+ /* failed to extract ELF resources, could not create a temporary path */
+ goto failed;
+ }
+ /* If this library cannot dynamically load resources then pull out all the resources to a temporary directory */
+ for(i=0;i<libr_resources(handle);i++)
+ {
+ char *resource_name = libr_list(handle, i);
+ char *file_path[PATH_MAX];
+ size_t resource_size;
+ FILE *file_handle;
+ char *resource;
+
+ resource = libr_malloc(handle, resource_name, &resource_size);
+ if(!make_valid_path((char *)file_path, sizeof(file_path), temp_folder, resource_name))
+ {
+ /* failed to build the path required by a resource */
+ cleanup_folder(temp_folder);
+ temp_folder = NULL;
+ goto failed;
+ }
+ file_handle = fopen((const char *) file_path, "w");
+ if(file_handle == NULL)
+ {
+ /* failed to extract ELF resources, could not write to temporary path */
+ cleanup_folder(temp_folder);
+ temp_folder = NULL;
+ goto failed;
+ }
+ /* if the resource is empty then fwrite will fail */
+ if( (resource_size != 0) && (fwrite(resource, resource_size, 1, file_handle) != 1) )
+ {
+ /* failed to extract ELF resources, temporary path out of space? */
+ cleanup_folder(temp_folder);
+ temp_folder = NULL;
+ goto failed;
+ }
+ fclose(file_handle);
+ free(resource);
+ }
+failed:
+ if(temp_folder != NULL)
+ temp_folder = strdup(temp_folder);
+ free(temp_mask);
+ return temp_folder;
+}
diff --git a/src/tempfiles.h b/src/tempfiles.h
new file mode 100644
index 0000000..5b9b0bc
--- /dev/null
+++ b/src/tempfiles.h
@@ -0,0 +1,13 @@
+#ifndef __TEMPFILES_H
+#define __TEMPFILES_H
+
+#include "libr.h"
+
+void cleanup_folder(char *temp_folder);
+void register_handle_cleanup(libr_file *handle);
+void unregister_handle_cleanup(libr_file *handle);
+void register_internal_handle(libr_file *handle);
+void register_folder_cleanup(char *temp_folder);
+char *libr_extract_resources(libr_file *handle);
+
+#endif /* __TEMPFILES_H */