summaryrefslogtreecommitdiff
path: root/support
diff options
context:
space:
mode:
Diffstat (limited to 'support')
-rw-r--r--support/Makefile.am20
-rw-r--r--support/ezxml/Makefile.am4
-rw-r--r--support/ezxml/ezxml.c1015
-rw-r--r--support/ezxml/ezxml.h167
-rw-r--r--support/ezxml/ezxml_init.c6
-rw-r--r--support/glib/Makefile.am9
-rw-r--r--support/glib/fake.c5
-rw-r--r--support/glib/fake.h6
-rw-r--r--support/glib/galias.h0
-rw-r--r--support/glib/galiasdef.c0
-rw-r--r--support/glib/gatomic.c936
-rw-r--r--support/glib/gerror.c381
-rw-r--r--support/glib/gerror.h92
-rw-r--r--support/glib/ghash.c1202
-rw-r--r--support/glib/ghash.h145
-rw-r--r--support/glib/glib.h40
-rw-r--r--support/glib/glib_init.c6
-rw-r--r--support/glib/glibconfig.h264
-rw-r--r--support/glib/glibintl.h39
-rw-r--r--support/glib/glist.c999
-rw-r--r--support/glib/glist.h120
-rw-r--r--support/glib/gmacros.h273
-rw-r--r--support/glib/gmem.c742
-rw-r--r--support/glib/gmem.h152
-rw-r--r--support/glib/gmessages.c1126
-rw-r--r--support/glib/gmessages.h341
-rw-r--r--support/glib/gprimes.c90
-rw-r--r--support/glib/gprintf.c342
-rw-r--r--support/glib/gprintf.h52
-rw-r--r--support/glib/gprintfint.h59
-rw-r--r--support/glib/gquark.h52
-rw-r--r--support/glib/gslice.c1493
-rw-r--r--support/glib/gslice.h90
-rw-r--r--support/glib/gstrfuncs.c3125
-rw-r--r--support/glib/gstrfuncs.h266
-rw-r--r--support/glib/gstring.c1488
-rw-r--r--support/glib/gthreadprivate.h68
-rw-r--r--support/glib/gtypes.h432
-rw-r--r--support/glib/gunicode.h404
-rw-r--r--support/glib/gutf8.c1866
-rw-r--r--support/glib/gutils.c3416
-rw-r--r--support/libc/Makefile.am4
-rw-r--r--support/libc/errno.h4
-rw-r--r--support/libc/libc.c158
-rw-r--r--support/libc/libc_init.c6
-rw-r--r--support/libc/locale.h12
-rw-r--r--support/libc/signal.h2
-rw-r--r--support/win32/ConvertUTF.c539
-rw-r--r--support/win32/ConvertUTF.h149
-rw-r--r--support/win32/Makefile.am4
-rw-r--r--support/win32/mmap.c43
-rw-r--r--support/win32/sys/mman.h8
-rw-r--r--support/win32/win32_init.c6
-rw-r--r--support/wordexp/Makefile.am4
-rw-r--r--support/wordexp/glob.c108
-rw-r--r--support/wordexp/glob.h19
-rw-r--r--support/wordexp/wordexp.c134
-rw-r--r--support/wordexp/wordexp.h42
-rw-r--r--support/wordexp/wordexp_init.c6
-rw-r--r--support/zlib/Makefile.am4
-rw-r--r--support/zlib/adler32.c149
-rw-r--r--support/zlib/crc32.c423
-rw-r--r--support/zlib/crc32.h441
-rw-r--r--support/zlib/infback.c623
-rw-r--r--support/zlib/inffast.c318
-rw-r--r--support/zlib/inffast.h11
-rw-r--r--support/zlib/inffixed.h94
-rw-r--r--support/zlib/inflate.c1368
-rw-r--r--support/zlib/inflate.h115
-rw-r--r--support/zlib/inftrees.c329
-rw-r--r--support/zlib/inftrees.h55
-rw-r--r--support/zlib/zconf.h332
-rw-r--r--support/zlib/zlib.h1357
-rw-r--r--support/zlib/zlib_init.c6
-rw-r--r--support/zlib/zutil.c318
-rw-r--r--support/zlib/zutil.h269
76 files changed, 28793 insertions, 0 deletions
diff --git a/support/Makefile.am b/support/Makefile.am
new file mode 100644
index 00000000..8a488cde
--- /dev/null
+++ b/support/Makefile.am
@@ -0,0 +1,20 @@
+SUBDIRS=
+if SUPPORT_EZXML
+ SUBDIRS+=ezxml
+endif
+if SUPPORT_GLIB
+ SUBDIRS+=glib
+endif
+if SUPPORT_WORDEXP
+ SUBDIRS+=wordexp
+endif
+if SUPPORT_WIN32
+ SUBDIRS+=win32
+endif
+if SUPPORT_ZLIB
+ SUBDIRS+=zlib
+endif
+if SUPPORT_LIBC
+ SUBDIRS+=libc
+endif
+DIST_SUBDIRS=ezxml glib wordexp win32 zlib libc
diff --git a/support/ezxml/Makefile.am b/support/ezxml/Makefile.am
new file mode 100644
index 00000000..1b091a39
--- /dev/null
+++ b/support/ezxml/Makefile.am
@@ -0,0 +1,4 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=support_ezxml -DEZXML_NOMMAP
+noinst_LTLIBRARIES = libsupport_ezxml.la
+libsupport_ezxml_la_SOURCES = ezxml.c ezxml_init.c ezxml.h
diff --git a/support/ezxml/ezxml.c b/support/ezxml/ezxml.c
new file mode 100644
index 00000000..7095c775
--- /dev/null
+++ b/support/ezxml/ezxml.c
@@ -0,0 +1,1015 @@
+/* ezxml.c
+ *
+ * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#ifndef EZXML_NOMMAP
+#include <sys/mman.h>
+#endif // EZXML_NOMMAP
+#include <sys/stat.h>
+#include "ezxml.h"
+
+#define EZXML_WS "\t\r\n " // whitespace
+#define EZXML_ERRL 128 // maximum error string length
+
+typedef struct ezxml_root *ezxml_root_t;
+struct ezxml_root { // additional data for the root tag
+ struct ezxml xml; // is a super-struct built on top of ezxml struct
+ ezxml_t cur; // current xml tree insertion point
+ char *m; // original xml string
+ size_t len; // length of allocated memory for mmap, -1 for malloc
+ char *u; // UTF-8 conversion of string if original was UTF-16
+ char *s; // start of work area
+ char *e; // end of work area
+ char **ent; // general entities (ampersand sequences)
+ char ***attr; // default attributes
+ char ***pi; // processing instructions
+ short standalone; // non-zero if <?xml standalone="yes"?>
+ char err[EZXML_ERRL]; // error string
+};
+
+char *EZXML_NIL[] = { NULL }; // empty, null terminated array of strings
+
+// returns the first child tag with the given name or NULL if not found
+ezxml_t ezxml_child(ezxml_t xml, const char *name)
+{
+ xml = (xml) ? xml->child : NULL;
+ while (xml && strcmp(name, xml->name)) xml = xml->sibling;
+ return xml;
+}
+
+// returns the Nth tag with the same name in the same subsection or NULL if not
+// found
+ezxml_t ezxml_idx(ezxml_t xml, int idx)
+{
+ for (; xml && idx; idx--) xml = xml->next;
+ return xml;
+}
+
+// returns the value of the requested tag attribute or NULL if not found
+const char *ezxml_attr(ezxml_t xml, const char *attr)
+{
+ int i = 0, j = 1;
+ ezxml_root_t root = (ezxml_root_t)xml;
+
+ if (! xml || ! xml->attr) return NULL;
+ while (xml->attr[i] && strcmp(attr, xml->attr[i])) i += 2;
+ if (xml->attr[i]) return xml->attr[i + 1]; // found attribute
+
+ while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+ for (i = 0; root->attr[i] && strcmp(xml->name, root->attr[i][0]); i++);
+ if (! root->attr[i]) return NULL; // no matching default attributes
+ while (root->attr[i][j] && strcmp(attr, root->attr[i][j])) j += 3;
+ return (root->attr[i][j]) ? root->attr[i][j + 1] : NULL; // found default
+}
+
+// same as ezxml_get but takes an already initialized va_list
+ezxml_t ezxml_vget(ezxml_t xml, va_list ap)
+{
+ char *name = va_arg(ap, char *);
+ int idx = -1;
+
+ if (name && *name) {
+ idx = va_arg(ap, int);
+ xml = ezxml_child(xml, name);
+ }
+ return (idx < 0) ? xml : ezxml_vget(ezxml_idx(xml, idx), ap);
+}
+
+// Traverses the xml tree to retrieve a specific subtag. Takes a variable
+// length list of tag names and indexes. The argument list must be terminated
+// by either an index of -1 or an empty string tag name. Example:
+// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
+// This retrieves the title of the 3rd book on the 1st shelf of library.
+// Returns NULL if not found.
+ezxml_t ezxml_get(ezxml_t xml, ...)
+{
+ va_list ap;
+ ezxml_t r;
+
+ va_start(ap, xml);
+ r = ezxml_vget(xml, ap);
+ va_end(ap);
+ return r;
+}
+
+// returns a null terminated array of processing instructions for the given
+// target
+const char **ezxml_pi(ezxml_t xml, const char *target)
+{
+ ezxml_root_t root = (ezxml_root_t)xml;
+ int i = 0;
+
+ if (! root) return (const char **)EZXML_NIL;
+ while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+ while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
+ return (const char **)((root->pi[i]) ? root->pi[i] + 1 : EZXML_NIL);
+}
+
+// set an error string and return root
+ezxml_t ezxml_err(ezxml_root_t root, char *s, const char *err, ...)
+{
+ va_list ap;
+ int line = 1;
+ char *t, fmt[EZXML_ERRL];
+
+ for (t = root->s; t < s; t++) if (*t == '\n') line++;
+ snprintf(fmt, EZXML_ERRL, "[error near line %d]: %s", line, err);
+
+ va_start(ap, err);
+ vsnprintf(root->err, EZXML_ERRL, fmt, ap);
+ va_end(ap);
+
+ return &root->xml;
+}
+
+// Recursively decodes entity and character references and normalizes new lines
+// ent is a null terminated array of alternating entity names and values. set t
+// to '&' for general entity decoding, '%' for parameter entity decoding, 'c'
+// for cdata sections, ' ' for attribute normalization, or '*' for non-cdata
+// attribute normalization. Returns s, or if the decoded string is longer than
+// s, returns a malloced string that must be freed.
+char *ezxml_decode(char *s, char **ent, char t)
+{
+ char *e, *r = s, *m = s;
+ long b, c, d, l;
+
+ for (; *s; s++) { // normalize line endings
+ while (*s == '\r') {
+ *(s++) = '\n';
+ if (*s == '\n') memmove(s, (s + 1), strlen(s));
+ }
+ }
+
+ for (s = r; ; ) {
+ while (*s && *s != '&' && (*s != '%' || t != '%') && !isspace(*s)) s++;
+
+ if (! *s) break;
+ else if (t != 'c' && ! strncmp(s, "&#", 2)) { // character reference
+ if (s[2] == 'x') c = strtol(s + 3, &e, 16); // base 16
+ else c = strtol(s + 2, &e, 10); // base 10
+ if (! c || *e != ';') { s++; continue; } // not a character ref
+
+ if (c < 0x80) *(s++) = c; // US-ASCII subset
+ else { // multi-byte UTF-8 sequence
+ for (b = 0, d = c; d; d /= 2) b++; // number of bits in c
+ b = (b - 2) / 5; // number of bytes in payload
+ *(s++) = (0xFF << (7 - b)) | (c >> (6 * b)); // head
+ while (b) *(s++) = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload
+ }
+
+ memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';')));
+ }
+ else if ((*s == '&' && (t == '&' || t == ' ' || t == '*')) ||
+ (*s == '%' && t == '%')) { // entity reference
+ for (b = 0; ent[b] && strncmp(s + 1, ent[b], strlen(ent[b]));
+ b += 2); // find entity in entity list
+
+ if (ent[b++]) { // found a match
+ if ((c = strlen(ent[b])) - 1 > (e = strchr(s, ';')) - s) {
+ l = (d = (s - r)) + c + strlen(e); // new length
+ r = (r == m) ? strcpy(malloc(l), r) : realloc(r, l);
+ e = strchr((s = r + d), ';'); // fix up pointers
+ }
+
+ memmove(s + c, e + 1, strlen(e)); // shift rest of string
+ strncpy(s, ent[b], c); // copy in replacement text
+ }
+ else s++; // not a known entity
+ }
+ else if ((t == ' ' || t == '*') && isspace(*s)) *(s++) = ' ';
+ else s++; // no decoding needed
+ }
+
+ if (t == '*') { // normalize spaces for non-cdata attributes
+ for (s = r; *s; s++) {
+ if ((l = strspn(s, " "))) memmove(s, s + l, strlen(s + l) + 1);
+ while (*s && *s != ' ') s++;
+ }
+ if (--s >= r && *s == ' ') *s = '\0'; // trim any trailing space
+ }
+ return r;
+}
+
+// called when parser finds start of new tag
+void ezxml_open_tag(ezxml_root_t root, char *name, char **attr)
+{
+ ezxml_t xml = root->cur;
+
+ if (xml->name) xml = ezxml_add_child(xml, name, strlen(xml->txt));
+ else xml->name = name; // first open tag
+
+ xml->attr = attr;
+ root->cur = xml; // update tag insertion point
+}
+
+// called when parser finds character content between open and closing tag
+void ezxml_char_content(ezxml_root_t root, char *s, size_t len, char t)
+{
+ ezxml_t xml = root->cur;
+ char *m = s;
+ size_t l;
+
+ if (! xml || ! xml->name || ! len) return; // sanity check
+
+ s[len] = '\0'; // null terminate text (calling functions anticipate this)
+ len = strlen(s = ezxml_decode(s, root->ent, t)) + 1;
+
+ if (! *(xml->txt)) xml->txt = s; // initial character content
+ else { // allocate our own memory and make a copy
+ xml->txt = (xml->flags & EZXML_TXTM) // allocate some space
+ ? realloc(xml->txt, (l = strlen(xml->txt)) + len)
+ : strcpy(malloc((l = strlen(xml->txt)) + len), xml->txt);
+ strcpy(xml->txt + l, s); // add new char content
+ if (s != m) free(s); // free s if it was malloced by ezxml_decode()
+ }
+
+ if (xml->txt != m) ezxml_set_flag(xml, EZXML_TXTM);
+}
+
+// called when parser finds closing tag
+ezxml_t ezxml_close_tag(ezxml_root_t root, char *name, char *s)
+{
+ if (! root->cur || ! root->cur->name || strcmp(name, root->cur->name))
+ return ezxml_err(root, s, "unexpected closing tag </%s>", name);
+
+ root->cur = root->cur->parent;
+ return NULL;
+}
+
+// checks for circular entity references, returns non-zero if no circular
+// references are found, zero otherwise
+int ezxml_ent_ok(char *name, char *s, char **ent)
+{
+ int i;
+
+ for (; ; s++) {
+ while (*s && *s != '&') s++; // find next entity reference
+ if (! *s) return 1;
+ if (! strncmp(s + 1, name, strlen(name))) return 0; // circular ref.
+ for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2);
+ if (ent[i] && ! ezxml_ent_ok(name, ent[i + 1], ent)) return 0;
+ }
+}
+
+// called when the parser finds a processing instruction
+void ezxml_proc_inst(ezxml_root_t root, char *s, size_t len)
+{
+ int i = 0, j = 1;
+ char *target = s;
+
+ s[len] = '\0'; // null terminate instruction
+ if (*(s += strcspn(s, EZXML_WS))) {
+ *s = '\0'; // null terminate target
+ s += strspn(s + 1, EZXML_WS) + 1; // skip whitespace after target
+ }
+
+ if (! strcmp(target, "xml")) { // <?xml ... ?>
+ if ((s = strstr(s, "standalone")) && ! strncmp(s + strspn(s + 10,
+ EZXML_WS "='\"") + 10, "yes", 3)) root->standalone = 1;
+ return;
+ }
+
+ if (! root->pi[0]) *(root->pi = malloc(sizeof(char **))) = NULL; //first pi
+
+ while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
+ if (! root->pi[i]) { // new target
+ root->pi = realloc(root->pi, sizeof(char **) * (i + 2));
+ root->pi[i] = malloc(sizeof(char *) * 3);
+ root->pi[i][0] = target;
+ root->pi[i][1] = (char *)(root->pi[i + 1] = NULL); // terminate pi list
+ root->pi[i][2] = strdup(""); // empty document position list
+ }
+
+ while (root->pi[i][j]) j++; // find end of instruction list for this target
+ root->pi[i] = realloc(root->pi[i], sizeof(char *) * (j + 3));
+ root->pi[i][j + 2] = realloc(root->pi[i][j + 1], j + 1);
+ strcpy(root->pi[i][j + 2] + j - 1, (root->xml.name) ? ">" : "<");
+ root->pi[i][j + 1] = NULL; // null terminate pi list for this target
+ root->pi[i][j] = s; // set instruction
+}
+
+// called when the parser finds an internal doctype subset
+short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len)
+{
+ char q, *c, *t, *n = NULL, *v, **ent, **pe;
+ int i, j;
+
+ pe = memcpy(malloc(sizeof(EZXML_NIL)), EZXML_NIL, sizeof(EZXML_NIL));
+
+ for (s[len] = '\0'; s; ) {
+ while (*s && *s != '<' && *s != '%') s++; // find next declaration
+
+ if (! *s) break;
+ else if (! strncmp(s, "<!ENTITY", 8)) { // parse entity definitions
+ c = s += strspn(s + 8, EZXML_WS) + 8; // skip white space separator
+ n = s + strspn(s, EZXML_WS "%"); // find name
+ *(s = n + strcspn(n, EZXML_WS)) = ';'; // append ; to name
+
+ v = s + strspn(s + 1, EZXML_WS) + 1; // find value
+ if ((q = *(v++)) != '"' && q != '\'') { // skip externals
+ s = strchr(s, '>');
+ continue;
+ }
+
+ for (i = 0, ent = (*c == '%') ? pe : root->ent; ent[i]; i++);
+ ent = realloc(ent, (i + 3) * sizeof(char *)); // space for next ent
+ if (*c == '%') pe = ent;
+ else root->ent = ent;
+
+ *(++s) = '\0'; // null terminate name
+ if ((s = strchr(v, q))) *(s++) = '\0'; // null terminate value
+ ent[i + 1] = ezxml_decode(v, pe, '%'); // set value
+ ent[i + 2] = NULL; // null terminate entity list
+ if (! ezxml_ent_ok(n, ent[i + 1], ent)) { // circular reference
+ if (ent[i + 1] != v) free(ent[i + 1]);
+ ezxml_err(root, v, "circular entity declaration &%s", n);
+ break;
+ }
+ else ent[i] = n; // set entity name
+ }
+ else if (! strncmp(s, "<!ATTLIST", 9)) { // parse default attributes
+ t = s + strspn(s + 9, EZXML_WS) + 9; // skip whitespace separator
+ if (! *t) { ezxml_err(root, t, "unclosed <!ATTLIST"); break; }
+ if (*(s = t + strcspn(t, EZXML_WS ">")) == '>') continue;
+ else *s = '\0'; // null terminate tag name
+ for (i = 0; root->attr[i] && strcmp(n, root->attr[i][0]); i++);
+
+ while (*(n = ++s + strspn(s, EZXML_WS)) && *n != '>') {
+ if (*(s = n + strcspn(n, EZXML_WS))) *s = '\0'; // attr name
+ else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+ s += strspn(s + 1, EZXML_WS) + 1; // find next token
+ c = (strncmp(s, "CDATA", 5)) ? "*" : " "; // is it cdata?
+ if (! strncmp(s, "NOTATION", 8))
+ s += strspn(s + 8, EZXML_WS) + 8;
+ s = (*s == '(') ? strchr(s, ')') : s + strcspn(s, EZXML_WS);
+ if (! s) { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+ s += strspn(s, EZXML_WS ")"); // skip white space separator
+ if (! strncmp(s, "#FIXED", 6))
+ s += strspn(s + 6, EZXML_WS) + 6;
+ if (*s == '#') { // no default value
+ s += strcspn(s, EZXML_WS ">") - 1;
+ if (*c == ' ') continue; // cdata is default, nothing to do
+ v = NULL;
+ }
+ else if ((*s == '"' || *s == '\'') && // default value
+ (s = strchr(v = s + 1, *s))) *s = '\0';
+ else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+ if (! root->attr[i]) { // new tag name
+ root->attr = (! i) ? malloc(2 * sizeof(char **))
+ : realloc(root->attr,
+ (i + 2) * sizeof(char **));
+ root->attr[i] = malloc(2 * sizeof(char *));
+ root->attr[i][0] = t; // set tag name
+ root->attr[i][1] = (char *)(root->attr[i + 1] = NULL);
+ }
+
+ for (j = 1; root->attr[i][j]; j += 3); // find end of list
+ root->attr[i] = realloc(root->attr[i],
+ (j + 4) * sizeof(char *));
+
+ root->attr[i][j + 3] = NULL; // null terminate list
+ root->attr[i][j + 2] = c; // is it cdata?
+ root->attr[i][j + 1] = (v) ? ezxml_decode(v, root->ent, *c)
+ : NULL;
+ root->attr[i][j] = n; // attribute name
+ }
+ }
+ else if (! strncmp(s, "<!--", 4)) s = strstr(s + 4, "-->"); // comments
+ else if (! strncmp(s, "<?", 2)) { // processing instructions
+ if ((s = strstr(c = s + 2, "?>")))
+ ezxml_proc_inst(root, c, s++ - c);
+ }
+ else if (*s == '<') s = strchr(s, '>'); // skip other declarations
+ else if (*(s++) == '%' && ! root->standalone) break;
+ }
+
+ free(pe);
+ return ! *root->err;
+}
+
+// Converts a UTF-16 string to UTF-8. Returns a new string that must be freed
+// or NULL if no conversion was needed.
+char *ezxml_str2utf8(char **s, size_t *len)
+{
+ char *u;
+ size_t l = 0, sl, max = *len;
+ long c, d;
+ int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1;
+
+ if (be == -1) return NULL; // not UTF-16
+
+ u = malloc(max);
+ for (sl = 2; sl < *len - 1; sl += 2) {
+ c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF) //UTF-16BE
+ : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); //UTF-16LE
+ if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { // high-half
+ d = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)
+ : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF);
+ c = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000;
+ }
+
+ while (l + 6 > max) u = realloc(u, max += EZXML_BUFSIZE);
+ if (c < 0x80) u[l++] = c; // US-ASCII subset
+ else { // multi-byte UTF-8 sequence
+ for (b = 0, d = c; d; d /= 2) b++; // bits in c
+ b = (b - 2) / 5; // bytes in payload
+ u[l++] = (0xFF << (7 - b)) | (c >> (6 * b)); // head
+ while (b) u[l++] = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload
+ }
+ }
+ return *s = realloc(u, *len = l);
+}
+
+// frees a tag attribute list
+void ezxml_free_attr(char **attr) {
+ int i = 0;
+ char *m;
+
+ if (! attr || attr == EZXML_NIL) return; // nothing to free
+ while (attr[i]) i += 2; // find end of attribute list
+ m = attr[i + 1]; // list of which names and values are malloced
+ for (i = 0; m[i]; i++) {
+ if (m[i] & EZXML_NAMEM) free(attr[i * 2]);
+ if (m[i] & EZXML_TXTM) free(attr[(i * 2) + 1]);
+ }
+ free(m);
+ free(attr);
+}
+
+// parse the given xml string and return an ezxml structure
+ezxml_t ezxml_parse_str(char *s, size_t len)
+{
+ ezxml_root_t root = (ezxml_root_t)ezxml_new(NULL);
+ char q, e, *d, **attr, **a = NULL; // initialize a to avoid compile warning
+ int l, i, j;
+
+ root->m = s;
+ if (! len) return ezxml_err(root, NULL, "root tag missing");
+ root->u = ezxml_str2utf8(&s, &len); // convert utf-16 to utf-8
+ root->e = (root->s = s) + len; // record start and end of work area
+
+ e = s[len - 1]; // save end char
+ s[len - 1] = '\0'; // turn end char into null terminator
+
+ while (*s && *s != '<') s++; // find first tag
+ if (! *s) return ezxml_err(root, s, "root tag missing");
+
+ for (; ; ) {
+ attr = (char **)EZXML_NIL;
+ d = ++s;
+
+ if (isalpha(*s) || *s == '_' || *s == ':' || *s < '\0') { // new tag
+ if (! root->cur)
+ return ezxml_err(root, d, "markup outside of root element");
+
+ s += strcspn(s, EZXML_WS "/>");
+ while (isspace(*s)) *(s++) = '\0'; // null terminate tag name
+
+ if (*s && *s != '/' && *s != '>') // find tag in default attr list
+ for (i = 0; (a = root->attr[i]) && strcmp(a[0], d); i++);
+
+ for (l = 0; *s && *s != '/' && *s != '>'; l += 2) { // new attrib
+ attr = (l) ? realloc(attr, (l + 4) * sizeof(char *))
+ : malloc(4 * sizeof(char *)); // allocate space
+ attr[l + 3] = (l) ? realloc(attr[l + 1], (l / 2) + 2)
+ : malloc(2); // mem for list of maloced vals
+ strcpy(attr[l + 3] + (l / 2), " "); // value is not malloced
+ attr[l + 2] = NULL; // null terminate list
+ attr[l + 1] = ""; // temporary attribute value
+ attr[l] = s; // set attribute name
+
+ s += strcspn(s, EZXML_WS "=/>");
+ if (*s == '=' || isspace(*s)) {
+ *(s++) = '\0'; // null terminate tag attribute name
+ q = *(s += strspn(s, EZXML_WS "="));
+ if (q == '"' || q == '\'') { // attribute value
+ attr[l + 1] = ++s;
+ while (*s && *s != q) s++;
+ if (*s) *(s++) = '\0'; // null terminate attribute val
+ else {
+ ezxml_free_attr(attr);
+ return ezxml_err(root, d, "missing %c", q);
+ }
+
+ for (j = 1; a && a[j] && strcmp(a[j], attr[l]); j +=3);
+ attr[l + 1] = ezxml_decode(attr[l + 1], root->ent, (a
+ && a[j]) ? *a[j + 2] : ' ');
+ if (attr[l + 1] < d || attr[l + 1] > s)
+ attr[l + 3][l / 2] = EZXML_TXTM; // value malloced
+ }
+ }
+ while (isspace(*s)) s++;
+ }
+
+ if (*s == '/') { // self closing tag
+ *(s++) = '\0';
+ if ((*s && *s != '>') || (! *s && e != '>')) {
+ if (l) ezxml_free_attr(attr);
+ return ezxml_err(root, d, "missing >");
+ }
+ ezxml_open_tag(root, d, attr);
+ ezxml_close_tag(root, d, s);
+ }
+ else if ((q = *s) == '>' || (! *s && e == '>')) { // open tag
+ *s = '\0'; // temporarily null terminate tag name
+ ezxml_open_tag(root, d, attr);
+ *s = q;
+ }
+ else {
+ if (l) ezxml_free_attr(attr);
+ return ezxml_err(root, d, "missing >");
+ }
+ }
+ else if (*s == '/') { // close tag
+ s += strcspn(d = s + 1, EZXML_WS ">") + 1;
+ if (! (q = *s) && e != '>') return ezxml_err(root, d, "missing >");
+ *s = '\0'; // temporarily null terminate tag name
+ if (ezxml_close_tag(root, d, s)) return &root->xml;
+ if (isspace(*s = q)) s += strspn(s, EZXML_WS);
+ }
+ else if (! strncmp(s, "!--", 3)) { // xml comment
+ if (! (s = strstr(s + 3, "--")) || (*(s += 2) != '>' && *s) ||
+ (! *s && e != '>')) return ezxml_err(root, d, "unclosed <!--");
+ }
+ else if (! strncmp(s, "![CDATA[", 8)) { // cdata
+ if ((s = strstr(s, "]]>")))
+ ezxml_char_content(root, d + 8, (s += 2) - d - 10, 'c');
+ else return ezxml_err(root, d, "unclosed <![CDATA[");
+ }
+ else if (! strncmp(s, "!DOCTYPE", 8)) { // dtd
+ for (l = 0; *s && ((! l && *s != '>') || (l && (*s != ']' ||
+ *(s + strspn(s + 1, EZXML_WS) + 1) != '>')));
+ l = (*s == '[') ? 1 : l) s += strcspn(s + 1, "[]>") + 1;
+ if (! *s && e != '>')
+ return ezxml_err(root, d, "unclosed <!DOCTYPE");
+ d = (l) ? strchr(d, '[') + 1 : d;
+ if (l && ! ezxml_internal_dtd(root, d, s++ - d)) return &root->xml;
+ }
+ else if (*s == '?') { // <?...?> processing instructions
+ do { s = strchr(s, '?'); } while (s && *(++s) && *s != '>');
+ if (! s || (! *s && e != '>'))
+ return ezxml_err(root, d, "unclosed <?");
+ else ezxml_proc_inst(root, d + 1, s - d - 2);
+ }
+ else return ezxml_err(root, d, "unexpected <");
+
+ if (! s || ! *s) break;
+ *s = '\0';
+ d = ++s;
+ if (*s && *s != '<') { // tag character content
+ while (*s && *s != '<') s++;
+ if (*s) ezxml_char_content(root, d, s - d, '&');
+ else break;
+ }
+ else if (! *s) break;
+ }
+
+ if (! root->cur) return &root->xml;
+ else if (! root->cur->name) return ezxml_err(root, d, "root tag missing");
+ else return ezxml_err(root, d, "unclosed tag <%s>", root->cur->name);
+}
+
+// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
+// stream into memory and then parses it. For xml files, use ezxml_parse_file()
+// or ezxml_parse_fd()
+ezxml_t ezxml_parse_fp(FILE *fp)
+{
+ ezxml_root_t root;
+ size_t l, len = 0;
+ char *s;
+
+ if (! (s = malloc(EZXML_BUFSIZE))) return NULL;
+ do {
+ len += (l = fread((s + len), 1, EZXML_BUFSIZE, fp));
+ if (l == EZXML_BUFSIZE) s = realloc(s, len + EZXML_BUFSIZE);
+ } while (s && l == EZXML_BUFSIZE);
+
+ if (! s) return NULL;
+ root = (ezxml_root_t)ezxml_parse_str(s, len);
+ root->len = -1; // so we know to free s in ezxml_free()
+ return &root->xml;
+}
+
+// A wrapper for ezxml_parse_str() that accepts a file descriptor. First
+// attempts to mem map the file. Failing that, reads the file into memory.
+// Returns NULL on failure.
+ezxml_t ezxml_parse_fd(int fd)
+{
+ ezxml_root_t root;
+ struct stat st;
+ size_t l;
+ void *m;
+
+ if (fd == -1) return NULL;
+ fstat(fd, &st);
+
+#ifndef EZXML_NOMMAP
+ l = (st.st_size + sysconf(_SC_PAGESIZE) - 1) & ~(sysconf(_SC_PAGESIZE) -1);
+ if ((m = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) !=
+ MAP_FAILED) {
+ madvise(m, l, MADV_SEQUENTIAL); // optimize for sequential access
+ root = (ezxml_root_t)ezxml_parse_str(m, st.st_size);
+ madvise(m, root->len = l, MADV_NORMAL); // put it back to normal
+ }
+ else { // mmap failed, read file into memory
+#endif // EZXML_NOMMAP
+ l = read(fd, m = malloc(st.st_size), st.st_size);
+ root = (ezxml_root_t)ezxml_parse_str(m, l);
+ root->len = -1; // so we know to free s in ezxml_free()
+#ifndef EZXML_NOMMAP
+ }
+#endif // EZXML_NOMMAP
+ return &root->xml;
+}
+
+// a wrapper for ezxml_parse_fd that accepts a file name
+ezxml_t ezxml_parse_file(const char *file)
+{
+ int fd = open(file, O_RDONLY, 0);
+ ezxml_t xml = ezxml_parse_fd(fd);
+
+ if (fd >= 0) close(fd);
+ return xml;
+}
+
+// Encodes ampersand sequences appending the results to *dst, reallocating *dst
+// if length excedes max. a is non-zero for attribute encoding. Returns *dst
+char *ezxml_ampencode(const char *s, size_t len, char **dst, size_t *dlen,
+ size_t *max, short a)
+{
+ const char *e;
+
+ for (e = s + len; s != e; s++) {
+ while (*dlen + 10 > *max) *dst = realloc(*dst, *max += EZXML_BUFSIZE);
+
+ switch (*s) {
+ case '\0': return *dst;
+ case '&': *dlen += sprintf(*dst + *dlen, "&amp;"); break;
+ case '<': *dlen += sprintf(*dst + *dlen, "&lt;"); break;
+ case '>': *dlen += sprintf(*dst + *dlen, "&gt;"); break;
+ case '"': *dlen += sprintf(*dst + *dlen, (a) ? "&quot;" : "\""); break;
+ case '\n': *dlen += sprintf(*dst + *dlen, (a) ? "&#xA;" : "\n"); break;
+ case '\t': *dlen += sprintf(*dst + *dlen, (a) ? "&#x9;" : "\t"); break;
+ case '\r': *dlen += sprintf(*dst + *dlen, "&#xD;"); break;
+ default: (*dst)[(*dlen)++] = *s;
+ }
+ }
+ return *dst;
+}
+
+// Recursively converts each tag to xml appending it to *s. Reallocates *s if
+// its length excedes max. start is the location of the previous tag in the
+// parent tag's character content. Returns *s.
+char *ezxml_toxml_r(ezxml_t xml, char **s, size_t *len, size_t *max,
+ size_t start, char ***attr)
+{
+ int i, j;
+ char *txt = (xml->parent) ? xml->parent->txt : "";
+ size_t off = 0;
+
+ // parent character content up to this tag
+ *s = ezxml_ampencode(txt + start, xml->off - start, s, len, max, 0);
+
+ while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, "<%s", xml->name); // open tag
+ for (i = 0; xml->attr[i]; i += 2) { // tag attributes
+ if (ezxml_attr(xml, xml->attr[i]) != xml->attr[i + 1]) continue;
+ while (*len + strlen(xml->attr[i]) + 7 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, " %s=\"", xml->attr[i]);
+ ezxml_ampencode(xml->attr[i + 1], -1, s, len, max, 1);
+ *len += sprintf(*s + *len, "\"");
+ }
+
+ for (i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++);
+ for (j = 1; attr[i] && attr[i][j]; j += 3) { // default attributes
+ if (! attr[i][j + 1] || ezxml_attr(xml, attr[i][j]) != attr[i][j + 1])
+ continue; // skip duplicates and non-values
+ while (*len + strlen(attr[i][j]) + 7 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, " %s=\"", attr[i][j]);
+ ezxml_ampencode(attr[i][j + 1], -1, s, len, max, 1);
+ *len += sprintf(*s + *len, "\"");
+ }
+ *len += sprintf(*s + *len, ">");
+
+ *s = (xml->child) ? ezxml_toxml_r(xml->child, s, len, max, 0, attr) //child
+ : ezxml_ampencode(xml->txt, -1, s, len, max, 0); //data
+
+ while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, "</%s>", xml->name); // close tag
+
+ while (txt[off] && off < xml->off) off++; // make sure off is within bounds
+ return (xml->ordered) ? ezxml_toxml_r(xml->ordered, s, len, max, off, attr)
+ : ezxml_ampencode(txt + off, -1, s, len, max, 0);
+}
+
+// Converts an ezxml structure back to xml. Returns a string of xml data that
+// must be freed.
+char *ezxml_toxml(ezxml_t xml)
+{
+ ezxml_t p = (xml) ? xml->parent : NULL, o = (xml) ? xml->ordered : NULL;
+ ezxml_root_t root = (ezxml_root_t)xml;
+ size_t len = 0, max = EZXML_BUFSIZE;
+ char *s = strcpy(malloc(max), ""), *t, *n;
+ int i, j, k;
+
+ if (! xml || ! xml->name) return realloc(s, len + 1);
+ while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+
+ for (i = 0; ! p && root->pi[i]; i++) { // pre-root processing instructions
+ for (k = 2; root->pi[i][k - 1]; k++);
+ for (j = 1; (n = root->pi[i][j]); j++) {
+ if (root->pi[i][k][j - 1] == '>') continue; // not pre-root
+ while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
+ s = realloc(s, max += EZXML_BUFSIZE);
+ len += sprintf(s + len, "<?%s%s%s?>\n", t, *n ? " " : "", n);
+ }
+ }
+
+ xml->parent = xml->ordered = NULL;
+ s = ezxml_toxml_r(xml, &s, &len, &max, 0, root->attr);
+ xml->parent = p;
+ xml->ordered = o;
+
+ for (i = 0; ! p && root->pi[i]; i++) { // post-root processing instructions
+ for (k = 2; root->pi[i][k - 1]; k++);
+ for (j = 1; (n = root->pi[i][j]); j++) {
+ if (root->pi[i][k][j - 1] == '<') continue; // not post-root
+ while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
+ s = realloc(s, max += EZXML_BUFSIZE);
+ len += sprintf(s + len, "\n<?%s%s%s?>", t, *n ? " " : "", n);
+ }
+ }
+ return realloc(s, len + 1);
+}
+
+// free the memory allocated for the ezxml structure
+void ezxml_free(ezxml_t xml)
+{
+ ezxml_root_t root = (ezxml_root_t)xml;
+ int i, j;
+ char **a, *s;
+
+ if (! xml) return;
+ ezxml_free(xml->child);
+ ezxml_free(xml->ordered);
+
+ if (! xml->parent) { // free root tag allocations
+ for (i = 10; root->ent[i]; i += 2) // 0 - 9 are default entites (<>&"')
+ if ((s = root->ent[i + 1]) < root->s || s > root->e) free(s);
+ free(root->ent); // free list of general entities
+
+ for (i = 0; (a = root->attr[i]); i++) {
+ for (j = 1; a[j++]; j += 2) // free malloced attribute values
+ if (a[j] && (a[j] < root->s || a[j] > root->e)) free(a[j]);
+ free(a);
+ }
+ if (root->attr[0]) free(root->attr); // free default attribute list
+
+ for (i = 0; root->pi[i]; i++) {
+ for (j = 1; root->pi[i][j]; j++);
+ free(root->pi[i][j + 1]);
+ free(root->pi[i]);
+ }
+ if (root->pi[0]) free(root->pi); // free processing instructions
+
+ if (root->len == -1) free(root->m); // malloced xml data
+#ifndef EZXML_NOMMAP
+ else if (root->len) munmap(root->m, root->len); // mem mapped xml data
+#endif // EZXML_NOMMAP
+ if (root->u) free(root->u); // utf8 conversion
+ }
+
+ ezxml_free_attr(xml->attr); // tag attributes
+ if ((xml->flags & EZXML_TXTM)) free(xml->txt); // character content
+ if ((xml->flags & EZXML_NAMEM)) free(xml->name); // tag name
+ free(xml);
+}
+
+// return parser error message or empty string if none
+const char *ezxml_error(ezxml_t xml)
+{
+ while (xml && xml->parent) xml = xml->parent; // find root tag
+ return (xml) ? ((ezxml_root_t)xml)->err : "";
+}
+
+// returns a new empty ezxml structure with the given root tag name
+ezxml_t ezxml_new(const char *name)
+{
+ static char *ent[] = { "lt;", "&#60;", "gt;", "&#62;", "quot;", "&#34;",
+ "apos;", "&#39;", "amp;", "&#38;", NULL };
+ ezxml_root_t root = (ezxml_root_t)memset(malloc(sizeof(struct ezxml_root)),
+ '\0', sizeof(struct ezxml_root));
+ root->xml.name = (char *)name;
+ root->cur = &root->xml;
+ strcpy(root->err, root->xml.txt = "");
+ root->ent = memcpy(malloc(sizeof(ent)), ent, sizeof(ent));
+ root->attr = root->pi = (char ***)(root->xml.attr = EZXML_NIL);
+ return &root->xml;
+}
+
+// inserts an existing tag into an ezxml structure
+ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off)
+{
+ ezxml_t cur, prev, head;
+
+ xml->next = xml->sibling = xml->ordered = NULL;
+ xml->off = off;
+ xml->parent = dest;
+
+ if ((head = dest->child)) { // already have sub tags
+ if (head->off <= off) { // not first subtag
+ for (cur = head; cur->ordered && cur->ordered->off <= off;
+ cur = cur->ordered);
+ xml->ordered = cur->ordered;
+ cur->ordered = xml;
+ }
+ else { // first subtag
+ xml->ordered = head;
+ dest->child = xml;
+ }
+
+ for (cur = head, prev = NULL; cur && strcmp(cur->name, xml->name);
+ prev = cur, cur = cur->sibling); // find tag type
+ if (cur && cur->off <= off) { // not first of type
+ while (cur->next && cur->next->off <= off) cur = cur->next;
+ xml->next = cur->next;
+ cur->next = xml;
+ }
+ else { // first tag of this type
+ if (prev && cur) prev->sibling = cur->sibling; // remove old first
+ xml->next = cur; // old first tag is now next
+ for (cur = head, prev = NULL; cur && cur->off <= off;
+ prev = cur, cur = cur->sibling); // new sibling insert point
+ xml->sibling = cur;
+ if (prev) prev->sibling = xml;
+ }
+ }
+ else dest->child = xml; // only sub tag
+
+ return xml;
+}
+
+// Adds a child tag. off is the offset of the child tag relative to the start
+// of the parent tag's character content. Returns the child tag.
+ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off)
+{
+ ezxml_t child;
+
+ if (! xml) return NULL;
+ child = (ezxml_t)memset(malloc(sizeof(struct ezxml)), '\0',
+ sizeof(struct ezxml));
+ child->name = (char *)name;
+ child->attr = EZXML_NIL;
+ child->txt = "";
+
+ return ezxml_insert(child, xml, off);
+}
+
+// sets the character content for the given tag and returns the tag
+ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt)
+{
+ if (! xml) return NULL;
+ if (xml->flags & EZXML_TXTM) free(xml->txt); // existing txt was malloced
+ xml->flags &= ~EZXML_TXTM;
+ xml->txt = (char *)txt;
+ return xml;
+}
+
+// Sets the given tag attribute or adds a new attribute if not found. A value
+// of NULL will remove the specified attribute. Returns the tag given.
+ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value)
+{
+ int l = 0, c;
+
+ if (! xml) return NULL;
+ while (xml->attr[l] && strcmp(xml->attr[l], name)) l += 2;
+ if (! xml->attr[l]) { // not found, add as new attribute
+ if (! value) return xml; // nothing to do
+ if (xml->attr == EZXML_NIL) { // first attribute
+ xml->attr = malloc(4 * sizeof(char *));
+ xml->attr[1] = strdup(""); // empty list of malloced names/vals
+ }
+ else xml->attr = realloc(xml->attr, (l + 4) * sizeof(char *));
+
+ xml->attr[l] = (char *)name; // set attribute name
+ xml->attr[l + 2] = NULL; // null terminate attribute list
+ xml->attr[l + 3] = realloc(xml->attr[l + 1],
+ (c = strlen(xml->attr[l + 1])) + 2);
+ strcpy(xml->attr[l + 3] + c, " "); // set name/value as not malloced
+ if (xml->flags & EZXML_DUP) xml->attr[l + 3][c] = EZXML_NAMEM;
+ }
+ else if (xml->flags & EZXML_DUP) free((char *)name); // name was strduped
+
+ for (c = l; xml->attr[c]; c += 2); // find end of attribute list
+ if (xml->attr[c + 1][l / 2] & EZXML_TXTM) free(xml->attr[l + 1]); //old val
+ if (xml->flags & EZXML_DUP) xml->attr[c + 1][l / 2] |= EZXML_TXTM;
+ else xml->attr[c + 1][l / 2] &= ~EZXML_TXTM;
+
+ if (value) xml->attr[l + 1] = (char *)value; // set attribute value
+ else { // remove attribute
+ if (xml->attr[c + 1][l / 2] & EZXML_NAMEM) free(xml->attr[l]);
+ memmove(xml->attr + l, xml->attr + l + 2, (c - l + 2) * sizeof(char*));
+ xml->attr = realloc(xml->attr, (c + 2) * sizeof(char *));
+ memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1,
+ (c / 2) - (l / 2)); // fix list of which name/vals are malloced
+ }
+ xml->flags &= ~EZXML_DUP; // clear strdup() flag
+ return xml;
+}
+
+// sets a flag for the given tag and returns the tag
+ezxml_t ezxml_set_flag(ezxml_t xml, short flag)
+{
+ if (xml) xml->flags |= flag;
+ return xml;
+}
+
+// removes a tag along with its subtags without freeing its memory
+ezxml_t ezxml_cut(ezxml_t xml)
+{
+ ezxml_t cur;
+
+ if (! xml) return NULL; // nothing to do
+ if (xml->next) xml->next->sibling = xml->sibling; // patch sibling list
+
+ if (xml->parent) { // not root tag
+ cur = xml->parent->child; // find head of subtag list
+ if (cur == xml) xml->parent->child = xml->ordered; // first subtag
+ else { // not first subtag
+ while (cur->ordered != xml) cur = cur->ordered;
+ cur->ordered = cur->ordered->ordered; // patch ordered list
+
+ cur = xml->parent->child; // go back to head of subtag list
+ if (strcmp(cur->name, xml->name)) { // not in first sibling list
+ while (strcmp(cur->sibling->name, xml->name))
+ cur = cur->sibling;
+ if (cur->sibling == xml) { // first of a sibling list
+ cur->sibling = (xml->next) ? xml->next
+ : cur->sibling->sibling;
+ }
+ else cur = cur->sibling; // not first of a sibling list
+ }
+
+ while (cur->next && cur->next != xml) cur = cur->next;
+ if (cur->next) cur->next = cur->next->next; // patch next list
+ }
+ }
+ xml->ordered = xml->sibling = xml->next = NULL;
+ return xml;
+}
+
+#ifdef EZXML_TEST // test harness
+int main(int argc, char **argv)
+{
+ ezxml_t xml;
+ char *s;
+ int i;
+
+ if (argc != 2) return fprintf(stderr, "usage: %s xmlfile\n", argv[0]);
+
+ xml = ezxml_parse_file(argv[1]);
+ printf("%s\n", (s = ezxml_toxml(xml)));
+ free(s);
+ i = fprintf(stderr, "%s", ezxml_error(xml));
+ ezxml_free(xml);
+ return (i) ? 1 : 0;
+}
+#endif // EZXML_TEST
diff --git a/support/ezxml/ezxml.h b/support/ezxml/ezxml.h
new file mode 100644
index 00000000..3e020788
--- /dev/null
+++ b/support/ezxml/ezxml.h
@@ -0,0 +1,167 @@
+/* ezxml.h
+ *
+ * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EZXML_H
+#define _EZXML_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EZXML_BUFSIZE 1024 // size of internal memory buffers
+#define EZXML_NAMEM 0x80 // name is malloced
+#define EZXML_TXTM 0x40 // txt is malloced
+#define EZXML_DUP 0x20 // attribute name and value are strduped
+
+typedef struct ezxml *ezxml_t;
+struct ezxml {
+ char *name; // tag name
+ char **attr; // tag attributes { name, value, name, value, ... NULL }
+ char *txt; // tag character content, empty string if none
+ size_t off; // tag offset from start of parent tag character content
+ ezxml_t next; // next tag with same name in this section at this depth
+ ezxml_t sibling; // next tag with different name in same section and depth
+ ezxml_t ordered; // next tag, same section and depth, in original order
+ ezxml_t child; // head of sub tag list, NULL if none
+ ezxml_t parent; // parent tag, NULL if current tag is root tag
+ short flags; // additional information
+};
+
+// Given a string of xml data and its length, parses it and creates an ezxml
+// structure. For efficiency, modifies the data by adding null terminators
+// and decoding ampersand sequences. If you don't want this, copy the data and
+// pass in the copy. Returns NULL on failure.
+ezxml_t ezxml_parse_str(char *s, size_t len);
+
+// A wrapper for ezxml_parse_str() that accepts a file descriptor. First
+// attempts to mem map the file. Failing that, reads the file into memory.
+// Returns NULL on failure.
+ezxml_t ezxml_parse_fd(int fd);
+
+// a wrapper for ezxml_parse_fd() that accepts a file name
+ezxml_t ezxml_parse_file(const char *file);
+
+// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
+// stream into memory and then parses it. For xml files, use ezxml_parse_file()
+// or ezxml_parse_fd()
+ezxml_t ezxml_parse_fp(FILE *fp);
+
+// returns the first child tag (one level deeper) with the given name or NULL
+// if not found
+ezxml_t ezxml_child(ezxml_t xml, const char *name);
+
+// returns the next tag of the same name in the same section and depth or NULL
+// if not found
+#define ezxml_next(xml) ((xml) ? xml->next : NULL)
+
+// Returns the Nth tag with the same name in the same section at the same depth
+// or NULL if not found. An index of 0 returns the tag given.
+ezxml_t ezxml_idx(ezxml_t xml, int idx);
+
+// returns the name of the given tag
+#define ezxml_name(xml) ((xml) ? xml->name : NULL)
+
+// returns the given tag's character content or empty string if none
+#define ezxml_txt(xml) ((xml) ? xml->txt : "")
+
+// returns the value of the requested tag attribute, or NULL if not found
+const char *ezxml_attr(ezxml_t xml, const char *attr);
+
+// Traverses the ezxml sturcture to retrieve a specific subtag. Takes a
+// variable length list of tag names and indexes. The argument list must be
+// terminated by either an index of -1 or an empty string tag name. Example:
+// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
+// This retrieves the title of the 3rd book on the 1st shelf of library.
+// Returns NULL if not found.
+ezxml_t ezxml_get(ezxml_t xml, ...);
+
+// Converts an ezxml structure back to xml. Returns a string of xml data that
+// must be freed.
+char *ezxml_toxml(ezxml_t xml);
+
+// returns a NULL terminated array of processing instructions for the given
+// target
+const char **ezxml_pi(ezxml_t xml, const char *target);
+
+// frees the memory allocated for an ezxml structure
+void ezxml_free(ezxml_t xml);
+
+// returns parser error message or empty string if none
+const char *ezxml_error(ezxml_t xml);
+
+// returns a new empty ezxml structure with the given root tag name
+ezxml_t ezxml_new(const char *name);
+
+// wrapper for ezxml_new() that strdup()s name
+#define ezxml_new_d(name) ezxml_set_flag(ezxml_new(strdup(name)), EZXML_NAMEM)
+
+// Adds a child tag. off is the offset of the child tag relative to the start
+// of the parent tag's character content. Returns the child tag.
+ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off);
+
+// wrapper for ezxml_add_child() that strdup()s name
+#define ezxml_add_child_d(xml, name, off) \
+ ezxml_set_flag(ezxml_add_child(xml, strdup(name), off), EZXML_NAMEM)
+
+// sets the character content for the given tag and returns the tag
+ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt);
+
+// wrapper for ezxml_set_txt() that strdup()s txt
+#define ezxml_set_txt_d(xml, txt) \
+ ezxml_set_flag(ezxml_set_txt(xml, strdup(txt)), EZXML_TXTM)
+
+// Sets the given tag attribute or adds a new attribute if not found. A value
+// of NULL will remove the specified attribute. Returns the tag given.
+ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value);
+
+// Wrapper for ezxml_set_attr() that strdup()s name/value. Value cannot be NULL
+#define ezxml_set_attr_d(xml, name, value) \
+ ezxml_set_attr(ezxml_set_flag(xml, EZXML_DUP), strdup(name), strdup(value))
+
+// sets a flag for the given tag and returns the tag
+ezxml_t ezxml_set_flag(ezxml_t xml, short flag);
+
+// removes a tag along with its subtags without freeing its memory
+ezxml_t ezxml_cut(ezxml_t xml);
+
+// inserts an existing tag into an ezxml structure
+ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off);
+
+// Moves an existing tag to become a subtag of dest at the given offset from
+// the start of dest's character content. Returns the moved tag.
+#define ezxml_move(xml, dest, off) ezxml_insert(ezxml_cut(xml), dest, off)
+
+// removes a tag along with all its subtags
+#define ezxml_remove(xml) ezxml_free(ezxml_cut(xml))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _EZXML_H
diff --git a/support/ezxml/ezxml_init.c b/support/ezxml/ezxml_init.c
new file mode 100644
index 00000000..32be387d
--- /dev/null
+++ b/support/ezxml/ezxml_init.c
@@ -0,0 +1,6 @@
+#include "plugin.h"
+
+void
+plugin_init(void)
+{
+}
diff --git a/support/glib/Makefile.am b/support/glib/Makefile.am
new file mode 100644
index 00000000..6412cbd2
--- /dev/null
+++ b/support/glib/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -I$(top_srcdir)/navit/support -DMODULE=support_glib
+noinst_LTLIBRARIES = libsupport_glib.la
+libsupport_glib_la_SOURCES = fake.c galiasdef.c gatomic.c gerror.c \
+ ghash.c glib_init.c glist.c gmem.c gmessages.c gprimes.c gprintf.c gslice.c \
+ gstrfuncs.c gstring.c gutils.c gutf8.c \
+ fake.h galias.h gerror.h ghash.h glib.h glibconfig.h glibintl.h glist.h \
+ gmacros.h gmem.h gmessages.h gprintf.h gprintfint.h gquark.h gslice.h \
+ gstrfuncs.h gthreadprivate.h gtypes.h
diff --git a/support/glib/fake.c b/support/glib/fake.c
new file mode 100644
index 00000000..7da37182
--- /dev/null
+++ b/support/glib/fake.c
@@ -0,0 +1,5 @@
+char *
+g_convert(char *in)
+{
+ return g_strdup(in);
+}
diff --git a/support/glib/fake.h b/support/glib/fake.h
new file mode 100644
index 00000000..6fc9d55f
--- /dev/null
+++ b/support/glib/fake.h
@@ -0,0 +1,6 @@
+#define g_return_if_fail
+#define GMutex void
+#define GPrivate void
+#define g_mutex_new() NULL
+#define g_mutex_lock(x)
+#define g_mutex_unlock(x)
diff --git a/support/glib/galias.h b/support/glib/galias.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/support/glib/galias.h
diff --git a/support/glib/galiasdef.c b/support/glib/galiasdef.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/support/glib/galiasdef.c
diff --git a/support/glib/gatomic.c b/support/glib/gatomic.c
new file mode 100644
index 00000000..b75a8c5e
--- /dev/null
+++ b/support/glib/gatomic.c
@@ -0,0 +1,936 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * g_atomic_*: atomic operations.
+ * Copyright (C) 2003 Sebastian Wilhelmi
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#if defined (G_ATOMIC_ARM)
+#include <sched.h>
+#endif
+
+#include "glib.h"
+#include "gthreadprivate.h"
+#include "galias.h"
+
+#if defined (__GNUC__)
+# if defined (G_ATOMIC_I486)
+/* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h
+ */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+ gint val)
+{
+ gint result;
+
+ __asm__ __volatile__ ("lock; xaddl %0,%1"
+ : "=r" (result), "=m" (*atomic)
+ : "0" (val), "m" (*atomic));
+ return result;
+}
+
+void
+g_atomic_int_add (volatile gint *atomic,
+ gint val)
+{
+ __asm__ __volatile__ ("lock; addl %1,%0"
+ : "=m" (*atomic)
+ : "ir" (val), "m" (*atomic));
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+ gint oldval,
+ gint newval)
+{
+ gint result;
+
+ __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
+ : "=a" (result), "=m" (*atomic)
+ : "r" (newval), "m" (*atomic), "0" (oldval));
+
+ return result == oldval;
+}
+
+/* The same code as above, as on i386 gpointer is 32 bit as well.
+ * Duplicating the code here seems more natural than casting the
+ * arguments and calling the former function */
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gpointer result;
+
+ __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
+ : "=a" (result), "=m" (*atomic)
+ : "r" (newval), "m" (*atomic), "0" (oldval));
+
+ return result == oldval;
+}
+
+# elif defined (G_ATOMIC_SPARCV9)
+/* Adapted from CVS version 1.3 of glibc's sysdeps/sparc/sparc64/bits/atomic.h
+ */
+# define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \
+ ({ \
+ gint __result; \
+ __asm__ __volatile__ ("cas [%4], %2, %0" \
+ : "=r" (__result), "=m" (*(atomic)) \
+ : "r" (oldval), "m" (*(atomic)), "r" (atomic),\
+ "0" (newval)); \
+ __result == oldval; \
+ })
+
+# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gpointer result;
+ __asm__ __volatile__ ("cas [%4], %2, %0"
+ : "=r" (result), "=m" (*atomic)
+ : "r" (oldval), "m" (*atomic), "r" (atomic),
+ "0" (newval));
+ return result == oldval;
+}
+# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gpointer result;
+ gpointer *a = atomic;
+ __asm__ __volatile__ ("casx [%4], %2, %0"
+ : "=r" (result), "=m" (*a)
+ : "r" (oldval), "m" (*a), "r" (a),
+ "0" (newval));
+ return result == oldval;
+}
+# else /* What's that */
+# error "Your system has an unsupported pointer size"
+# endif /* GLIB_SIZEOF_VOID_P */
+# define G_ATOMIC_MEMORY_BARRIER \
+ __asm__ __volatile__ ("membar #LoadLoad | #LoadStore" \
+ " | #StoreLoad | #StoreStore" : : : "memory")
+
+# elif defined (G_ATOMIC_ALPHA)
+/* Adapted from CVS version 1.3 of glibc's sysdeps/alpha/bits/atomic.h
+ */
+# define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \
+ ({ \
+ gint __result; \
+ gint __prev; \
+ __asm__ __volatile__ ( \
+ " mb\n" \
+ "1: ldl_l %0,%2\n" \
+ " cmpeq %0,%3,%1\n" \
+ " beq %1,2f\n" \
+ " mov %4,%1\n" \
+ " stl_c %1,%2\n" \
+ " beq %1,1b\n" \
+ " mb\n" \
+ "2:" \
+ : "=&r" (__prev), \
+ "=&r" (__result) \
+ : "m" (*(atomic)), \
+ "Ir" (oldval), \
+ "Ir" (newval) \
+ : "memory"); \
+ __result != 0; \
+ })
+# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gint result;
+ gpointer prev;
+ __asm__ __volatile__ (
+ " mb\n"
+ "1: ldl_l %0,%2\n"
+ " cmpeq %0,%3,%1\n"
+ " beq %1,2f\n"
+ " mov %4,%1\n"
+ " stl_c %1,%2\n"
+ " beq %1,1b\n"
+ " mb\n"
+ "2:"
+ : "=&r" (prev),
+ "=&r" (result)
+ : "m" (*atomic),
+ "Ir" (oldval),
+ "Ir" (newval)
+ : "memory");
+ return result != 0;
+}
+# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gint result;
+ gpointer prev;
+ __asm__ __volatile__ (
+ " mb\n"
+ "1: ldq_l %0,%2\n"
+ " cmpeq %0,%3,%1\n"
+ " beq %1,2f\n"
+ " mov %4,%1\n"
+ " stq_c %1,%2\n"
+ " beq %1,1b\n"
+ " mb\n"
+ "2:"
+ : "=&r" (prev),
+ "=&r" (result)
+ : "m" (*atomic),
+ "Ir" (oldval),
+ "Ir" (newval)
+ : "memory");
+ return result != 0;
+}
+# else /* What's that */
+# error "Your system has an unsupported pointer size"
+# endif /* GLIB_SIZEOF_VOID_P */
+# define G_ATOMIC_MEMORY_BARRIER __asm__ ("mb" : : : "memory")
+# elif defined (G_ATOMIC_X86_64)
+/* Adapted from CVS version 1.9 of glibc's sysdeps/x86_64/bits/atomic.h
+ */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+ gint val)
+{
+ gint result;
+
+ __asm__ __volatile__ ("lock; xaddl %0,%1"
+ : "=r" (result), "=m" (*atomic)
+ : "0" (val), "m" (*atomic));
+ return result;
+}
+
+void
+g_atomic_int_add (volatile gint *atomic,
+ gint val)
+{
+ __asm__ __volatile__ ("lock; addl %1,%0"
+ : "=m" (*atomic)
+ : "ir" (val), "m" (*atomic));
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+ gint oldval,
+ gint newval)
+{
+ gint result;
+
+ __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
+ : "=a" (result), "=m" (*atomic)
+ : "r" (newval), "m" (*atomic), "0" (oldval));
+
+ return result == oldval;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gpointer result;
+
+ __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
+ : "=a" (result), "=m" (*atomic)
+ : "r" (newval), "m" (*atomic), "0" (oldval));
+
+ return result == oldval;
+}
+
+# elif defined (G_ATOMIC_POWERPC)
+/* Adapted from CVS version 1.16 of glibc's sysdeps/powerpc/bits/atomic.h
+ * and CVS version 1.4 of glibc's sysdeps/powerpc/powerpc32/bits/atomic.h
+ * and CVS version 1.7 of glibc's sysdeps/powerpc/powerpc64/bits/atomic.h
+ */
+# ifdef __OPTIMIZE__
+/* Non-optimizing compile bails on the following two asm statements
+ * for reasons unknown to the author */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+ gint val)
+{
+ gint result, temp;
+#if ASM_NUMERIC_LABELS
+ __asm__ __volatile__ ("1: lwarx %0,0,%3\n"
+ " add %1,%0,%4\n"
+ " stwcx. %1,0,%3\n"
+ " bne- 1b"
+ : "=&b" (result), "=&r" (temp), "=m" (*atomic)
+ : "b" (atomic), "r" (val), "m" (*atomic)
+ : "cr0", "memory");
+#else
+ __asm__ __volatile__ (".Lieaa%=: lwarx %0,0,%3\n"
+ " add %1,%0,%4\n"
+ " stwcx. %1,0,%3\n"
+ " bne- .Lieaa%="
+ : "=&b" (result), "=&r" (temp), "=m" (*atomic)
+ : "b" (atomic), "r" (val), "m" (*atomic)
+ : "cr0", "memory");
+#endif
+ return result;
+}
+
+/* The same as above, to save a function call repeated here */
+void
+g_atomic_int_add (volatile gint *atomic,
+ gint val)
+{
+ gint result, temp;
+#if ASM_NUMERIC_LABELS
+ __asm__ __volatile__ ("1: lwarx %0,0,%3\n"
+ " add %1,%0,%4\n"
+ " stwcx. %1,0,%3\n"
+ " bne- 1b"
+ : "=&b" (result), "=&r" (temp), "=m" (*atomic)
+ : "b" (atomic), "r" (val), "m" (*atomic)
+ : "cr0", "memory");
+#else
+ __asm__ __volatile__ (".Lia%=: lwarx %0,0,%3\n"
+ " add %1,%0,%4\n"
+ " stwcx. %1,0,%3\n"
+ " bne- .Lia%="
+ : "=&b" (result), "=&r" (temp), "=m" (*atomic)
+ : "b" (atomic), "r" (val), "m" (*atomic)
+ : "cr0", "memory");
+#endif
+}
+# else /* !__OPTIMIZE__ */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+ gint val)
+{
+ gint result;
+ do
+ result = *atomic;
+ while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
+
+ return result;
+}
+
+void
+g_atomic_int_add (volatile gint *atomic,
+ gint val)
+{
+ gint result;
+ do
+ result = *atomic;
+ while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
+}
+# endif /* !__OPTIMIZE__ */
+
+# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+ gint oldval,
+ gint newval)
+{
+ gint result;
+#if ASM_NUMERIC_LABELS
+ __asm__ __volatile__ ("sync\n"
+ "1: lwarx %0,0,%1\n"
+ " subf. %0,%2,%0\n"
+ " bne 2f\n"
+ " stwcx. %3,0,%1\n"
+ " bne- 1b\n"
+ "2: isync"
+ : "=&r" (result)
+ : "b" (atomic), "r" (oldval), "r" (newval)
+ : "cr0", "memory");
+#else
+ __asm__ __volatile__ ("sync\n"
+ ".L1icae%=: lwarx %0,0,%1\n"
+ " subf. %0,%2,%0\n"
+ " bne .L2icae%=\n"
+ " stwcx. %3,0,%1\n"
+ " bne- .L1icae%=\n"
+ ".L2icae%=: isync"
+ : "=&r" (result)
+ : "b" (atomic), "r" (oldval), "r" (newval)
+ : "cr0", "memory");
+#endif
+ return result == 0;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gpointer result;
+#if ASM_NUMERIC_LABELS
+ __asm__ __volatile__ ("sync\n"
+ "1: lwarx %0,0,%1\n"
+ " subf. %0,%2,%0\n"
+ " bne 2f\n"
+ " stwcx. %3,0,%1\n"
+ " bne- 1b\n"
+ "2: isync"
+ : "=&r" (result)
+ : "b" (atomic), "r" (oldval), "r" (newval)
+ : "cr0", "memory");
+#else
+ __asm__ __volatile__ ("sync\n"
+ ".L1pcae%=: lwarx %0,0,%1\n"
+ " subf. %0,%2,%0\n"
+ " bne .L2pcae%=\n"
+ " stwcx. %3,0,%1\n"
+ " bne- .L1pcae%=\n"
+ ".L2pcae%=: isync"
+ : "=&r" (result)
+ : "b" (atomic), "r" (oldval), "r" (newval)
+ : "cr0", "memory");
+#endif
+ return result == 0;
+}
+# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+ gint oldval,
+ gint newval)
+{
+ gpointer result;
+#if ASM_NUMERIC_LABELS
+ __asm__ __volatile__ ("sync\n"
+ "1: lwarx %0,0,%1\n"
+ " extsw %0,%0\n"
+ " subf. %0,%2,%0\n"
+ " bne 2f\n"
+ " stwcx. %3,0,%1\n"
+ " bne- 1b\n"
+ "2: isync"
+ : "=&r" (result)
+ : "b" (atomic), "r" (oldval), "r" (newval)
+ : "cr0", "memory");
+#else
+ __asm__ __volatile__ ("sync\n"
+ ".L1icae%=: lwarx %0,0,%1\n"
+ " extsw %0,%0\n"
+ " subf. %0,%2,%0\n"
+ " bne .L2icae%=\n"
+ " stwcx. %3,0,%1\n"
+ " bne- .L1icae%=\n"
+ ".L2icae%=: isync"
+ : "=&r" (result)
+ : "b" (atomic), "r" (oldval), "r" (newval)
+ : "cr0", "memory");
+#endif
+ return result == 0;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gpointer result;
+#if ASM_NUMERIC_LABELS
+ __asm__ __volatile__ ("sync\n"
+ "1: ldarx %0,0,%1\n"
+ " subf. %0,%2,%0\n"
+ " bne 2f\n"
+ " stdcx. %3,0,%1\n"
+ " bne- 1b\n"
+ "2: isync"
+ : "=&r" (result)
+ : "b" (atomic), "r" (oldval), "r" (newval)
+ : "cr0", "memory");
+#else
+ __asm__ __volatile__ ("sync\n"
+ ".L1pcae%=: ldarx %0,0,%1\n"
+ " subf. %0,%2,%0\n"
+ " bne .L2pcae%=\n"
+ " stdcx. %3,0,%1\n"
+ " bne- .L1pcae%=\n"
+ ".L2pcae%=: isync"
+ : "=&r" (result)
+ : "b" (atomic), "r" (oldval), "r" (newval)
+ : "cr0", "memory");
+#endif
+ return result == 0;
+}
+# else /* What's that */
+# error "Your system has an unsupported pointer size"
+# endif /* GLIB_SIZEOF_VOID_P */
+
+# define G_ATOMIC_MEMORY_BARRIER __asm__ ("sync" : : : "memory")
+
+# elif defined (G_ATOMIC_IA64)
+/* Adapted from CVS version 1.8 of glibc's sysdeps/ia64/bits/atomic.h
+ */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+ gint val)
+{
+ return __sync_fetch_and_add (atomic, val);
+}
+
+void
+g_atomic_int_add (volatile gint *atomic,
+ gint val)
+{
+ __sync_fetch_and_add (atomic, val);
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+ gint oldval,
+ gint newval)
+{
+ return __sync_bool_compare_and_swap (atomic, oldval, newval);
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ return __sync_bool_compare_and_swap ((long *)atomic,
+ (long)oldval, (long)newval);
+}
+
+# define G_ATOMIC_MEMORY_BARRIER __sync_synchronize ()
+# elif defined (G_ATOMIC_S390)
+/* Adapted from glibc's sysdeps/s390/bits/atomic.h
+ */
+# define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval) \
+ ({ \
+ gint __result = oldval; \
+ __asm__ __volatile__ ("cs %0, %2, %1" \
+ : "+d" (__result), "=Q" (*(atomic)) \
+ : "d" (newval), "m" (*(atomic)) : "cc" ); \
+ __result == oldval; \
+ })
+
+# if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gpointer result = oldval;
+ __asm__ __volatile__ ("cs %0, %2, %1"
+ : "+d" (result), "=Q" (*(atomic))
+ : "d" (newval), "m" (*(atomic)) : "cc" );
+ return result == oldval;
+}
+# elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gpointer result = oldval;
+ gpointer *a = atomic;
+ __asm__ __volatile__ ("csg %0, %2, %1"
+ : "+d" (result), "=Q" (*a)
+ : "d" ((long)(newval)), "m" (*a) : "cc" );
+ return result == oldval;
+}
+# else /* What's that */
+# error "Your system has an unsupported pointer size"
+# endif /* GLIB_SIZEOF_VOID_P */
+# elif defined (G_ATOMIC_ARM)
+static volatile int atomic_spin = 0;
+
+static int atomic_spin_trylock (void)
+{
+ int result;
+
+ asm volatile (
+ "swp %0, %1, [%2]\n"
+ : "=&r,&r" (result)
+ : "r,0" (1), "r,r" (&atomic_spin)
+ : "memory");
+ if (result == 0)
+ return 0;
+ else
+ return -1;
+}
+
+static void atomic_spin_lock (void)
+{
+ while (atomic_spin_trylock())
+ sched_yield();
+}
+
+static void atomic_spin_unlock (void)
+{
+ atomic_spin = 0;
+}
+
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+ gint val)
+{
+ gint result;
+
+ atomic_spin_lock();
+ result = *atomic;
+ *atomic += val;
+ atomic_spin_unlock();
+
+ return result;
+}
+
+void
+g_atomic_int_add (volatile gint *atomic,
+ gint val)
+{
+ atomic_spin_lock();
+ *atomic += val;
+ atomic_spin_unlock();
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+ gint oldval,
+ gint newval)
+{
+ gboolean result;
+
+ atomic_spin_lock();
+ if (*atomic == oldval)
+ {
+ result = TRUE;
+ *atomic = newval;
+ }
+ else
+ result = FALSE;
+ atomic_spin_unlock();
+
+ return result;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gboolean result;
+
+ atomic_spin_lock();
+ if (*atomic == oldval)
+ {
+ result = TRUE;
+ *atomic = newval;
+ }
+ else
+ result = FALSE;
+ atomic_spin_unlock();
+
+ return result;
+}
+# else /* !G_ATOMIC_ARM */
+# define DEFINE_WITH_MUTEXES
+# endif /* G_ATOMIC_IA64 */
+#else /* !__GNUC__ */
+# ifdef G_PLATFORM_WIN32
+# define DEFINE_WITH_WIN32_INTERLOCKED
+# else
+# define DEFINE_WITH_MUTEXES
+# endif
+#endif /* __GNUC__ */
+
+#ifdef DEFINE_WITH_WIN32_INTERLOCKED
+# include <windows.h>
+/* Following indicates that InterlockedCompareExchangePointer is
+ * declared in winbase.h (included by windows.h) and needs to be
+ * commented out if not true. It is defined iff WINVER > 0x0400,
+ * which is usually correct but can be wrong if WINVER is set before
+ * windows.h is included.
+ */
+# if WINVER > 0x0400
+# define HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
+# endif
+
+gint32
+g_atomic_int_exchange_and_add (volatile gint32 *atomic,
+ gint32 val)
+{
+ return InterlockedExchangeAdd (atomic, val);
+}
+
+void
+g_atomic_int_add (volatile gint32 *atomic,
+ gint32 val)
+{
+ InterlockedExchangeAdd (atomic, val);
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint32 *atomic,
+ gint32 oldval,
+ gint32 newval)
+{
+#ifndef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
+ return (guint32) InterlockedCompareExchange ((PVOID*)atomic,
+ (PVOID)newval,
+ (PVOID)oldval) == oldval;
+#else
+ return InterlockedCompareExchange (atomic,
+ newval,
+ oldval) == oldval;
+#endif
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+# ifdef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
+ return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval;
+# else
+# if GLIB_SIZEOF_VOID_P != 4 /* no 32-bit system */
+# error "InterlockedCompareExchangePointer needed"
+# else
+ return InterlockedCompareExchange (atomic, newval, oldval) == oldval;
+# endif
+# endif
+}
+#endif /* DEFINE_WITH_WIN32_INTERLOCKED */
+
+#ifdef DEFINE_WITH_MUTEXES
+/* We have to use the slow, but safe locking method */
+static GMutex *g_atomic_mutex;
+
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+ gint val)
+{
+ gint result;
+
+ g_mutex_lock (g_atomic_mutex);
+ result = *atomic;
+ *atomic += val;
+ g_mutex_unlock (g_atomic_mutex);
+
+ return result;
+}
+
+
+void
+g_atomic_int_add (volatile gint *atomic,
+ gint val)
+{
+ g_mutex_lock (g_atomic_mutex);
+ *atomic += val;
+ g_mutex_unlock (g_atomic_mutex);
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+ gint oldval,
+ gint newval)
+{
+ gboolean result;
+
+ g_mutex_lock (g_atomic_mutex);
+ if (*atomic == oldval)
+ {
+ result = TRUE;
+ *atomic = newval;
+ }
+ else
+ result = FALSE;
+ g_mutex_unlock (g_atomic_mutex);
+
+ return result;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+ gpointer oldval,
+ gpointer newval)
+{
+ gboolean result;
+
+ g_mutex_lock (g_atomic_mutex);
+ if (*atomic == oldval)
+ {
+ result = TRUE;
+ *atomic = newval;
+ }
+ else
+ result = FALSE;
+ g_mutex_unlock (g_atomic_mutex);
+
+ return result;
+}
+
+#ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
+gint
+g_atomic_int_get (volatile gint *atomic)
+{
+ gint result;
+
+ g_mutex_lock (g_atomic_mutex);
+ result = *atomic;
+ g_mutex_unlock (g_atomic_mutex);
+
+ return result;
+}
+
+void
+g_atomic_int_set (volatile gint *atomic,
+ gint newval)
+{
+ g_mutex_lock (g_atomic_mutex);
+ *atomic = newval;
+ g_mutex_unlock (g_atomic_mutex);
+}
+
+gpointer
+g_atomic_pointer_get (volatile gpointer *atomic)
+{
+ gpointer result;
+
+ g_mutex_lock (g_atomic_mutex);
+ result = *atomic;
+ g_mutex_unlock (g_atomic_mutex);
+
+ return result;
+}
+
+void
+g_atomic_pointer_set (volatile gpointer *atomic,
+ gpointer newval)
+{
+ g_mutex_lock (g_atomic_mutex);
+ *atomic = newval;
+ g_mutex_unlock (g_atomic_mutex);
+}
+#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
+#elif defined (G_ATOMIC_OP_MEMORY_BARRIER_NEEDED)
+gint
+g_atomic_int_get (volatile gint *atomic)
+{
+ G_ATOMIC_MEMORY_BARRIER;
+ return *atomic;
+}
+
+void
+g_atomic_int_set (volatile gint *atomic,
+ gint newval)
+{
+ *atomic = newval;
+ G_ATOMIC_MEMORY_BARRIER;
+}
+
+gpointer
+g_atomic_pointer_get (volatile gpointer *atomic)
+{
+ G_ATOMIC_MEMORY_BARRIER;
+ return *atomic;
+}
+
+void
+g_atomic_pointer_set (volatile gpointer *atomic,
+ gpointer newval)
+{
+ *atomic = newval;
+ G_ATOMIC_MEMORY_BARRIER;
+}
+#endif /* DEFINE_WITH_MUTEXES || G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
+
+#ifdef ATOMIC_INT_CMP_XCHG
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+ gint oldval,
+ gint newval)
+{
+ return ATOMIC_INT_CMP_XCHG (atomic, oldval, newval);
+}
+
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+ gint val)
+{
+ gint result;
+ do
+ result = *atomic;
+ while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val));
+
+ return result;
+}
+
+void
+g_atomic_int_add (volatile gint *atomic,
+ gint val)
+{
+ gint result;
+ do
+ result = *atomic;
+ while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val));
+}
+#endif /* ATOMIC_INT_CMP_XCHG */
+
+void
+_g_atomic_thread_init (void)
+{
+#ifdef DEFINE_WITH_MUTEXES
+ g_atomic_mutex = g_mutex_new ();
+#endif /* DEFINE_WITH_MUTEXES */
+}
+
+#ifndef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
+gint
+(g_atomic_int_get) (volatile gint *atomic)
+{
+ return g_atomic_int_get (atomic);
+}
+
+void
+(g_atomic_int_set) (volatile gint *atomic,
+ gint newval)
+{
+ g_atomic_int_set (atomic, newval);
+}
+
+gpointer
+(g_atomic_pointer_get) (volatile gpointer *atomic)
+{
+ return g_atomic_pointer_get (atomic);
+}
+
+void
+(g_atomic_pointer_set) (volatile gpointer *atomic,
+ gpointer newval)
+{
+ g_atomic_pointer_set (atomic, newval);
+}
+#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
+
+#define __G_ATOMIC_C__
+#include "galiasdef.c"
diff --git a/support/glib/gerror.c b/support/glib/gerror.c
new file mode 100644
index 00000000..34d8c284
--- /dev/null
+++ b/support/glib/gerror.c
@@ -0,0 +1,381 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "glib.h"
+#include "galias.h"
+
+
+static GError*
+g_error_new_valist (GQuark domain,
+ gint code,
+ const gchar *format,
+ va_list args)
+{
+ GError *error;
+
+ error = g_slice_new (GError);
+
+ error->domain = domain;
+ error->code = code;
+ error->message = g_strdup_vprintf (format, args);
+
+ return error;
+}
+
+#if NOT_NEEDED_FOR_NAVIT
+/**
+ * g_error_new:
+ * @domain: error domain
+ * @code: error code
+ * @format: printf()-style format for error message
+ * @Varargs: parameters for message format
+ *
+ * Creates a new #GError with the given @domain and @code,
+ * and a message formatted with @format.
+ *
+ * Return value: a new #GError
+ **/
+GError*
+g_error_new (GQuark domain,
+ gint code,
+ const gchar *format,
+ ...)
+{
+ GError* error;
+ va_list args;
+
+ g_return_val_if_fail (format != NULL, NULL);
+ g_return_val_if_fail (domain != 0, NULL);
+
+ va_start (args, format);
+ error = g_error_new_valist (domain, code, format, args);
+ va_end (args);
+
+ return error;
+}
+
+/**
+ * g_error_new_literal:
+ * @domain: error domain
+ * @code: error code
+ * @message: error message
+ *
+ * Creates a new #GError; unlike g_error_new(), @message is not
+ * a printf()-style format string. Use this
+ * function if @message contains text you don't have control over,
+ * that could include printf() escape sequences.
+ *
+ * Return value: a new #GError
+ **/
+GError*
+g_error_new_literal (GQuark domain,
+ gint code,
+ const gchar *message)
+{
+ GError* err;
+
+ g_return_val_if_fail (message != NULL, NULL);
+ g_return_val_if_fail (domain != 0, NULL);
+
+ err = g_slice_new (GError);
+
+ err->domain = domain;
+ err->code = code;
+ err->message = g_strdup (message);
+
+ return err;
+}
+
+/**
+ * g_error_free:
+ * @error: a #GError
+ *
+ * Frees a #GError and associated resources.
+ *
+ **/
+void
+g_error_free (GError *error)
+{
+ g_return_if_fail (error != NULL);
+
+ g_free (error->message);
+
+ g_slice_free (GError, error);
+}
+
+/**
+ * g_error_copy:
+ * @error: a #GError
+ *
+ * Makes a copy of @error.
+ *
+ * Return value: a new #GError
+ **/
+GError*
+g_error_copy (const GError *error)
+{
+ GError *copy;
+
+ g_return_val_if_fail (error != NULL, NULL);
+
+ copy = g_slice_new (GError);
+
+ *copy = *error;
+
+ copy->message = g_strdup (error->message);
+
+ return copy;
+}
+
+/**
+ * g_error_matches:
+ * @error: a #GError
+ * @domain: an error domain
+ * @code: an error code
+ *
+ * Returns %TRUE if @error matches @domain and @code, %FALSE
+ * otherwise.
+ *
+ * Return value: whether @error has @domain and @code
+ **/
+gboolean
+g_error_matches (const GError *error,
+ GQuark domain,
+ gint code)
+{
+ return error &&
+ error->domain == domain &&
+ error->code == code;
+}
+
+#define ERROR_OVERWRITTEN_WARNING "GError set over the top of a previous GError or uninitialized memory.\n" \
+ "This indicates a bug in someone's code. You must ensure an error is NULL before it's set.\n" \
+ "The overwriting error message was: %s"
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+/**
+ * g_set_error:
+ * @err: a return location for a #GError, or %NULL
+ * @domain: error domain
+ * @code: error code
+ * @format: printf()-style format
+ * @Varargs: args for @format
+ *
+ * Does nothing if @err is %NULL; if @err is non-%NULL, then *@err must
+ * be %NULL. A new #GError is created and assigned to *@err.
+ **/
+void
+g_set_error (GError **err,
+ GQuark domain,
+ gint code,
+ const gchar *format,
+ ...)
+{
+ GError *new;
+
+ va_list args;
+
+ if (err == NULL)
+ return;
+
+ va_start (args, format);
+ new = g_error_new_valist (domain, code, format, args);
+ va_end (args);
+
+ if (*err == NULL)
+ *err = new;
+#if NOT_NEEDED_FOR_NAVIT
+ else
+ g_warning (ERROR_OVERWRITTEN_WARNING, new->message);
+#endif /* NOT_NEEDED_FOR_NAVIT */
+}
+
+#if NOT_NEEDED_FOR_NAVIT
+/**
+ * g_set_error_literal:
+ * @err: a return location for a #GError, or %NULL
+ * @domain: error domain
+ * @code: error code
+ * @message: error message
+ *
+ * Does nothing if @err is %NULL; if @err is non-%NULL, then *@err must
+ * be %NULL. A new #GError is created and assigned to *@err.
+ * Unlike g_set_error(), @message is not a printf()-style format string.
+ * Use this function if @message contains text you don't have control over,
+ * that could include printf() escape sequences.
+ *
+ * Since: 2.18
+ **/
+void
+g_set_error_literal (GError **err,
+ GQuark domain,
+ gint code,
+ const gchar *message)
+{
+ GError *new;
+
+ if (err == NULL)
+ return;
+
+ new = g_error_new_literal (domain, code, message);
+ if (*err == NULL)
+ *err = new;
+ else
+ g_warning (ERROR_OVERWRITTEN_WARNING, new->message);
+}
+
+/**
+ * g_propagate_error:
+ * @dest: error return location
+ * @src: error to move into the return location
+ *
+ * If @dest is %NULL, free @src; otherwise, moves @src into *@dest.
+ * The error variable @dest points to must be %NULL.
+ **/
+void
+g_propagate_error (GError **dest,
+ GError *src)
+{
+ g_return_if_fail (src != NULL);
+
+ if (dest == NULL)
+ {
+ if (src)
+ g_error_free (src);
+ return;
+ }
+ else
+ {
+ if (*dest != NULL)
+ g_warning (ERROR_OVERWRITTEN_WARNING, src->message);
+ else
+ *dest = src;
+ }
+}
+
+/**
+ * g_clear_error:
+ * @err: a #GError return location
+ *
+ * If @err is %NULL, does nothing. If @err is non-%NULL,
+ * calls g_error_free() on *@err and sets *@err to %NULL.
+ **/
+void
+g_clear_error (GError **err)
+{
+ if (err && *err)
+ {
+ g_error_free (*err);
+ *err = NULL;
+ }
+}
+
+static void
+g_error_add_prefix (gchar **string,
+ const gchar *format,
+ va_list ap)
+{
+ gchar *oldstring;
+ gchar *prefix;
+
+ prefix = g_strdup_vprintf (format, ap);
+ oldstring = *string;
+ *string = g_strconcat (prefix, oldstring, NULL);
+ g_free (oldstring);
+ g_free (prefix);
+}
+
+/**
+ * g_prefix_error:
+ * @err: a return location for a #GError, or %NULL
+ * @format: printf()-style format string
+ * @...: arguments to @format
+ *
+ * Formats a string according to @format and
+ * prefix it to an existing error message. If
+ * @err is %NULL (ie: no error variable) then do
+ * nothing.
+ *
+ * If *@err is %NULL (ie: an error variable is
+ * present but there is no error condition) then
+ * also do nothing. Whether or not it makes
+ * sense to take advantage of this feature is up
+ * to you.
+ *
+ * Since: 2.16
+ **/
+void
+g_prefix_error (GError **err,
+ const gchar *format,
+ ...)
+{
+ if (err && *err)
+ {
+ va_list ap;
+
+ va_start (ap, format);
+ g_error_add_prefix (&(*err)->message, format, ap);
+ va_end (ap);
+ }
+}
+
+/**
+ * g_propagate_prefixed_error:
+ * @dest: error return location
+ * @src: error to move into the return location
+ * @format: printf()-style format string
+ * @...: arguments to @format
+ *
+ * If @dest is %NULL, free @src; otherwise,
+ * moves @src into *@dest. *@dest must be %NULL.
+ * After the move, add a prefix as with
+ * g_prefix_error().
+ *
+ * Since: 2.16
+ **/
+void
+g_propagate_prefixed_error (GError **dest,
+ GError *src,
+ const gchar *format,
+ ...)
+{
+ g_propagate_error (dest, src);
+
+ if (dest && *dest)
+ {
+ va_list ap;
+
+ va_start (ap, format);
+ g_error_add_prefix (&(*dest)->message, format, ap);
+ va_end (ap);
+ }
+}
+
+#endif /* NOT_NEEDED_FOR_NAVIT */
+#define __G_ERROR_C__
+#include "galiasdef.c"
diff --git a/support/glib/gerror.h b/support/glib/gerror.h
new file mode 100644
index 00000000..d3d42d59
--- /dev/null
+++ b/support/glib/gerror.h
@@ -0,0 +1,92 @@
+/* gerror.h - Error reporting system
+ *
+ * Copyright 2000 Red Hat, Inc.
+ *
+ * The Gnome Library 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.
+ *
+ * The Gnome Library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_ERROR_H__
+#define __G_ERROR_H__
+
+#include <glib/gquark.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GError GError;
+
+struct _GError
+{
+ GQuark domain;
+ gint code;
+ gchar *message;
+};
+
+GError* g_error_new (GQuark domain,
+ gint code,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (3, 4);
+
+GError* g_error_new_literal (GQuark domain,
+ gint code,
+ const gchar *message);
+
+void g_error_free (GError *error);
+GError* g_error_copy (const GError *error);
+
+gboolean g_error_matches (const GError *error,
+ GQuark domain,
+ gint code);
+
+/* if (err) *err = g_error_new(domain, code, format, ...), also has
+ * some sanity checks.
+ */
+void g_set_error (GError **err,
+ GQuark domain,
+ gint code,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (4, 5);
+
+void g_set_error_literal (GError **err,
+ GQuark domain,
+ gint code,
+ const gchar *message);
+
+/* if (dest) *dest = src; also has some sanity checks.
+ */
+void g_propagate_error (GError **dest,
+ GError *src);
+
+/* if (err && *err) { g_error_free(*err); *err = NULL; } */
+void g_clear_error (GError **err);
+
+/* if (err) prefix the formatted string to the ->message */
+void g_prefix_error (GError **err,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (2, 3);
+
+/* g_propagate_error then g_error_prefix on dest */
+void g_propagate_prefixed_error (GError **dest,
+ GError *src,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (3, 4);
+
+G_END_DECLS
+
+#endif /* __G_ERROR_H__ */
diff --git a/support/glib/ghash.c b/support/glib/ghash.c
new file mode 100644
index 00000000..e00b4c4c
--- /dev/null
+++ b/support/glib/ghash.c
@@ -0,0 +1,1202 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe
+ */
+
+#include "config.h"
+
+#include "glib.h"
+#include "galias.h"
+
+
+#define HASH_TABLE_MIN_SIZE 11
+#define HASH_TABLE_MAX_SIZE 13845163
+
+
+typedef struct _GHashNode GHashNode;
+
+struct _GHashNode
+{
+ gpointer key;
+ gpointer value;
+ GHashNode *next;
+ guint key_hash;
+};
+
+struct _GHashTable
+{
+ gint size;
+ gint nnodes;
+ GHashNode **nodes;
+ GHashFunc hash_func;
+ GEqualFunc key_equal_func;
+ volatile gint ref_count;
+#ifndef G_DISABLE_ASSERT
+ /*
+ * Tracks the structure of the hash table, not its contents: is only
+ * incremented when a node is added or removed (is not incremented
+ * when the key or data of a node is modified).
+ */
+ int version;
+#endif
+ GDestroyNotify key_destroy_func;
+ GDestroyNotify value_destroy_func;
+};
+
+typedef struct
+{
+ GHashTable *hash_table;
+ GHashNode *prev_node;
+ GHashNode *node;
+ int position;
+ gboolean pre_advanced;
+ int version;
+} RealIter;
+
+/*
+ * g_hash_table_lookup_node:
+ * @hash_table: our #GHashTable
+ * @key: the key to lookup against
+ * @hash_return: optional key hash return location
+ * Return value: a pointer to the described #GHashNode pointer
+ *
+ * Performs a lookup in the hash table. Virtually all hash operations
+ * will use this function internally.
+ *
+ * This function first computes the hash value of the key using the
+ * user's hash function.
+ *
+ * If an entry in the table matching @key is found then this function
+ * returns a pointer to the pointer to that entry in the table. In
+ * the case that the entry is at the head of a chain, this pointer
+ * will be an item in the nodes[] array. In the case that the entry
+ * is not at the head of a chain, this pointer will be the ->next
+ * pointer on the node that preceeds it.
+ *
+ * In the case that no matching entry exists in the table, a pointer
+ * to a %NULL pointer will be returned. To insert a item, this %NULL
+ * pointer should be updated to point to the new #GHashNode.
+ *
+ * If @hash_return is a pass-by-reference parameter. If it is
+ * non-%NULL then the computed hash value is returned. This is to
+ * save insertions from having to compute the hash record again for
+ * the new record.
+ */
+static inline GHashNode **
+g_hash_table_lookup_node (GHashTable *hash_table,
+ gconstpointer key,
+ guint *hash_return)
+{
+ GHashNode **node_ptr, *node;
+ guint hash_value;
+
+ hash_value = (* hash_table->hash_func) (key);
+ node_ptr = &hash_table->nodes[hash_value % hash_table->size];
+
+ if (hash_return)
+ *hash_return = hash_value;
+
+ /* Hash table lookup needs to be fast.
+ * We therefore remove the extra conditional of testing
+ * whether to call the key_equal_func or not from
+ * the inner loop.
+ *
+ * Additional optimisation: first check if our full hash
+ * values are equal so we can avoid calling the full-blown
+ * key equality function in most cases.
+ */
+ if (hash_table->key_equal_func)
+ {
+ while ((node = *node_ptr))
+ {
+ if (node->key_hash == hash_value &&
+ hash_table->key_equal_func (node->key, key))
+ break;
+
+ node_ptr = &(*node_ptr)->next;
+ }
+ }
+ else
+ {
+ while ((node = *node_ptr))
+ {
+ if (node->key == key)
+ break;
+
+ node_ptr = &(*node_ptr)->next;
+ }
+ }
+
+ return node_ptr;
+}
+
+/*
+ * g_hash_table_remove_node:
+ * @hash_table: our #GHashTable
+ * @node_ptr_ptr: a pointer to the return value from
+ * g_hash_table_lookup_node()
+ * @notify: %TRUE if the destroy notify handlers are to be called
+ *
+ * Removes a node from the hash table and updates the node count. The
+ * node is freed. No table resize is performed.
+ *
+ * If @notify is %TRUE then the destroy notify functions are called
+ * for the key and value of the hash node.
+ *
+ * @node_ptr_ptr is a pass-by-reference in/out parameter. When the
+ * function is called, it should point to the pointer to the node to
+ * remove. This level of indirection is required so that the pointer
+ * may be updated appropriately once the node has been removed.
+ *
+ * Before the function returns, the pointer at @node_ptr_ptr will be
+ * updated to point to the position in the table that contains the
+ * pointer to the "next" node in the chain. This makes this function
+ * convenient to use from functions that iterate over the entire
+ * table. If there is no further item in the chain then the
+ * #GHashNode pointer will be %NULL (ie: **node_ptr_ptr == %NULL).
+ *
+ * Since the pointer in the table to the removed node is replaced with
+ * either a pointer to the next node or a %NULL pointer as
+ * appropriate, the pointer at the end of @node_ptr_ptr will never be
+ * modified at all. Stay tuned. :)
+ */
+static void
+g_hash_table_remove_node (GHashTable *hash_table,
+ GHashNode ***node_ptr_ptr,
+ gboolean notify)
+{
+ GHashNode **node_ptr, *node;
+
+ node_ptr = *node_ptr_ptr;
+ node = *node_ptr;
+
+ *node_ptr = node->next;
+
+ if (notify && hash_table->key_destroy_func)
+ hash_table->key_destroy_func (node->key);
+
+ if (notify && hash_table->value_destroy_func)
+ hash_table->value_destroy_func (node->value);
+
+ g_slice_free (GHashNode, node);
+
+ hash_table->nnodes--;
+}
+
+/*
+ * g_hash_table_remove_all_nodes:
+ * @hash_table: our #GHashTable
+ * @notify: %TRUE if the destroy notify handlers are to be called
+ *
+ * Removes all nodes from the table. Since this may be a precursor to
+ * freeing the table entirely, no resize is performed.
+ *
+ * If @notify is %TRUE then the destroy notify functions are called
+ * for the key and value of the hash node.
+ */
+static void
+g_hash_table_remove_all_nodes (GHashTable *hash_table,
+ gboolean notify)
+{
+ GHashNode **node_ptr;
+ int i;
+
+ for (i = 0; i < hash_table->size; i++)
+ for (node_ptr = &hash_table->nodes[i]; *node_ptr != NULL;)
+ g_hash_table_remove_node (hash_table, &node_ptr, notify);
+
+ hash_table->nnodes = 0;
+}
+
+/*
+ * g_hash_table_resize:
+ * @hash_table: our #GHashTable
+ *
+ * Resizes the hash table to the optimal size based on the number of
+ * nodes currently held. If you call this function then a resize will
+ * occur, even if one does not need to occur. Use
+ * g_hash_table_maybe_resize() instead.
+ */
+static void
+g_hash_table_resize (GHashTable *hash_table)
+{
+ GHashNode **new_nodes;
+ GHashNode *node;
+ GHashNode *next;
+ guint hash_val;
+ gint new_size;
+ gint i;
+
+ new_size = g_spaced_primes_closest (hash_table->nnodes);
+ new_size = CLAMP (new_size, HASH_TABLE_MIN_SIZE, HASH_TABLE_MAX_SIZE);
+
+ new_nodes = g_new0 (GHashNode*, new_size);
+
+ for (i = 0; i < hash_table->size; i++)
+ for (node = hash_table->nodes[i]; node; node = next)
+ {
+ next = node->next;
+
+ hash_val = node->key_hash % new_size;
+
+ node->next = new_nodes[hash_val];
+ new_nodes[hash_val] = node;
+ }
+
+ g_free (hash_table->nodes);
+ hash_table->nodes = new_nodes;
+ hash_table->size = new_size;
+}
+
+/*
+ * g_hash_table_maybe_resize:
+ * @hash_table: our #GHashTable
+ *
+ * Resizes the hash table, if needed.
+ *
+ * Essentially, calls g_hash_table_resize() if the table has strayed
+ * too far from its ideal size for its number of nodes.
+ */
+static inline void
+g_hash_table_maybe_resize (GHashTable *hash_table)
+{
+ gint nnodes = hash_table->nnodes;
+ gint size = hash_table->size;
+
+ if ((size >= 3 * nnodes && size > HASH_TABLE_MIN_SIZE) ||
+ (3 * size <= nnodes && size < HASH_TABLE_MAX_SIZE))
+ g_hash_table_resize (hash_table);
+}
+
+/**
+ * g_hash_table_new:
+ * @hash_func: a function to create a hash value from a key.
+ * Hash values are used to determine where keys are stored within the
+ * #GHashTable data structure. The g_direct_hash(), g_int_hash() and
+ * g_str_hash() functions are provided for some common types of keys.
+ * If hash_func is %NULL, g_direct_hash() is used.
+ * @key_equal_func: a function to check two keys for equality. This is
+ * used when looking up keys in the #GHashTable. The g_direct_equal(),
+ * g_int_equal() and g_str_equal() functions are provided for the most
+ * common types of keys. If @key_equal_func is %NULL, keys are compared
+ * directly in a similar fashion to g_direct_equal(), but without the
+ * overhead of a function call.
+ *
+ * Creates a new #GHashTable with a reference count of 1.
+ *
+ * Return value: a new #GHashTable.
+ **/
+GHashTable*
+g_hash_table_new (GHashFunc hash_func,
+ GEqualFunc key_equal_func)
+{
+ return g_hash_table_new_full (hash_func, key_equal_func, NULL, NULL);
+}
+
+
+/**
+ * g_hash_table_new_full:
+ * @hash_func: a function to create a hash value from a key.
+ * @key_equal_func: a function to check two keys for equality.
+ * @key_destroy_func: a function to free the memory allocated for the key
+ * used when removing the entry from the #GHashTable or %NULL if you
+ * don't want to supply such a function.
+ * @value_destroy_func: a function to free the memory allocated for the
+ * value used when removing the entry from the #GHashTable or %NULL if
+ * you don't want to supply such a function.
+ *
+ * Creates a new #GHashTable like g_hash_table_new() with a reference count
+ * of 1 and allows to specify functions to free the memory allocated for the
+ * key and value that get called when removing the entry from the #GHashTable.
+ *
+ * Return value: a new #GHashTable.
+ **/
+GHashTable*
+g_hash_table_new_full (GHashFunc hash_func,
+ GEqualFunc key_equal_func,
+ GDestroyNotify key_destroy_func,
+ GDestroyNotify value_destroy_func)
+{
+ GHashTable *hash_table;
+
+ hash_table = g_slice_new (GHashTable);
+ hash_table->size = HASH_TABLE_MIN_SIZE;
+ hash_table->nnodes = 0;
+ hash_table->hash_func = hash_func ? hash_func : g_direct_hash;
+ hash_table->key_equal_func = key_equal_func;
+ hash_table->ref_count = 1;
+#ifndef G_DISABLE_ASSERT
+ hash_table->version = 0;
+#endif
+ hash_table->key_destroy_func = key_destroy_func;
+ hash_table->value_destroy_func = value_destroy_func;
+ hash_table->nodes = g_new0 (GHashNode*, hash_table->size);
+
+ return hash_table;
+}
+
+/**
+ * g_hash_table_iter_init:
+ * @iter: an uninitialized #GHashTableIter.
+ * @hash_table: a #GHashTable.
+ *
+ * Initializes a key/value pair iterator and associates it with
+ * @hash_table. Modifying the hash table after calling this function
+ * invalidates the returned iterator.
+ * |[
+ * GHashTableIter iter;
+ * gpointer key, value;
+ *
+ * g_hash_table_iter_init (&iter, hash_table);
+ * while (g_hash_table_iter_next (&iter, &key, &value))
+ * {
+ * /&ast; do something with key and value &ast;/
+ * }
+ * ]|
+ *
+ * Since: 2.16
+ **/
+void
+g_hash_table_iter_init (GHashTableIter *iter,
+ GHashTable *hash_table)
+{
+ RealIter *ri = (RealIter *) iter;
+
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (hash_table != NULL);
+
+ ri->hash_table = hash_table;
+ ri->prev_node = NULL;
+ ri->node = NULL;
+ ri->position = -1;
+ ri->pre_advanced = FALSE;
+#ifndef G_DISABLE_ASSERT
+ ri->version = hash_table->version;
+#endif
+}
+
+/**
+ * g_hash_table_iter_next:
+ * @iter: an initialized #GHashTableIter.
+ * @key: a location to store the key, or %NULL.
+ * @value: a location to store the value, or %NULL.
+ *
+ * Advances @iter and retrieves the key and/or value that are now
+ * pointed to as a result of this advancement. If %FALSE is returned,
+ * @key and @value are not set, and the iterator becomes invalid.
+ *
+ * Return value: %FALSE if the end of the #GHashTable has been reached.
+ *
+ * Since: 2.16
+ **/
+gboolean
+g_hash_table_iter_next (GHashTableIter *iter,
+ gpointer *key,
+ gpointer *value)
+{
+ RealIter *ri = (RealIter *) iter;
+
+ g_return_val_if_fail (iter != NULL, FALSE);
+#ifndef G_DISABLE_ASSERT
+ g_return_val_if_fail (ri->version == ri->hash_table->version, FALSE);
+#endif
+
+ if (ri->pre_advanced)
+ {
+ ri->pre_advanced = FALSE;
+
+ if (ri->node == NULL)
+ return FALSE;
+ }
+ else
+ {
+ if (ri->node != NULL)
+ {
+ ri->prev_node = ri->node;
+ ri->node = ri->node->next;
+ }
+
+ while (ri->node == NULL)
+ {
+ ri->position++;
+ if (ri->position >= ri->hash_table->size)
+ return FALSE;
+
+ ri->prev_node = NULL;
+ ri->node = ri->hash_table->nodes[ri->position];
+ }
+ }
+
+ if (key != NULL)
+ *key = ri->node->key;
+ if (value != NULL)
+ *value = ri->node->value;
+
+ return TRUE;
+}
+
+/**
+ * g_hash_table_iter_get_hash_table:
+ * @iter: an initialized #GHashTableIter.
+ *
+ * Returns the #GHashTable associated with @iter.
+ *
+ * Return value: the #GHashTable associated with @iter.
+ *
+ * Since: 2.16
+ **/
+GHashTable *
+g_hash_table_iter_get_hash_table (GHashTableIter *iter)
+{
+ g_return_val_if_fail (iter != NULL, NULL);
+
+ return ((RealIter *) iter)->hash_table;
+}
+
+static void
+iter_remove_or_steal (RealIter *ri, gboolean notify)
+{
+ GHashNode *prev;
+ GHashNode *node;
+ int position;
+
+ g_return_if_fail (ri != NULL);
+#ifndef G_DISABLE_ASSERT
+ g_return_if_fail (ri->version == ri->hash_table->version);
+#endif
+ g_return_if_fail (ri->node != NULL);
+
+ prev = ri->prev_node;
+ node = ri->node;
+ position = ri->position;
+
+ /* pre-advance the iterator since we will remove the node */
+
+ ri->node = ri->node->next;
+ /* ri->prev_node is still the correct previous node */
+
+ while (ri->node == NULL)
+ {
+ ri->position++;
+ if (ri->position >= ri->hash_table->size)
+ break;
+
+ ri->prev_node = NULL;
+ ri->node = ri->hash_table->nodes[ri->position];
+ }
+
+ ri->pre_advanced = TRUE;
+
+ /* remove the node */
+
+ if (prev != NULL)
+ prev->next = node->next;
+ else
+ ri->hash_table->nodes[position] = node->next;
+
+ if (notify)
+ {
+ if (ri->hash_table->key_destroy_func)
+ ri->hash_table->key_destroy_func(node->key);
+ if (ri->hash_table->value_destroy_func)
+ ri->hash_table->value_destroy_func(node->value);
+ }
+
+ g_slice_free (GHashNode, node);
+
+ ri->hash_table->nnodes--;
+
+#ifndef G_DISABLE_ASSERT
+ ri->version++;
+ ri->hash_table->version++;
+#endif
+}
+
+/**
+ * g_hash_table_iter_remove():
+ * @iter: an initialized #GHashTableIter.
+ *
+ * Removes the key/value pair currently pointed to by the iterator
+ * from its associated #GHashTable. Can only be called after
+ * g_hash_table_iter_next() returned %TRUE, and cannot be called more
+ * than once for the same key/value pair.
+ *
+ * If the #GHashTable was created using g_hash_table_new_full(), the
+ * key and value are freed using the supplied destroy functions, otherwise
+ * you have to make sure that any dynamically allocated values are freed
+ * yourself.
+ *
+ * Since: 2.16
+ **/
+void
+g_hash_table_iter_remove (GHashTableIter *iter)
+{
+ iter_remove_or_steal ((RealIter *) iter, TRUE);
+}
+
+/**
+ * g_hash_table_iter_steal():
+ * @iter: an initialized #GHashTableIter.
+ *
+ * Removes the key/value pair currently pointed to by the iterator
+ * from its associated #GHashTable, without calling the key and value
+ * destroy functions. Can only be called after
+ * g_hash_table_iter_next() returned %TRUE, and cannot be called more
+ * than once for the same key/value pair.
+ *
+ * Since: 2.16
+ **/
+void
+g_hash_table_iter_steal (GHashTableIter *iter)
+{
+ iter_remove_or_steal ((RealIter *) iter, FALSE);
+}
+
+
+/**
+ * g_hash_table_ref:
+ * @hash_table: a valid #GHashTable.
+ *
+ * Atomically increments the reference count of @hash_table by one.
+ * This function is MT-safe and may be called from any thread.
+ *
+ * Return value: the passed in #GHashTable.
+ *
+ * Since: 2.10
+ **/
+GHashTable*
+g_hash_table_ref (GHashTable *hash_table)
+{
+ g_return_val_if_fail (hash_table != NULL, NULL);
+ g_return_val_if_fail (hash_table->ref_count > 0, hash_table);
+
+ g_atomic_int_add (&hash_table->ref_count, 1);
+ return hash_table;
+}
+
+/**
+ * g_hash_table_unref:
+ * @hash_table: a valid #GHashTable.
+ *
+ * Atomically decrements the reference count of @hash_table by one.
+ * If the reference count drops to 0, all keys and values will be
+ * destroyed, and all memory allocated by the hash table is released.
+ * This function is MT-safe and may be called from any thread.
+ *
+ * Since: 2.10
+ **/
+void
+g_hash_table_unref (GHashTable *hash_table)
+{
+ g_return_if_fail (hash_table != NULL);
+ g_return_if_fail (hash_table->ref_count > 0);
+
+ if (g_atomic_int_exchange_and_add (&hash_table->ref_count, -1) - 1 == 0)
+ {
+ g_hash_table_remove_all_nodes (hash_table, TRUE);
+ g_free (hash_table->nodes);
+ g_slice_free (GHashTable, hash_table);
+ }
+}
+
+/**
+ * g_hash_table_destroy:
+ * @hash_table: a #GHashTable.
+ *
+ * Destroys all keys and values in the #GHashTable and decrements its
+ * reference count by 1. If keys and/or values are dynamically allocated,
+ * you should either free them first or create the #GHashTable with destroy
+ * notifiers using g_hash_table_new_full(). In the latter case the destroy
+ * functions you supplied will be called on all keys and values during the
+ * destruction phase.
+ **/
+void
+g_hash_table_destroy (GHashTable *hash_table)
+{
+ g_return_if_fail (hash_table != NULL);
+ g_return_if_fail (hash_table->ref_count > 0);
+
+ g_hash_table_remove_all (hash_table);
+ g_hash_table_unref (hash_table);
+}
+
+/**
+ * g_hash_table_lookup:
+ * @hash_table: a #GHashTable.
+ * @key: the key to look up.
+ *
+ * Looks up a key in a #GHashTable. Note that this function cannot
+ * distinguish between a key that is not present and one which is present
+ * and has the value %NULL. If you need this distinction, use
+ * g_hash_table_lookup_extended().
+ *
+ * Return value: the associated value, or %NULL if the key is not found.
+ **/
+gpointer
+g_hash_table_lookup (GHashTable *hash_table,
+ gconstpointer key)
+{
+ GHashNode *node;
+
+ g_return_val_if_fail (hash_table != NULL, NULL);
+
+ node = *g_hash_table_lookup_node (hash_table, key, NULL);
+
+ return node ? node->value : NULL;
+}
+
+/**
+ * g_hash_table_lookup_extended:
+ * @hash_table: a #GHashTable.
+ * @lookup_key: the key to look up.
+ * @orig_key: returns the original key.
+ * @value: returns the value associated with the key.
+ *
+ * Looks up a key in the #GHashTable, returning the original key and the
+ * associated value and a #gboolean which is %TRUE if the key was found. This
+ * is useful if you need to free the memory allocated for the original key,
+ * for example before calling g_hash_table_remove().
+ *
+ * Return value: %TRUE if the key was found in the #GHashTable.
+ **/
+gboolean
+g_hash_table_lookup_extended (GHashTable *hash_table,
+ gconstpointer lookup_key,
+ gpointer *orig_key,
+ gpointer *value)
+{
+ GHashNode *node;
+
+ g_return_val_if_fail (hash_table != NULL, FALSE);
+
+ node = *g_hash_table_lookup_node (hash_table, lookup_key, NULL);
+
+ if (node == NULL)
+ return FALSE;
+
+ if (orig_key)
+ *orig_key = node->key;
+
+ if (value)
+ *value = node->value;
+
+ return TRUE;
+}
+
+/*
+ * g_hash_table_insert_internal:
+ * @hash_table: our #GHashTable
+ * @key: the key to insert
+ * @value: the value to insert
+ * @keep_new_key: if %TRUE and this key already exists in the table
+ * then call the destroy notify function on the old key. If %FALSE
+ * then call the destroy notify function on the new key.
+ *
+ * Implements the common logic for the g_hash_table_insert() and
+ * g_hash_table_replace() functions.
+ *
+ * Do a lookup of @key. If it is found, replace it with the new
+ * @value (and perhaps the new @key). If it is not found, create a
+ * new node.
+ */
+static void
+g_hash_table_insert_internal (GHashTable *hash_table,
+ gpointer key,
+ gpointer value,
+ gboolean keep_new_key)
+{
+ GHashNode **node_ptr, *node;
+ guint key_hash;
+
+ g_return_if_fail (hash_table != NULL);
+ g_return_if_fail (hash_table->ref_count > 0);
+
+ node_ptr = g_hash_table_lookup_node (hash_table, key, &key_hash);
+
+ if ((node = *node_ptr))
+ {
+ if (keep_new_key)
+ {
+ if (hash_table->key_destroy_func)
+ hash_table->key_destroy_func (node->key);
+ node->key = key;
+ }
+ else
+ {
+ if (hash_table->key_destroy_func)
+ hash_table->key_destroy_func (key);
+ }
+
+ if (hash_table->value_destroy_func)
+ hash_table->value_destroy_func (node->value);
+
+ node->value = value;
+ }
+ else
+ {
+ node = g_slice_new (GHashNode);
+
+ node->key = key;
+ node->value = value;
+ node->key_hash = key_hash;
+ node->next = NULL;
+
+ *node_ptr = node;
+ hash_table->nnodes++;
+ g_hash_table_maybe_resize (hash_table);
+
+#ifndef G_DISABLE_ASSERT
+ hash_table->version++;
+#endif
+ }
+}
+
+/**
+ * g_hash_table_insert:
+ * @hash_table: a #GHashTable.
+ * @key: a key to insert.
+ * @value: the value to associate with the key.
+ *
+ * Inserts a new key and value into a #GHashTable.
+ *
+ * If the key already exists in the #GHashTable its current value is replaced
+ * with the new value. If you supplied a @value_destroy_func when creating the
+ * #GHashTable, the old value is freed using that function. If you supplied
+ * a @key_destroy_func when creating the #GHashTable, the passed key is freed
+ * using that function.
+ **/
+void
+g_hash_table_insert (GHashTable *hash_table,
+ gpointer key,
+ gpointer value)
+{
+ g_hash_table_insert_internal (hash_table, key, value, FALSE);
+}
+
+/**
+ * g_hash_table_replace:
+ * @hash_table: a #GHashTable.
+ * @key: a key to insert.
+ * @value: the value to associate with the key.
+ *
+ * Inserts a new key and value into a #GHashTable similar to
+ * g_hash_table_insert(). The difference is that if the key already exists
+ * in the #GHashTable, it gets replaced by the new key. If you supplied a
+ * @value_destroy_func when creating the #GHashTable, the old value is freed
+ * using that function. If you supplied a @key_destroy_func when creating the
+ * #GHashTable, the old key is freed using that function.
+ **/
+void
+g_hash_table_replace (GHashTable *hash_table,
+ gpointer key,
+ gpointer value)
+{
+ g_hash_table_insert_internal (hash_table, key, value, TRUE);
+}
+
+/*
+ * g_hash_table_remove_internal:
+ * @hash_table: our #GHashTable
+ * @key: the key to remove
+ * @notify: %TRUE if the destroy notify handlers are to be called
+ * Return value: %TRUE if a node was found and removed, else %FALSE
+ *
+ * Implements the common logic for the g_hash_table_remove() and
+ * g_hash_table_steal() functions.
+ *
+ * Do a lookup of @key and remove it if it is found, calling the
+ * destroy notify handlers only if @notify is %TRUE.
+ */
+static gboolean
+g_hash_table_remove_internal (GHashTable *hash_table,
+ gconstpointer key,
+ gboolean notify)
+{
+ GHashNode **node_ptr;
+
+ g_return_val_if_fail (hash_table != NULL, FALSE);
+
+ node_ptr = g_hash_table_lookup_node (hash_table, key, NULL);
+ if (*node_ptr == NULL)
+ return FALSE;
+
+ g_hash_table_remove_node (hash_table, &node_ptr, notify);
+ g_hash_table_maybe_resize (hash_table);
+
+#ifndef G_DISABLE_ASSERT
+ hash_table->version++;
+#endif
+
+ return TRUE;
+}
+
+/**
+ * g_hash_table_remove:
+ * @hash_table: a #GHashTable.
+ * @key: the key to remove.
+ *
+ * Removes a key and its associated value from a #GHashTable.
+ *
+ * If the #GHashTable was created using g_hash_table_new_full(), the
+ * key and value are freed using the supplied destroy functions, otherwise
+ * you have to make sure that any dynamically allocated values are freed
+ * yourself.
+ *
+ * Return value: %TRUE if the key was found and removed from the #GHashTable.
+ **/
+gboolean
+g_hash_table_remove (GHashTable *hash_table,
+ gconstpointer key)
+{
+ return g_hash_table_remove_internal (hash_table, key, TRUE);
+}
+
+/**
+ * g_hash_table_steal:
+ * @hash_table: a #GHashTable.
+ * @key: the key to remove.
+ *
+ * Removes a key and its associated value from a #GHashTable without
+ * calling the key and value destroy functions.
+ *
+ * Return value: %TRUE if the key was found and removed from the #GHashTable.
+ **/
+gboolean
+g_hash_table_steal (GHashTable *hash_table,
+ gconstpointer key)
+{
+ return g_hash_table_remove_internal (hash_table, key, FALSE);
+}
+
+/**
+ * g_hash_table_remove_all:
+ * @hash_table: a #GHashTable
+ *
+ * Removes all keys and their associated values from a #GHashTable.
+ *
+ * If the #GHashTable was created using g_hash_table_new_full(), the keys
+ * and values are freed using the supplied destroy functions, otherwise you
+ * have to make sure that any dynamically allocated values are freed
+ * yourself.
+ *
+ * Since: 2.12
+ **/
+void
+g_hash_table_remove_all (GHashTable *hash_table)
+{
+ g_return_if_fail (hash_table != NULL);
+
+#ifndef G_DISABLE_ASSERT
+ if (hash_table->nnodes != 0)
+ hash_table->version++;
+#endif
+
+ g_hash_table_remove_all_nodes (hash_table, TRUE);
+ g_hash_table_maybe_resize (hash_table);
+}
+
+/**
+ * g_hash_table_steal_all:
+ * @hash_table: a #GHashTable.
+ *
+ * Removes all keys and their associated values from a #GHashTable
+ * without calling the key and value destroy functions.
+ *
+ * Since: 2.12
+ **/
+void
+g_hash_table_steal_all (GHashTable *hash_table)
+{
+ g_return_if_fail (hash_table != NULL);
+
+#ifndef G_DISABLE_ASSERT
+ if (hash_table->nnodes != 0)
+ hash_table->version++;
+#endif
+
+ g_hash_table_remove_all_nodes (hash_table, FALSE);
+ g_hash_table_maybe_resize (hash_table);
+}
+
+/*
+ * g_hash_table_foreach_remove_or_steal:
+ * @hash_table: our #GHashTable
+ * @func: the user's callback function
+ * @user_data: data for @func
+ * @notify: %TRUE if the destroy notify handlers are to be called
+ *
+ * Implements the common logic for g_hash_table_foreach_remove() and
+ * g_hash_table_foreach_steal().
+ *
+ * Iterates over every node in the table, calling @func with the key
+ * and value of the node (and @user_data). If @func returns %TRUE the
+ * node is removed from the table.
+ *
+ * If @notify is true then the destroy notify handlers will be called
+ * for each removed node.
+ */
+static guint
+g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
+ GHRFunc func,
+ gpointer user_data,
+ gboolean notify)
+{
+ GHashNode *node, **node_ptr;
+ guint deleted = 0;
+ gint i;
+
+ for (i = 0; i < hash_table->size; i++)
+ for (node_ptr = &hash_table->nodes[i]; (node = *node_ptr) != NULL;)
+ if ((* func) (node->key, node->value, user_data))
+ {
+ g_hash_table_remove_node (hash_table, &node_ptr, notify);
+ deleted++;
+ }
+ else
+ node_ptr = &node->next;
+
+ g_hash_table_maybe_resize (hash_table);
+
+#ifndef G_DISABLE_ASSERT
+ if (deleted > 0)
+ hash_table->version++;
+#endif
+
+ return deleted;
+}
+
+/**
+ * g_hash_table_foreach_remove:
+ * @hash_table: a #GHashTable.
+ * @func: the function to call for each key/value pair.
+ * @user_data: user data to pass to the function.
+ *
+ * Calls the given function for each key/value pair in the #GHashTable.
+ * If the function returns %TRUE, then the key/value pair is removed from the
+ * #GHashTable. If you supplied key or value destroy functions when creating
+ * the #GHashTable, they are used to free the memory allocated for the removed
+ * keys and values.
+ *
+ * See #GHashTableIterator for an alternative way to loop over the
+ * key/value pairs in the hash table.
+ *
+ * Return value: the number of key/value pairs removed.
+ **/
+guint
+g_hash_table_foreach_remove (GHashTable *hash_table,
+ GHRFunc func,
+ gpointer user_data)
+{
+ g_return_val_if_fail (hash_table != NULL, 0);
+ g_return_val_if_fail (func != NULL, 0);
+
+ return g_hash_table_foreach_remove_or_steal (hash_table, func, user_data, TRUE);
+}
+
+/**
+ * g_hash_table_foreach_steal:
+ * @hash_table: a #GHashTable.
+ * @func: the function to call for each key/value pair.
+ * @user_data: user data to pass to the function.
+ *
+ * Calls the given function for each key/value pair in the #GHashTable.
+ * If the function returns %TRUE, then the key/value pair is removed from the
+ * #GHashTable, but no key or value destroy functions are called.
+ *
+ * See #GHashTableIterator for an alternative way to loop over the
+ * key/value pairs in the hash table.
+ *
+ * Return value: the number of key/value pairs removed.
+ **/
+guint
+g_hash_table_foreach_steal (GHashTable *hash_table,
+ GHRFunc func,
+ gpointer user_data)
+{
+ g_return_val_if_fail (hash_table != NULL, 0);
+ g_return_val_if_fail (func != NULL, 0);
+
+ return g_hash_table_foreach_remove_or_steal (hash_table, func, user_data, FALSE);
+}
+
+/**
+ * g_hash_table_foreach:
+ * @hash_table: a #GHashTable.
+ * @func: the function to call for each key/value pair.
+ * @user_data: user data to pass to the function.
+ *
+ * Calls the given function for each of the key/value pairs in the
+ * #GHashTable. The function is passed the key and value of each
+ * pair, and the given @user_data parameter. The hash table may not
+ * be modified while iterating over it (you can't add/remove
+ * items). To remove all items matching a predicate, use
+ * g_hash_table_foreach_remove().
+ *
+ * See g_hash_table_find() for performance caveats for linear
+ * order searches in contrast to g_hash_table_lookup().
+ **/
+void
+g_hash_table_foreach (GHashTable *hash_table,
+ GHFunc func,
+ gpointer user_data)
+{
+ GHashNode *node;
+ gint i;
+
+ g_return_if_fail (hash_table != NULL);
+ g_return_if_fail (func != NULL);
+
+ for (i = 0; i < hash_table->size; i++)
+ for (node = hash_table->nodes[i]; node; node = node->next)
+ (* func) (node->key, node->value, user_data);
+}
+
+/**
+ * g_hash_table_find:
+ * @hash_table: a #GHashTable.
+ * @predicate: function to test the key/value pairs for a certain property.
+ * @user_data: user data to pass to the function.
+ *
+ * Calls the given function for key/value pairs in the #GHashTable until
+ * @predicate returns %TRUE. The function is passed the key and value of
+ * each pair, and the given @user_data parameter. The hash table may not
+ * be modified while iterating over it (you can't add/remove items).
+ *
+ * Note, that hash tables are really only optimized for forward lookups,
+ * i.e. g_hash_table_lookup().
+ * So code that frequently issues g_hash_table_find() or
+ * g_hash_table_foreach() (e.g. in the order of once per every entry in a
+ * hash table) should probably be reworked to use additional or different
+ * data structures for reverse lookups (keep in mind that an O(n) find/foreach
+ * operation issued for all n values in a hash table ends up needing O(n*n)
+ * operations).
+ *
+ * Return value: The value of the first key/value pair is returned, for which
+ * func evaluates to %TRUE. If no pair with the requested property is found,
+ * %NULL is returned.
+ *
+ * Since: 2.4
+ **/
+gpointer
+g_hash_table_find (GHashTable *hash_table,
+ GHRFunc predicate,
+ gpointer user_data)
+{
+ GHashNode *node;
+ gint i;
+
+ g_return_val_if_fail (hash_table != NULL, NULL);
+ g_return_val_if_fail (predicate != NULL, NULL);
+
+ for (i = 0; i < hash_table->size; i++)
+ for (node = hash_table->nodes[i]; node; node = node->next)
+ if (predicate (node->key, node->value, user_data))
+ return node->value;
+ return NULL;
+}
+
+/**
+ * g_hash_table_size:
+ * @hash_table: a #GHashTable.
+ *
+ * Returns the number of elements contained in the #GHashTable.
+ *
+ * Return value: the number of key/value pairs in the #GHashTable.
+ **/
+guint
+g_hash_table_size (GHashTable *hash_table)
+{
+ g_return_val_if_fail (hash_table != NULL, 0);
+
+ return hash_table->nnodes;
+}
+
+/**
+ * g_hash_table_get_keys:
+ * @hash_table: a #GHashTable
+ *
+ * Retrieves every key inside @hash_table. The returned data is valid
+ * until @hash_table is modified.
+ *
+ * Return value: a #GList containing all the keys inside the hash
+ * table. The content of the list is owned by the hash table and
+ * should not be modified or freed. Use g_list_free() when done
+ * using the list.
+ *
+ * Since: 2.14
+ */
+GList *
+g_hash_table_get_keys (GHashTable *hash_table)
+{
+ GHashNode *node;
+ gint i;
+ GList *retval;
+
+ g_return_val_if_fail (hash_table != NULL, NULL);
+
+ retval = NULL;
+ for (i = 0; i < hash_table->size; i++)
+ for (node = hash_table->nodes[i]; node; node = node->next)
+ retval = g_list_prepend (retval, node->key);
+
+ return retval;
+}
+
+/**
+ * g_hash_table_get_values:
+ * @hash_table: a #GHashTable
+ *
+ * Retrieves every value inside @hash_table. The returned data is
+ * valid until @hash_table is modified.
+ *
+ * Return value: a #GList containing all the values inside the hash
+ * table. The content of the list is owned by the hash table and
+ * should not be modified or freed. Use g_list_free() when done
+ * using the list.
+ *
+ * Since: 2.14
+ */
+GList *
+g_hash_table_get_values (GHashTable *hash_table)
+{
+ GHashNode *node;
+ gint i;
+ GList *retval;
+
+ g_return_val_if_fail (hash_table != NULL, NULL);
+
+ retval = NULL;
+ for (i = 0; i < hash_table->size; i++)
+ for (node = hash_table->nodes[i]; node; node = node->next)
+ retval = g_list_prepend (retval, node->value);
+
+ return retval;
+}
+
+#define __G_HASH_C__
+#include "galiasdef.c"
diff --git a/support/glib/ghash.h b/support/glib/ghash.h
new file mode 100644
index 00000000..afdd0729
--- /dev/null
+++ b/support/glib/ghash.h
@@ -0,0 +1,145 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_HASH_H__
+#define __G_HASH_H__
+
+#include <glib/gtypes.h>
+#include <glib/glist.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GHashTable GHashTable;
+
+typedef gboolean (*GHRFunc) (gpointer key,
+ gpointer value,
+ gpointer user_data);
+
+typedef struct _GHashTableIter GHashTableIter;
+
+struct _GHashTableIter
+{
+ /*< private >*/
+ gpointer dummy1;
+ gpointer dummy2;
+ gpointer dummy3;
+ int dummy4;
+ gboolean dummy5;
+ gpointer dummy6;
+};
+
+/* Hash tables
+ */
+GHashTable* g_hash_table_new (GHashFunc hash_func,
+ GEqualFunc key_equal_func);
+GHashTable* g_hash_table_new_full (GHashFunc hash_func,
+ GEqualFunc key_equal_func,
+ GDestroyNotify key_destroy_func,
+ GDestroyNotify value_destroy_func);
+void g_hash_table_destroy (GHashTable *hash_table);
+void g_hash_table_insert (GHashTable *hash_table,
+ gpointer key,
+ gpointer value);
+void g_hash_table_replace (GHashTable *hash_table,
+ gpointer key,
+ gpointer value);
+gboolean g_hash_table_remove (GHashTable *hash_table,
+ gconstpointer key);
+void g_hash_table_remove_all (GHashTable *hash_table);
+gboolean g_hash_table_steal (GHashTable *hash_table,
+ gconstpointer key);
+void g_hash_table_steal_all (GHashTable *hash_table);
+gpointer g_hash_table_lookup (GHashTable *hash_table,
+ gconstpointer key);
+gboolean g_hash_table_lookup_extended (GHashTable *hash_table,
+ gconstpointer lookup_key,
+ gpointer *orig_key,
+ gpointer *value);
+void g_hash_table_foreach (GHashTable *hash_table,
+ GHFunc func,
+ gpointer user_data);
+gpointer g_hash_table_find (GHashTable *hash_table,
+ GHRFunc predicate,
+ gpointer user_data);
+guint g_hash_table_foreach_remove (GHashTable *hash_table,
+ GHRFunc func,
+ gpointer user_data);
+guint g_hash_table_foreach_steal (GHashTable *hash_table,
+ GHRFunc func,
+ gpointer user_data);
+guint g_hash_table_size (GHashTable *hash_table);
+GList * g_hash_table_get_keys (GHashTable *hash_table);
+GList * g_hash_table_get_values (GHashTable *hash_table);
+
+void g_hash_table_iter_init (GHashTableIter *iter,
+ GHashTable *hash_table);
+gboolean g_hash_table_iter_next (GHashTableIter *iter,
+ gpointer *key,
+ gpointer *value);
+GHashTable* g_hash_table_iter_get_hash_table (GHashTableIter *iter);
+void g_hash_table_iter_remove (GHashTableIter *iter);
+void g_hash_table_iter_steal (GHashTableIter *iter);
+
+/* keeping hash tables alive */
+GHashTable* g_hash_table_ref (GHashTable *hash_table);
+void g_hash_table_unref (GHashTable *hash_table);
+
+#ifndef G_DISABLE_DEPRECATED
+
+/* The following two functions are deprecated and will be removed in
+ * the next major release. They do no good. */
+#define g_hash_table_freeze(hash_table) ((void)0)
+#define g_hash_table_thaw(hash_table) ((void)0)
+
+#endif /* G_DISABLE_DEPRECATED */
+
+/* Hash Functions
+ */
+gboolean g_str_equal (gconstpointer v1,
+ gconstpointer v2);
+guint g_str_hash (gconstpointer v);
+
+gboolean g_int_equal (gconstpointer v1,
+ gconstpointer v2);
+guint g_int_hash (gconstpointer v);
+
+/* This "hash" function will just return the key's address as an
+ * unsigned integer. Useful for hashing on plain addresses or
+ * simple integer values.
+ * Passing NULL into g_hash_table_new() as GHashFunc has the
+ * same effect as passing g_direct_hash().
+ */
+guint g_direct_hash (gconstpointer v) G_GNUC_CONST;
+gboolean g_direct_equal (gconstpointer v1,
+ gconstpointer v2) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_HASH_H__ */
diff --git a/support/glib/glib.h b/support/glib/glib.h
new file mode 100644
index 00000000..34901949
--- /dev/null
+++ b/support/glib/glib.h
@@ -0,0 +1,40 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __G_LIB_H__
+#define __G_LIB_H__
+
+#define __GLIB_H_INSIDE__
+#include <glib/fake.h>
+#include <glib/ghash.h>
+#include <glib/gerror.h>
+#include <glib/gmessages.h>
+#include <glib/gstrfuncs.h>
+#include <glib/gunicode.h>
+
+#undef __GLIB_H_INSIDE__
+
+#endif /* __G_LIB_H__ */
diff --git a/support/glib/glib_init.c b/support/glib/glib_init.c
new file mode 100644
index 00000000..32be387d
--- /dev/null
+++ b/support/glib/glib_init.c
@@ -0,0 +1,6 @@
+#include "plugin.h"
+
+void
+plugin_init(void)
+{
+}
diff --git a/support/glib/glibconfig.h b/support/glib/glibconfig.h
new file mode 100644
index 00000000..ac133487
--- /dev/null
+++ b/support/glib/glibconfig.h
@@ -0,0 +1,264 @@
+/* glibconfig.h.win32.in Merged from two versions generated by configure for gcc and MSVC. */
+/* glibconfig.h
+ *
+ * This is a generated file. Please modify 'configure.in'
+ */
+
+#ifndef __G_LIBCONFIG_H__
+#define __G_LIBCONFIG_H__
+
+#include <glib/gmacros.h>
+
+#include <limits.h>
+#include <float.h>
+#include "config.h"
+
+G_BEGIN_DECLS
+
+#define G_MINFLOAT FLT_MIN
+#define G_MAXFLOAT FLT_MAX
+#define G_MINDOUBLE DBL_MIN
+#define G_MAXDOUBLE DBL_MAX
+#define G_MINSHORT SHRT_MIN
+#define G_MAXSHORT SHRT_MAX
+#define G_MAXUSHORT USHRT_MAX
+#define G_MININT INT_MIN
+#define G_MAXINT INT_MAX
+#define G_MAXUINT UINT_MAX
+#define G_MINLONG LONG_MIN
+#define G_MAXLONG LONG_MAX
+#define G_MAXULONG ULONG_MAX
+
+typedef signed char gint8;
+typedef unsigned char guint8;
+typedef signed short gint16;
+typedef unsigned short guint16;
+#define G_GINT16_MODIFIER "h"
+#define G_GINT16_FORMAT "hi"
+#define G_GUINT16_FORMAT "hu"
+typedef signed int gint32;
+typedef unsigned int guint32;
+#define G_GINT32_MODIFIER ""
+#define G_GINT32_FORMAT "i"
+#define G_GUINT32_FORMAT "u"
+#define G_HAVE_GINT64 1 /* deprecated, always true */
+
+#ifndef _MSC_VER
+G_GNUC_EXTENSION typedef signed long long gint64;
+G_GNUC_EXTENSION typedef unsigned long long guint64;
+#else /* _MSC_VER */
+typedef signed __int64 gint64;
+typedef unsigned __int64 guint64;
+#endif /* _MSC_VER */
+
+#ifndef _MSC_VER
+#define G_GINT64_CONSTANT(val) (G_GNUC_EXTENSION (val##LL))
+#else /* _MSC_VER */
+#define G_GINT64_CONSTANT(val) (val##i64)
+#endif /* _MSC_VER */
+#ifndef _MSC_VER
+#define G_GUINT64_CONSTANT(val) (G_GNUC_EXTENSION (val##ULL))
+#else /* _MSC_VER */
+#define G_GUINT64_CONSTANT(val) (val##Ui64)
+#endif /* _MSC_VER */
+#define G_GINT64_MODIFIER "I64"
+#define G_GINT64_FORMAT "I64i"
+#define G_GUINT64_FORMAT "I64u"
+
+#if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
+
+#define GLIB_SIZEOF_VOID_P 8
+#define GLIB_SIZEOF_LONG 4
+#define GLIB_SIZEOF_SIZE_T 8
+
+typedef signed long long gssize;
+typedef unsigned long long gsize;
+#define G_GSIZE_MODIFIER "I64"
+#define G_GSSIZE_FORMAT "I64d"
+#define G_GSIZE_FORMAT "I64u"
+
+#define G_MAXSIZE G_MAXUINT64
+#define G_MINSSIZE G_MININT64
+#define G_MAXSSIZE G_MAXINT64
+
+#else
+
+#define GLIB_SIZEOF_VOID_P 4
+#define GLIB_SIZEOF_LONG 4
+#define GLIB_SIZEOF_SIZE_T 4
+
+typedef signed int gssize;
+typedef unsigned int gsize;
+#define G_GSIZE_MODIFIER ""
+#define G_GSSIZE_FORMAT "i"
+#define G_GSIZE_FORMAT "u"
+
+#define G_MAXSIZE G_MAXUINT
+#define G_MINSSIZE G_MININT
+#define G_MAXSSIZE G_MAXINT
+
+#endif
+
+typedef gint64 goffset;
+#define G_MINOFFSET G_MININT64
+#define G_MAXOFFSET G_MAXINT64
+
+#ifndef _WIN64
+
+#define GPOINTER_TO_INT(p) ((gint) (p))
+#define GPOINTER_TO_UINT(p) ((guint) (p))
+
+#define GINT_TO_POINTER(i) ((gpointer) (i))
+#define GUINT_TO_POINTER(u) ((gpointer) (u))
+
+typedef signed int gintptr;
+typedef unsigned int guintptr;
+
+#else
+
+#define GPOINTER_TO_INT(p) ((gint) (gint64) (p))
+#define GPOINTER_TO_UINT(p) ((guint) (guint64) (p))
+
+#define GINT_TO_POINTER(i) ((gpointer) (gint64) (i))
+#define GUINT_TO_POINTER(u) ((gpointer) (guint64) (u))
+
+#ifndef _MSC_VER
+typedef signed long long gintptr;
+typedef unsigned long long guintptr;
+#else
+typedef signed __int64 gintptr;
+typedef unsigned __int64 guintptr;
+#endif
+
+#endif
+
+#ifdef NeXT /* @#%@! NeXTStep */
+# define g_ATEXIT(proc) (!atexit (proc))
+#else
+# define g_ATEXIT(proc) (atexit (proc))
+#endif
+
+#define g_memmove(dest,src,len) G_STMT_START { memmove ((dest), (src), (len)); } G_STMT_END
+
+#define GLIB_MAJOR_VERSION 2
+#define GLIB_MINOR_VERSION 18
+#define GLIB_MICRO_VERSION 1
+
+#ifdef HAVE_API_WIN32_BASE
+#define G_OS_WIN32
+#define G_PLATFORM_WIN32
+#endif
+
+
+#ifndef _MSC_VER
+#define G_VA_COPY va_copy
+#endif /* not _MSC_VER */
+
+#ifdef __cplusplus
+#define G_HAVE_INLINE 1
+#else /* !__cplusplus */
+#ifndef _MSC_VER
+#define G_HAVE_INLINE 1
+#endif /* _MSC_VER */
+#define G_HAVE___INLINE 1
+#if !defined(_MSC_VER) && !defined(__DMC__)
+#define G_HAVE___INLINE__ 1
+#endif /* !_MSC_VER and !__DMC__ */
+#endif /* !__cplusplus */
+
+#define G_CAN_INLINE 1
+
+#ifndef _MSC_VER
+#define G_HAVE_ISO_VARARGS 1
+
+/* gcc-2.95.x supports both gnu style and ISO varargs, but if -ansi
+ * is passed ISO vararg support is turned off, and there is no work
+ * around to turn it on, so we unconditionally turn it off.
+ */
+#if __GNUC__ == 2 && __GNUC_MINOR__ == 95
+# undef G_HAVE_ISO_VARARGS
+#endif
+
+#define G_HAVE_GNUC_VARARGS 1
+#else /* _MSC_VER */
+/* varargs macros available since msvc8 (vs2005) */
+# if _MSC_VER >= 1400
+# define G_HAVE_ISO_VARARGS 1
+# endif
+#endif /* not _MSC_VER */
+#define G_HAVE_GROWING_STACK 0
+
+#define G_GNUC_INTERNAL
+
+#if NOT_NEEDED_FOR_NAVIT
+#define G_THREADS_ENABLED
+#define G_THREADS_IMPL_WIN32
+#endif /* NOT_NEEDED_FOR_NAVIT */
+typedef struct _GMutex* GStaticMutex;
+#define G_STATIC_MUTEX_INIT NULL
+#define g_static_mutex_get_mutex(mutex) \
+ (g_static_mutex_get_mutex_impl_shortcut (mutex))
+/* This represents a system thread as used by the implementation. An
+ * alien implementaion, as loaded by g_thread_init can only count on
+ * "sizeof (gpointer)" bytes to store their info. We however need more
+ * for some of our native implementations. */
+typedef union _GSystemThread GSystemThread;
+union _GSystemThread
+{
+#ifndef _WIN64
+ char data[4];
+#else
+ char data[8];
+#endif
+ double dummy_double;
+ void *dummy_pointer;
+ long dummy_long;
+};
+
+#define GINT16_TO_LE(val) ((gint16) (val))
+#define GUINT16_TO_LE(val) ((guint16) (val))
+#define GINT16_TO_BE(val) ((gint16) GUINT16_SWAP_LE_BE (val))
+#define GUINT16_TO_BE(val) (GUINT16_SWAP_LE_BE (val))
+#define GINT32_TO_LE(val) ((gint32) (val))
+#define GUINT32_TO_LE(val) ((guint32) (val))
+#define GINT32_TO_BE(val) ((gint32) GUINT32_SWAP_LE_BE (val))
+#define GUINT32_TO_BE(val) (GUINT32_SWAP_LE_BE (val))
+#define GINT64_TO_LE(val) ((gint64) (val))
+#define GUINT64_TO_LE(val) ((guint64) (val))
+#define GINT64_TO_BE(val) ((gint64) GUINT64_SWAP_LE_BE (val))
+#define GUINT64_TO_BE(val) (GUINT64_SWAP_LE_BE (val))
+#define GLONG_TO_LE(val) ((glong) GINT32_TO_LE (val))
+#define GULONG_TO_LE(val) ((gulong) GUINT32_TO_LE (val))
+#define GLONG_TO_BE(val) ((glong) GINT32_TO_BE (val))
+#define GULONG_TO_BE(val) ((gulong) GUINT32_TO_BE (val))
+#define GINT_TO_LE(val) ((gint) GINT32_TO_LE (val))
+#define GUINT_TO_LE(val) ((guint) GUINT32_TO_LE (val))
+#define GINT_TO_BE(val) ((gint) GINT32_TO_BE (val))
+#define GUINT_TO_BE(val) ((guint) GUINT32_TO_BE (val))
+#define G_BYTE_ORDER G_LITTLE_ENDIAN
+
+#define GLIB_SYSDEF_POLLIN =1
+#define GLIB_SYSDEF_POLLOUT =4
+#define GLIB_SYSDEF_POLLPRI =2
+#define GLIB_SYSDEF_POLLHUP =16
+#define GLIB_SYSDEF_POLLERR =8
+#define GLIB_SYSDEF_POLLNVAL =32
+
+#define G_MODULE_SUFFIX "dll"
+
+#define HAVE_GOOD_PRINTF
+#define NO_SYS_SIGLIST_DECL
+#define GLIB_STATIC_COMPILATION
+#define G_DISABLE_CHECKS
+/* A GPid is an abstraction for a process "handle". It is *not* an
+ * abstraction for a process identifier in general. GPid is used in
+ * GLib only for descendant processes spawned with the g_spawn*
+ * functions. On POSIX there is no "process handle" concept as such,
+ * but on Windows a GPid is a handle to a process, a kind of pointer,
+ * not a process identifier.
+ */
+typedef void * GPid;
+
+G_END_DECLS
+
+#endif /* GLIBCONFIG_H */
diff --git a/support/glib/glibintl.h b/support/glib/glibintl.h
new file mode 100644
index 00000000..7899488a
--- /dev/null
+++ b/support/glib/glibintl.h
@@ -0,0 +1,39 @@
+#ifndef __GLIBINTL_H__
+#define __GLIBINTL_H__
+
+#if NOT_NEEDED_FOR_NAVIT
+#ifndef SIZEOF_CHAR
+#error "config.h must be included prior to glibintl.h"
+#endif
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+G_CONST_RETURN gchar *glib_gettext (const gchar *str);
+
+#ifdef ENABLE_NLS
+
+#include <libintl.h>
+#define _(String) glib_gettext(String)
+/* Split out this in the code, but keep it in the same domain for now */
+#define P_(String) glib_gettext(String)
+
+#ifdef gettext_noop
+#define N_(String) gettext_noop(String)
+#else
+#define N_(String) (String)
+#endif
+#else /* NLS is disabled */
+#define _(String) (String)
+#define N_(String) (String)
+#define P_(String) (String)
+#define textdomain(String) (String)
+#define gettext(String) (String)
+#define dgettext(Domain,String) (String)
+#define dcgettext(Domain,String,Type) (String)
+#define dngettext(Domain,String1,String2,N) ((N) == 1 ? (String1) : (String2))
+#define bindtextdomain(Domain,Directory) (Domain)
+#endif
+
+/* not really I18N-related, but also a string marker macro */
+#define I_(string) g_intern_static_string (string)
+
+#endif /* __GLIBINTL_H__ */
diff --git a/support/glib/glist.c b/support/glib/glist.c
new file mode 100644
index 00000000..b607abd6
--- /dev/null
+++ b/support/glib/glist.c
@@ -0,0 +1,999 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe
+ */
+
+#include "config.h"
+
+#include "glib.h"
+#include "galias.h"
+
+
+void g_list_push_allocator (gpointer dummy) { /* present for binary compat only */ }
+void g_list_pop_allocator (void) { /* present for binary compat only */ }
+
+#define _g_list_alloc() g_slice_new (GList)
+#define _g_list_alloc0() g_slice_new0 (GList)
+#define _g_list_free1(list) g_slice_free (GList, list)
+
+GList*
+g_list_alloc (void)
+{
+ return _g_list_alloc0 ();
+}
+
+/**
+ * g_list_free:
+ * @list: a #GList
+ *
+ * Frees all of the memory used by a #GList.
+ * The freed elements are returned to the slice allocator.
+ *
+ * <note><para>
+ * If list elements contain dynamically-allocated memory,
+ * they should be freed first.
+ * </para></note>
+ */
+void
+g_list_free (GList *list)
+{
+ g_slice_free_chain (GList, list, next);
+}
+
+/**
+ * g_list_free_1:
+ * @list: a #GList element
+ *
+ * Frees one #GList element.
+ * It is usually used after g_list_remove_link().
+ */
+void
+g_list_free_1 (GList *list)
+{
+ _g_list_free1 (list);
+}
+
+/**
+ * g_list_append:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ *
+ * Adds a new element on to the end of the list.
+ *
+ * <note><para>
+ * The return value is the new start of the list, which
+ * may have changed, so make sure you store the new value.
+ * </para></note>
+ *
+ * <note><para>
+ * Note that g_list_append() has to traverse the entire list
+ * to find the end, which is inefficient when adding multiple
+ * elements. A common idiom to avoid the inefficiency is to prepend
+ * the elements and reverse the list when all elements have been added.
+ * </para></note>
+ *
+ * |[
+ * /&ast; Notice that these are initialized to the empty list. &ast;/
+ * GList *list = NULL, *number_list = NULL;
+ *
+ * /&ast; This is a list of strings. &ast;/
+ * list = g_list_append (list, "first");
+ * list = g_list_append (list, "second");
+ *
+ * /&ast; This is a list of integers. &ast;/
+ * number_list = g_list_append (number_list, GINT_TO_POINTER (27));
+ * number_list = g_list_append (number_list, GINT_TO_POINTER (14));
+ * ]|
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_append (GList *list,
+ gpointer data)
+{
+ GList *new_list;
+ GList *last;
+
+ new_list = _g_list_alloc ();
+ new_list->data = data;
+ new_list->next = NULL;
+
+ if (list)
+ {
+ last = g_list_last (list);
+ /* g_assert (last != NULL); */
+ last->next = new_list;
+ new_list->prev = last;
+
+ return list;
+ }
+ else
+ {
+ new_list->prev = NULL;
+ return new_list;
+ }
+}
+
+/**
+ * g_list_prepend:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ *
+ * Adds a new element on to the start of the list.
+ *
+ * <note><para>
+ * The return value is the new start of the list, which
+ * may have changed, so make sure you store the new value.
+ * </para></note>
+ *
+ * |[
+ * /&ast; Notice that it is initialized to the empty list. &ast;/
+ * GList *list = NULL;
+ * list = g_list_prepend (list, "last");
+ * list = g_list_prepend (list, "first");
+ * ]|
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_prepend (GList *list,
+ gpointer data)
+{
+ GList *new_list;
+
+ new_list = _g_list_alloc ();
+ new_list->data = data;
+ new_list->next = list;
+
+ if (list)
+ {
+ new_list->prev = list->prev;
+ if (list->prev)
+ list->prev->next = new_list;
+ list->prev = new_list;
+ }
+ else
+ new_list->prev = NULL;
+
+ return new_list;
+}
+
+/**
+ * g_list_insert:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ * @position: the position to insert the element. If this is
+ * negative, or is larger than the number of elements in the
+ * list, the new element is added on to the end of the list.
+ *
+ * Inserts a new element into the list at the given position.
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_insert (GList *list,
+ gpointer data,
+ gint position)
+{
+ GList *new_list;
+ GList *tmp_list;
+
+ if (position < 0)
+ return g_list_append (list, data);
+ else if (position == 0)
+ return g_list_prepend (list, data);
+
+ tmp_list = g_list_nth (list, position);
+ if (!tmp_list)
+ return g_list_append (list, data);
+
+ new_list = _g_list_alloc ();
+ new_list->data = data;
+ new_list->prev = tmp_list->prev;
+ if (tmp_list->prev)
+ tmp_list->prev->next = new_list;
+ new_list->next = tmp_list;
+ tmp_list->prev = new_list;
+
+ if (tmp_list == list)
+ return new_list;
+ else
+ return list;
+}
+
+/**
+ * g_list_insert_before:
+ * @list: a pointer to a #GList
+ * @sibling: the list element before which the new element
+ * is inserted or %NULL to insert at the end of the list
+ * @data: the data for the new element
+ *
+ * Inserts a new element into the list before the given position.
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_insert_before (GList *list,
+ GList *sibling,
+ gpointer data)
+{
+ if (!list)
+ {
+ list = g_list_alloc ();
+ list->data = data;
+ g_return_val_if_fail (sibling == NULL, list);
+ return list;
+ }
+ else if (sibling)
+ {
+ GList *node;
+
+ node = _g_list_alloc ();
+ node->data = data;
+ node->prev = sibling->prev;
+ node->next = sibling;
+ sibling->prev = node;
+ if (node->prev)
+ {
+ node->prev->next = node;
+ return list;
+ }
+ else
+ {
+ g_return_val_if_fail (sibling == list, node);
+ return node;
+ }
+ }
+ else
+ {
+ GList *last;
+
+ last = list;
+ while (last->next)
+ last = last->next;
+
+ last->next = _g_list_alloc ();
+ last->next->data = data;
+ last->next->prev = last;
+ last->next->next = NULL;
+
+ return list;
+ }
+}
+
+/**
+ * g_list_concat:
+ * @list1: a #GList
+ * @list2: the #GList to add to the end of the first #GList
+ *
+ * Adds the second #GList onto the end of the first #GList.
+ * Note that the elements of the second #GList are not copied.
+ * They are used directly.
+ *
+ * Returns: the start of the new #GList
+ */
+GList *
+g_list_concat (GList *list1, GList *list2)
+{
+ GList *tmp_list;
+
+ if (list2)
+ {
+ tmp_list = g_list_last (list1);
+ if (tmp_list)
+ tmp_list->next = list2;
+ else
+ list1 = list2;
+ list2->prev = tmp_list;
+ }
+
+ return list1;
+}
+
+/**
+ * g_list_remove:
+ * @list: a #GList
+ * @data: the data of the element to remove
+ *
+ * Removes an element from a #GList.
+ * If two elements contain the same data, only the first is removed.
+ * If none of the elements contain the data, the #GList is unchanged.
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_remove (GList *list,
+ gconstpointer data)
+{
+ GList *tmp;
+
+ tmp = list;
+ while (tmp)
+ {
+ if (tmp->data != data)
+ tmp = tmp->next;
+ else
+ {
+ if (tmp->prev)
+ tmp->prev->next = tmp->next;
+ if (tmp->next)
+ tmp->next->prev = tmp->prev;
+
+ if (list == tmp)
+ list = list->next;
+
+ _g_list_free1 (tmp);
+
+ break;
+ }
+ }
+ return list;
+}
+
+/**
+ * g_list_remove_all:
+ * @list: a #GList
+ * @data: data to remove
+ *
+ * Removes all list nodes with data equal to @data.
+ * Returns the new head of the list. Contrast with
+ * g_list_remove() which removes only the first node
+ * matching the given data.
+ *
+ * Returns: new head of @list
+ */
+GList*
+g_list_remove_all (GList *list,
+ gconstpointer data)
+{
+ GList *tmp = list;
+
+ while (tmp)
+ {
+ if (tmp->data != data)
+ tmp = tmp->next;
+ else
+ {
+ GList *next = tmp->next;
+
+ if (tmp->prev)
+ tmp->prev->next = next;
+ else
+ list = next;
+ if (next)
+ next->prev = tmp->prev;
+
+ _g_list_free1 (tmp);
+ tmp = next;
+ }
+ }
+ return list;
+}
+
+static inline GList*
+_g_list_remove_link (GList *list,
+ GList *link)
+{
+ if (link)
+ {
+ if (link->prev)
+ link->prev->next = link->next;
+ if (link->next)
+ link->next->prev = link->prev;
+
+ if (link == list)
+ list = list->next;
+
+ link->next = NULL;
+ link->prev = NULL;
+ }
+
+ return list;
+}
+
+/**
+ * g_list_remove_link:
+ * @list: a #GList
+ * @llink: an element in the #GList
+ *
+ * Removes an element from a #GList, without freeing the element.
+ * The removed element's prev and next links are set to %NULL, so
+ * that it becomes a self-contained list with one element.
+ *
+ * Returns: the new start of the #GList, without the element
+ */
+GList*
+g_list_remove_link (GList *list,
+ GList *llink)
+{
+ return _g_list_remove_link (list, llink);
+}
+
+/**
+ * g_list_delete_link:
+ * @list: a #GList
+ * @link_: node to delete from @list
+ *
+ * Removes the node link_ from the list and frees it.
+ * Compare this to g_list_remove_link() which removes the node
+ * without freeing it.
+ *
+ * Returns: the new head of @list
+ */
+GList*
+g_list_delete_link (GList *list,
+ GList *link_)
+{
+ list = _g_list_remove_link (list, link_);
+ _g_list_free1 (link_);
+
+ return list;
+}
+
+/**
+ * g_list_copy:
+ * @list: a #GList
+ *
+ * Copies a #GList.
+ *
+ * <note><para>
+ * Note that this is a "shallow" copy. If the list elements
+ * consist of pointers to data, the pointers are copied but
+ * the actual data is not.
+ * </para></note>
+ *
+ * Returns: a copy of @list
+ */
+GList*
+g_list_copy (GList *list)
+{
+ GList *new_list = NULL;
+
+ if (list)
+ {
+ GList *last;
+
+ new_list = _g_list_alloc ();
+ new_list->data = list->data;
+ new_list->prev = NULL;
+ last = new_list;
+ list = list->next;
+ while (list)
+ {
+ last->next = _g_list_alloc ();
+ last->next->prev = last;
+ last = last->next;
+ last->data = list->data;
+ list = list->next;
+ }
+ last->next = NULL;
+ }
+
+ return new_list;
+}
+
+/**
+ * g_list_reverse:
+ * @list: a #GList
+ *
+ * Reverses a #GList.
+ * It simply switches the next and prev pointers of each element.
+ *
+ * Returns: the start of the reversed #GList
+ */
+GList*
+g_list_reverse (GList *list)
+{
+ GList *last;
+
+ last = NULL;
+ while (list)
+ {
+ last = list;
+ list = last->next;
+ last->next = last->prev;
+ last->prev = list;
+ }
+
+ return last;
+}
+
+/**
+ * g_list_nth:
+ * @list: a #GList
+ * @n: the position of the element, counting from 0
+ *
+ * Gets the element at the given position in a #GList.
+ *
+ * Returns: the element, or %NULL if the position is off
+ * the end of the #GList
+ */
+GList*
+g_list_nth (GList *list,
+ guint n)
+{
+ while ((n-- > 0) && list)
+ list = list->next;
+
+ return list;
+}
+
+/**
+ * g_list_nth_prev:
+ * @list: a #GList
+ * @n: the position of the element, counting from 0
+ *
+ * Gets the element @n places before @list.
+ *
+ * Returns: the element, or %NULL if the position is
+ * off the end of the #GList
+ */
+GList*
+g_list_nth_prev (GList *list,
+ guint n)
+{
+ while ((n-- > 0) && list)
+ list = list->prev;
+
+ return list;
+}
+
+/**
+ * g_list_nth_data:
+ * @list: a #GList
+ * @n: the position of the element
+ *
+ * Gets the data of the element at the given position.
+ *
+ * Returns: the element's data, or %NULL if the position
+ * is off the end of the #GList
+ */
+gpointer
+g_list_nth_data (GList *list,
+ guint n)
+{
+ while ((n-- > 0) && list)
+ list = list->next;
+
+ return list ? list->data : NULL;
+}
+
+/**
+ * g_list_find:
+ * @list: a #GList
+ * @data: the element data to find
+ *
+ * Finds the element in a #GList which
+ * contains the given data.
+ *
+ * Returns: the found #GList element,
+ * or %NULL if it is not found
+ */
+GList*
+g_list_find (GList *list,
+ gconstpointer data)
+{
+ while (list)
+ {
+ if (list->data == data)
+ break;
+ list = list->next;
+ }
+
+ return list;
+}
+
+/**
+ * g_list_find_custom:
+ * @list: a #GList
+ * @data: user data passed to the function
+ * @func: the function to call for each element.
+ * It should return 0 when the desired element is found
+ *
+ * Finds an element in a #GList, using a supplied function to
+ * find the desired element. It iterates over the list, calling
+ * the given function which should return 0 when the desired
+ * element is found. The function takes two #gconstpointer arguments,
+ * the #GList element's data as the first argument and the
+ * given user data.
+ *
+ * Returns: the found #GList element, or %NULL if it is not found
+ */
+GList*
+g_list_find_custom (GList *list,
+ gconstpointer data,
+ GCompareFunc func)
+{
+ g_return_val_if_fail (func != NULL, list);
+
+ while (list)
+ {
+ if (! func (list->data, data))
+ return list;
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * g_list_position:
+ * @list: a #GList
+ * @llink: an element in the #GList
+ *
+ * Gets the position of the given element
+ * in the #GList (starting from 0).
+ *
+ * Returns: the position of the element in the #GList,
+ * or -1 if the element is not found
+ */
+gint
+g_list_position (GList *list,
+ GList *llink)
+{
+ gint i;
+
+ i = 0;
+ while (list)
+ {
+ if (list == llink)
+ return i;
+ i++;
+ list = list->next;
+ }
+
+ return -1;
+}
+
+/**
+ * g_list_index:
+ * @list: a #GList
+ * @data: the data to find
+ *
+ * Gets the position of the element containing
+ * the given data (starting from 0).
+ *
+ * Returns: the index of the element containing the data,
+ * or -1 if the data is not found
+ */
+gint
+g_list_index (GList *list,
+ gconstpointer data)
+{
+ gint i;
+
+ i = 0;
+ while (list)
+ {
+ if (list->data == data)
+ return i;
+ i++;
+ list = list->next;
+ }
+
+ return -1;
+}
+
+/**
+ * g_list_last:
+ * @list: a #GList
+ *
+ * Gets the last element in a #GList.
+ *
+ * Returns: the last element in the #GList,
+ * or %NULL if the #GList has no elements
+ */
+GList*
+g_list_last (GList *list)
+{
+ if (list)
+ {
+ while (list->next)
+ list = list->next;
+ }
+
+ return list;
+}
+
+/**
+ * g_list_first:
+ * @list: a #GList
+ *
+ * Gets the first element in a #GList.
+ *
+ * Returns: the first element in the #GList,
+ * or %NULL if the #GList has no elements
+ */
+GList*
+g_list_first (GList *list)
+{
+ if (list)
+ {
+ while (list->prev)
+ list = list->prev;
+ }
+
+ return list;
+}
+
+/**
+ * g_list_length:
+ * @list: a #GList
+ *
+ * Gets the number of elements in a #GList.
+ *
+ * <note><para>
+ * This function iterates over the whole list to
+ * count its elements.
+ * </para></note>
+ *
+ * Returns: the number of elements in the #GList
+ */
+guint
+g_list_length (GList *list)
+{
+ guint length;
+
+ length = 0;
+ while (list)
+ {
+ length++;
+ list = list->next;
+ }
+
+ return length;
+}
+
+/**
+ * g_list_foreach:
+ * @list: a #GList
+ * @func: the function to call with each element's data
+ * @user_data: user data to pass to the function
+ *
+ * Calls a function for each element of a #GList.
+ */
+void
+g_list_foreach (GList *list,
+ GFunc func,
+ gpointer user_data)
+{
+ while (list)
+ {
+ GList *next = list->next;
+ (*func) (list->data, user_data);
+ list = next;
+ }
+}
+
+static GList*
+g_list_insert_sorted_real (GList *list,
+ gpointer data,
+ GFunc func,
+ gpointer user_data)
+{
+ GList *tmp_list = list;
+ GList *new_list;
+ gint cmp;
+
+ g_return_val_if_fail (func != NULL, list);
+
+ if (!list)
+ {
+ new_list = _g_list_alloc0 ();
+ new_list->data = data;
+ return new_list;
+ }
+
+ cmp = ((GCompareDataFunc) func) (data, tmp_list->data, user_data);
+
+ while ((tmp_list->next) && (cmp > 0))
+ {
+ tmp_list = tmp_list->next;
+
+ cmp = ((GCompareDataFunc) func) (data, tmp_list->data, user_data);
+ }
+
+ new_list = _g_list_alloc0 ();
+ new_list->data = data;
+
+ if ((!tmp_list->next) && (cmp > 0))
+ {
+ tmp_list->next = new_list;
+ new_list->prev = tmp_list;
+ return list;
+ }
+
+ if (tmp_list->prev)
+ {
+ tmp_list->prev->next = new_list;
+ new_list->prev = tmp_list->prev;
+ }
+ new_list->next = tmp_list;
+ tmp_list->prev = new_list;
+
+ if (tmp_list == list)
+ return new_list;
+ else
+ return list;
+}
+
+/**
+ * g_list_insert_sorted:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ * @func: the function to compare elements in the list. It should
+ * return a number > 0 if the first parameter comes after the
+ * second parameter in the sort order.
+ *
+ * Inserts a new element into the list, using the given comparison
+ * function to determine its position.
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_insert_sorted (GList *list,
+ gpointer data,
+ GCompareFunc func)
+{
+ return g_list_insert_sorted_real (list, data, (GFunc) func, NULL);
+}
+
+/**
+ * g_list_insert_sorted_with_data:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ * @func: the function to compare elements in the list.
+ * It should return a number > 0 if the first parameter
+ * comes after the second parameter in the sort order.
+ * @user_data: user data to pass to comparison function.
+ *
+ * Inserts a new element into the list, using the given comparison
+ * function to determine its position.
+ *
+ * Returns: the new start of the #GList
+ *
+ * Since: 2.10
+ */
+GList*
+g_list_insert_sorted_with_data (GList *list,
+ gpointer data,
+ GCompareDataFunc func,
+ gpointer user_data)
+{
+ return g_list_insert_sorted_real (list, data, (GFunc) func, user_data);
+}
+
+static GList *
+g_list_sort_merge (GList *l1,
+ GList *l2,
+ GFunc compare_func,
+ gpointer user_data)
+{
+ GList list, *l, *lprev;
+ gint cmp;
+
+ l = &list;
+ lprev = NULL;
+
+ while (l1 && l2)
+ {
+ cmp = ((GCompareDataFunc) compare_func) (l1->data, l2->data, user_data);
+
+ if (cmp <= 0)
+ {
+ l->next = l1;
+ l1 = l1->next;
+ }
+ else
+ {
+ l->next = l2;
+ l2 = l2->next;
+ }
+ l = l->next;
+ l->prev = lprev;
+ lprev = l;
+ }
+ l->next = l1 ? l1 : l2;
+ l->next->prev = l;
+
+ return list.next;
+}
+
+static GList*
+g_list_sort_real (GList *list,
+ GFunc compare_func,
+ gpointer user_data)
+{
+ GList *l1, *l2;
+
+ if (!list)
+ return NULL;
+ if (!list->next)
+ return list;
+
+ l1 = list;
+ l2 = list->next;
+
+ while ((l2 = l2->next) != NULL)
+ {
+ if ((l2 = l2->next) == NULL)
+ break;
+ l1 = l1->next;
+ }
+ l2 = l1->next;
+ l1->next = NULL;
+
+ return g_list_sort_merge (g_list_sort_real (list, compare_func, user_data),
+ g_list_sort_real (l2, compare_func, user_data),
+ compare_func,
+ user_data);
+}
+
+/**
+ * g_list_sort:
+ * @list: a #GList
+ * @compare_func: the comparison function used to sort the #GList.
+ * This function is passed the data from 2 elements of the #GList
+ * and should return 0 if they are equal, a negative value if the
+ * first element comes before the second, or a positive value if
+ * the first element comes after the second.
+ *
+ * Sorts a #GList using the given comparison function.
+ *
+ * Returns: the start of the sorted #GList
+ */
+GList *
+g_list_sort (GList *list,
+ GCompareFunc compare_func)
+{
+ return g_list_sort_real (list, (GFunc) compare_func, NULL);
+
+}
+
+/**
+ * g_list_sort_with_data:
+ * @list: a #GList
+ * @compare_func: comparison function
+ * @user_data: user data to pass to comparison function
+ *
+ * Like g_list_sort(), but the comparison function accepts
+ * a user data argument.
+ *
+ * Returns: the new head of @list
+ */
+GList *
+g_list_sort_with_data (GList *list,
+ GCompareDataFunc compare_func,
+ gpointer user_data)
+{
+ return g_list_sort_real (list, (GFunc) compare_func, user_data);
+}
+
+#define __G_LIST_C__
+#include "galiasdef.c"
diff --git a/support/glib/glist.h b/support/glib/glist.h
new file mode 100644
index 00000000..e74ed96f
--- /dev/null
+++ b/support/glib/glist.h
@@ -0,0 +1,120 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_LIST_H__
+#define __G_LIST_H__
+
+#include <glib/gmem.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GList GList;
+
+struct _GList
+{
+ gpointer data;
+ GList *next;
+ GList *prev;
+};
+
+/* Doubly linked lists
+ */
+GList* g_list_alloc (void) G_GNUC_WARN_UNUSED_RESULT;
+void g_list_free (GList *list);
+void g_list_free_1 (GList *list);
+#define g_list_free1 g_list_free_1
+GList* g_list_append (GList *list,
+ gpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_prepend (GList *list,
+ gpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_insert (GList *list,
+ gpointer data,
+ gint position) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_insert_sorted (GList *list,
+ gpointer data,
+ GCompareFunc func) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_insert_sorted_with_data (GList *list,
+ gpointer data,
+ GCompareDataFunc func,
+ gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_insert_before (GList *list,
+ GList *sibling,
+ gpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_concat (GList *list1,
+ GList *list2) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_remove (GList *list,
+ gconstpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_remove_all (GList *list,
+ gconstpointer data) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_remove_link (GList *list,
+ GList *llink) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_delete_link (GList *list,
+ GList *link_) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_reverse (GList *list) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_copy (GList *list) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_nth (GList *list,
+ guint n);
+GList* g_list_nth_prev (GList *list,
+ guint n);
+GList* g_list_find (GList *list,
+ gconstpointer data);
+GList* g_list_find_custom (GList *list,
+ gconstpointer data,
+ GCompareFunc func);
+gint g_list_position (GList *list,
+ GList *llink);
+gint g_list_index (GList *list,
+ gconstpointer data);
+GList* g_list_last (GList *list);
+GList* g_list_first (GList *list);
+guint g_list_length (GList *list);
+void g_list_foreach (GList *list,
+ GFunc func,
+ gpointer user_data);
+GList* g_list_sort (GList *list,
+ GCompareFunc compare_func) G_GNUC_WARN_UNUSED_RESULT;
+GList* g_list_sort_with_data (GList *list,
+ GCompareDataFunc compare_func,
+ gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
+gpointer g_list_nth_data (GList *list,
+ guint n);
+
+
+#define g_list_previous(list) ((list) ? (((GList *)(list))->prev) : NULL)
+#define g_list_next(list) ((list) ? (((GList *)(list))->next) : NULL)
+
+#ifndef G_DISABLE_DEPRECATED
+void g_list_push_allocator (gpointer allocator);
+void g_list_pop_allocator (void);
+#endif
+
+G_END_DECLS
+
+#endif /* __G_LIST_H__ */
diff --git a/support/glib/gmacros.h b/support/glib/gmacros.h
new file mode 100644
index 00000000..f87e932c
--- /dev/null
+++ b/support/glib/gmacros.h
@@ -0,0 +1,273 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/* This file must not include any other glib header file and must thus
+ * not refer to variables from glibconfig.h
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MACROS_H__
+#define __G_MACROS_H__
+
+/* We include stddef.h to get the system's definition of NULL
+ */
+#include <stddef.h>
+
+/* Here we provide G_GNUC_EXTENSION as an alias for __extension__,
+ * where this is valid. This allows for warningless compilation of
+ * "long long" types even in the presence of '-ansi -pedantic'.
+ */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+# define G_GNUC_EXTENSION __extension__
+#else
+# define G_GNUC_EXTENSION
+#endif
+
+/* Provide macros to feature the GCC function attribute.
+ */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+#define G_GNUC_PURE \
+ __attribute__((__pure__))
+#define G_GNUC_MALLOC \
+ __attribute__((__malloc__))
+#else
+#define G_GNUC_PURE
+#define G_GNUC_MALLOC
+#endif
+
+#if __GNUC__ >= 4
+#define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
+#else
+#define G_GNUC_NULL_TERMINATED
+#endif
+
+#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+#define G_GNUC_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
+#define G_GNUC_ALLOC_SIZE2(x,y) __attribute__((__alloc_size__(x,y)))
+#else
+#define G_GNUC_ALLOC_SIZE(x)
+#define G_GNUC_ALLOC_SIZE2(x,y)
+#endif
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#define G_GNUC_PRINTF( format_idx, arg_idx ) \
+ __attribute__((__format__ (__printf__, format_idx, arg_idx)))
+#define G_GNUC_SCANF( format_idx, arg_idx ) \
+ __attribute__((__format__ (__scanf__, format_idx, arg_idx)))
+#define G_GNUC_FORMAT( arg_idx ) \
+ __attribute__((__format_arg__ (arg_idx)))
+#define G_GNUC_NORETURN \
+ __attribute__((__noreturn__))
+#define G_GNUC_CONST \
+ __attribute__((__const__))
+#define G_GNUC_UNUSED \
+ __attribute__((__unused__))
+#define G_GNUC_NO_INSTRUMENT \
+ __attribute__((__no_instrument_function__))
+#else /* !__GNUC__ */
+#define G_GNUC_PRINTF( format_idx, arg_idx )
+#define G_GNUC_SCANF( format_idx, arg_idx )
+#define G_GNUC_FORMAT( arg_idx )
+#define G_GNUC_NORETURN
+#define G_GNUC_CONST
+#define G_GNUC_UNUSED
+#define G_GNUC_NO_INSTRUMENT
+#endif /* !__GNUC__ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#define G_GNUC_DEPRECATED \
+ __attribute__((__deprecated__))
+#else
+#define G_GNUC_DEPRECATED
+#endif /* __GNUC__ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+# define G_GNUC_MAY_ALIAS __attribute__((may_alias))
+#else
+# define G_GNUC_MAY_ALIAS
+#endif
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define G_GNUC_WARN_UNUSED_RESULT \
+ __attribute__((warn_unused_result))
+#else
+#define G_GNUC_WARN_UNUSED_RESULT
+#endif /* __GNUC__ */
+
+#ifndef G_DISABLE_DEPRECATED
+/* Wrap the gcc __PRETTY_FUNCTION__ and __FUNCTION__ variables with
+ * macros, so we can refer to them as strings unconditionally.
+ * usage not-recommended since gcc-3.0
+ */
+#if defined (__GNUC__) && (__GNUC__ < 3)
+#define G_GNUC_FUNCTION __FUNCTION__
+#define G_GNUC_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else /* !__GNUC__ */
+#define G_GNUC_FUNCTION ""
+#define G_GNUC_PRETTY_FUNCTION ""
+#endif /* !__GNUC__ */
+#endif /* !G_DISABLE_DEPRECATED */
+
+#define G_STRINGIFY(macro_or_string) G_STRINGIFY_ARG (macro_or_string)
+#define G_STRINGIFY_ARG(contents) #contents
+
+/* Provide a string identifying the current code position */
+#if defined(__GNUC__) && (__GNUC__ < 3) && !defined(__cplusplus)
+# define G_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__) ":" __PRETTY_FUNCTION__ "()"
+#else
+# define G_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__)
+#endif
+
+/* Provide a string identifying the current function, non-concatenatable */
+#if defined (__GNUC__)
+# define G_STRFUNC ((const char*) (__PRETTY_FUNCTION__))
+#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 19901L
+# define G_STRFUNC ((const char*) (__func__))
+#else
+# define G_STRFUNC ((const char*) ("???"))
+#endif
+
+/* Guard C code in headers, while including them from C++ */
+#ifdef __cplusplus
+# define G_BEGIN_DECLS extern "C" {
+# define G_END_DECLS }
+#else
+# define G_BEGIN_DECLS
+# define G_END_DECLS
+#endif
+
+/* Provide definitions for some commonly used macros.
+ * Some of them are only provided if they haven't already
+ * been defined. It is assumed that if they are already
+ * defined then the current definition is correct.
+ */
+#ifndef NULL
+# ifdef __cplusplus
+# define NULL (0L)
+# else /* !__cplusplus */
+# define NULL ((void*) 0)
+# endif /* !__cplusplus */
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#undef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#undef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#undef ABS
+#define ABS(a) (((a) < 0) ? -(a) : (a))
+
+#undef CLAMP
+#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+
+/* Count the number of elements in an array. The array must be defined
+ * as such; using this with a dynamically allocated array will give
+ * incorrect results.
+ */
+#define G_N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0]))
+
+/* Macros by analogy to GINT_TO_POINTER, GPOINTER_TO_INT
+ */
+#define GPOINTER_TO_SIZE(p) ((gsize) (p))
+#define GSIZE_TO_POINTER(s) ((gpointer) (gsize) (s))
+
+/* Provide convenience macros for handling structure
+ * fields through their offsets.
+ */
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define G_STRUCT_OFFSET(struct_type, member) \
+ ((glong) __builtin_offsetof (struct_type, member))
+#else
+# define G_STRUCT_OFFSET(struct_type, member) \
+ ((glong) ((guint8*) &((struct_type*) 0)->member))
+#endif
+
+#define G_STRUCT_MEMBER_P(struct_p, struct_offset) \
+ ((gpointer) ((guint8*) (struct_p) + (glong) (struct_offset)))
+#define G_STRUCT_MEMBER(member_type, struct_p, struct_offset) \
+ (*(member_type*) G_STRUCT_MEMBER_P ((struct_p), (struct_offset)))
+
+/* Provide simple macro statement wrappers:
+ * G_STMT_START { statements; } G_STMT_END;
+ * This can be used as a single statement, like:
+ * if (x) G_STMT_START { ... } G_STMT_END; else ...
+ * This intentionally does not use compiler extensions like GCC's '({...})' to
+ * avoid portability issue or side effects when compiled with different compilers.
+ */
+#if !(defined (G_STMT_START) && defined (G_STMT_END))
+# define G_STMT_START do
+# define G_STMT_END while (0)
+#endif
+
+/* Allow the app programmer to select whether or not return values
+ * (usually char*) are const or not. Don't try using this feature for
+ * functions with C++ linkage.
+ */
+#ifdef G_DISABLE_CONST_RETURNS
+#define G_CONST_RETURN
+#else
+#define G_CONST_RETURN const
+#endif
+
+/*
+ * The G_LIKELY and G_UNLIKELY macros let the programmer give hints to
+ * the compiler about the expected result of an expression. Some compilers
+ * can use this information for optimizations.
+ *
+ * The _G_BOOLEAN_EXPR macro is intended to trigger a gcc warning when
+ * putting assignments in g_return_if_fail ().
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define _G_BOOLEAN_EXPR(expr) \
+ __extension__ ({ \
+ int _g_boolean_var_; \
+ if (expr) \
+ _g_boolean_var_ = 1; \
+ else \
+ _g_boolean_var_ = 0; \
+ _g_boolean_var_; \
+})
+#define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
+#define G_UNLIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 0))
+#else
+#define G_LIKELY(expr) (expr)
+#define G_UNLIKELY(expr) (expr)
+#endif
+
+#endif /* __G_MACROS_H__ */
diff --git a/support/glib/gmem.c b/support/glib/gmem.c
new file mode 100644
index 00000000..9cc091fd
--- /dev/null
+++ b/support/glib/gmem.c
@@ -0,0 +1,742 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include "glib.h"
+#include "gthreadprivate.h"
+#include "galias.h"
+
+#define MEM_PROFILE_TABLE_SIZE 4096
+
+
+/* notes on macros:
+ * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and
+ * g_mem_profile().
+ * REALLOC_0_WORKS is defined if g_realloc (NULL, x) works.
+ * SANE_MALLOC_PROTOS is defined if the systems malloc() and friends functions
+ * match the corresponding GLib prototypes, keep configure.in and gmem.h in sync here.
+ * g_mem_gc_friendly is TRUE, freed memory should be 0-wiped.
+ */
+
+/* --- prototypes --- */
+static gboolean g_mem_initialized = FALSE;
+static void g_mem_init_nomessage (void);
+
+
+/* --- malloc wrappers --- */
+#ifndef REALLOC_0_WORKS
+static gpointer
+standard_realloc (gpointer mem,
+ gsize n_bytes)
+{
+ if (!mem)
+ return malloc (n_bytes);
+ else
+ return realloc (mem, n_bytes);
+}
+#endif /* !REALLOC_0_WORKS */
+
+#ifdef SANE_MALLOC_PROTOS
+# define standard_malloc malloc
+# ifdef REALLOC_0_WORKS
+# define standard_realloc realloc
+# endif /* REALLOC_0_WORKS */
+# define standard_free free
+# define standard_calloc calloc
+# define standard_try_malloc malloc
+# define standard_try_realloc realloc
+#else /* !SANE_MALLOC_PROTOS */
+static gpointer
+standard_malloc (gsize n_bytes)
+{
+ return malloc (n_bytes);
+}
+# ifdef REALLOC_0_WORKS
+static gpointer
+standard_realloc (gpointer mem,
+ gsize n_bytes)
+{
+ return realloc (mem, n_bytes);
+}
+# endif /* REALLOC_0_WORKS */
+static void
+standard_free (gpointer mem)
+{
+ free (mem);
+}
+static gpointer
+standard_calloc (gsize n_blocks,
+ gsize n_bytes)
+{
+ return calloc (n_blocks, n_bytes);
+}
+#define standard_try_malloc standard_malloc
+#define standard_try_realloc standard_realloc
+#endif /* !SANE_MALLOC_PROTOS */
+
+
+/* --- variables --- */
+static GMemVTable glib_mem_vtable = {
+ standard_malloc,
+ standard_realloc,
+ standard_free,
+ standard_calloc,
+ standard_try_malloc,
+ standard_try_realloc,
+};
+
+
+/* --- functions --- */
+gpointer
+g_malloc (gsize n_bytes)
+{
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+ if (G_LIKELY (n_bytes))
+ {
+ gpointer mem;
+
+ mem = glib_mem_vtable.malloc (n_bytes);
+ if (mem)
+ return mem;
+
+#if NOT_NEEDED_FOR_NAVIT
+ g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
+ G_STRLOC, n_bytes);
+#endif /* NOT_NEEDED_FOR_NAVIT */
+ }
+
+ return NULL;
+}
+
+gpointer
+g_malloc0 (gsize n_bytes)
+{
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+ if (G_LIKELY (n_bytes))
+ {
+ gpointer mem;
+
+ mem = glib_mem_vtable.calloc (1, n_bytes);
+ if (mem)
+ return mem;
+
+#if NOT_NEEDED_FOR_NAVIT
+ g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
+ G_STRLOC, n_bytes);
+#endif /* NOT_NEEDED_FOR_NAVIT */
+ }
+
+ return NULL;
+}
+
+gpointer
+g_realloc (gpointer mem,
+ gsize n_bytes)
+{
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+ if (G_LIKELY (n_bytes))
+ {
+ mem = glib_mem_vtable.realloc (mem, n_bytes);
+ if (mem)
+ return mem;
+
+#if NOT_NEEDED_FOR_NAVIT
+ g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
+ G_STRLOC, n_bytes);
+#endif /* NOT_NEEDED_FOR_NAVIT */
+ }
+
+ if (mem)
+ glib_mem_vtable.free (mem);
+
+ return NULL;
+}
+
+void
+g_free (gpointer mem)
+{
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+ if (G_LIKELY (mem))
+ glib_mem_vtable.free (mem);
+}
+
+gpointer
+g_try_malloc (gsize n_bytes)
+{
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+ if (G_LIKELY (n_bytes))
+ return glib_mem_vtable.try_malloc (n_bytes);
+ else
+ return NULL;
+}
+
+gpointer
+g_try_malloc0 (gsize n_bytes)
+{
+ gpointer mem;
+
+ mem = g_try_malloc (n_bytes);
+
+ if (mem)
+ memset (mem, 0, n_bytes);
+
+ return mem;
+}
+
+gpointer
+g_try_realloc (gpointer mem,
+ gsize n_bytes)
+{
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+ if (G_LIKELY (n_bytes))
+ return glib_mem_vtable.try_realloc (mem, n_bytes);
+
+ if (mem)
+ glib_mem_vtable.free (mem);
+
+ return NULL;
+}
+
+static gpointer
+fallback_calloc (gsize n_blocks,
+ gsize n_block_bytes)
+{
+ gsize l = n_blocks * n_block_bytes;
+ gpointer mem = glib_mem_vtable.malloc (l);
+
+ if (mem)
+ memset (mem, 0, l);
+
+ return mem;
+}
+
+static gboolean vtable_set = FALSE;
+
+/**
+ * g_mem_is_system_malloc
+ *
+ * Checks whether the allocator used by g_malloc() is the system's
+ * malloc implementation. If it returns %TRUE memory allocated with
+ * malloc() can be used interchangeable with memory allocated using g_malloc().
+ * This function is useful for avoiding an extra copy of allocated memory returned
+ * by a non-GLib-based API.
+ *
+ * A different allocator can be set using g_mem_set_vtable().
+ *
+ * Return value: if %TRUE, malloc() and g_malloc() can be mixed.
+ **/
+gboolean
+g_mem_is_system_malloc (void)
+{
+ return !vtable_set;
+}
+
+void
+g_mem_set_vtable (GMemVTable *vtable)
+{
+ if (!vtable_set)
+ {
+ if (vtable->malloc && vtable->realloc && vtable->free)
+ {
+ glib_mem_vtable.malloc = vtable->malloc;
+ glib_mem_vtable.realloc = vtable->realloc;
+ glib_mem_vtable.free = vtable->free;
+ glib_mem_vtable.calloc = vtable->calloc ? vtable->calloc : fallback_calloc;
+ glib_mem_vtable.try_malloc = vtable->try_malloc ? vtable->try_malloc : glib_mem_vtable.malloc;
+ glib_mem_vtable.try_realloc = vtable->try_realloc ? vtable->try_realloc : glib_mem_vtable.realloc;
+ vtable_set = TRUE;
+ }
+#if NOT_NEEDED_FOR_NAVIT
+ else
+ g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()");
+#endif /* NOT_NEEDED_FOR_NAVIT */
+ }
+#if NOT_NEEDED_FOR_NAVIT
+ else
+ g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup");
+#endif /* NOT_NEEDED_FOR_NAVIT */
+}
+
+
+/* --- memory profiling and checking --- */
+#ifdef G_DISABLE_CHECKS
+GMemVTable *glib_mem_profiler_table = &glib_mem_vtable;
+void
+g_mem_profile (void)
+{
+}
+#else /* !G_DISABLE_CHECKS */
+typedef enum {
+ PROFILER_FREE = 0,
+ PROFILER_ALLOC = 1,
+ PROFILER_RELOC = 2,
+ PROFILER_ZINIT = 4
+} ProfilerJob;
+static guint *profile_data = NULL;
+static gsize profile_allocs = 0;
+static gsize profile_zinit = 0;
+static gsize profile_frees = 0;
+static GMutex *gmem_profile_mutex = NULL;
+#ifdef G_ENABLE_DEBUG
+static volatile gsize g_trap_free_size = 0;
+static volatile gsize g_trap_realloc_size = 0;
+static volatile gsize g_trap_malloc_size = 0;
+#endif /* G_ENABLE_DEBUG */
+
+#define PROFILE_TABLE(f1,f2,f3) ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 1))
+
+static void
+profiler_log (ProfilerJob job,
+ gsize n_bytes,
+ gboolean success)
+{
+ g_mutex_lock (gmem_profile_mutex);
+ if (!profile_data)
+ {
+ profile_data = standard_calloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8,
+ sizeof (profile_data[0]));
+ if (!profile_data) /* memory system kiddin' me, eh? */
+ {
+ g_mutex_unlock (gmem_profile_mutex);
+ return;
+ }
+ }
+
+ if (n_bytes < MEM_PROFILE_TABLE_SIZE)
+ profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
+ (job & PROFILER_RELOC) != 0,
+ success != 0)] += 1;
+ else
+ profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
+ (job & PROFILER_RELOC) != 0,
+ success != 0)] += 1;
+ if (success)
+ {
+ if (job & PROFILER_ALLOC)
+ {
+ profile_allocs += n_bytes;
+ if (job & PROFILER_ZINIT)
+ profile_zinit += n_bytes;
+ }
+ else
+ profile_frees += n_bytes;
+ }
+ g_mutex_unlock (gmem_profile_mutex);
+}
+
+static void
+profile_print_locked (guint *local_data,
+ gboolean success)
+{
+ gboolean need_header = TRUE;
+ guint i;
+
+ for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++)
+ {
+ glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)];
+ glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)];
+ glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)];
+ glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)];
+
+ if (!t_malloc && !t_realloc && !t_free && !t_refree)
+ continue;
+ else if (need_header)
+ {
+ need_header = FALSE;
+ g_print (" blocks of | allocated | freed | allocated | freed | n_bytes \n");
+ g_print (" n_bytes | n_times by | n_times by | n_times by | n_times by | remaining \n");
+ g_print (" | malloc() | free() | realloc() | realloc() | \n");
+ g_print ("===========|============|============|============|============|===========\n");
+ }
+ if (i < MEM_PROFILE_TABLE_SIZE)
+ g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n",
+ i, t_malloc, t_free, t_realloc, t_refree,
+ (t_malloc - t_free + t_realloc - t_refree) * i);
+ else if (i >= MEM_PROFILE_TABLE_SIZE)
+ g_print (" >%6u | %10ld | %10ld | %10ld | %10ld | ***\n",
+ i, t_malloc, t_free, t_realloc, t_refree);
+ }
+ if (need_header)
+ g_print (" --- none ---\n");
+}
+
+void
+g_mem_profile (void)
+{
+ guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])];
+ gsize local_allocs;
+ gsize local_zinit;
+ gsize local_frees;
+
+ if (G_UNLIKELY (!g_mem_initialized))
+ g_mem_init_nomessage();
+
+ g_mutex_lock (gmem_profile_mutex);
+
+ local_allocs = profile_allocs;
+ local_zinit = profile_zinit;
+ local_frees = profile_frees;
+
+ if (!profile_data)
+ {
+ g_mutex_unlock (gmem_profile_mutex);
+ return;
+ }
+
+ memcpy (local_data, profile_data,
+ (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0]));
+
+ g_mutex_unlock (gmem_profile_mutex);
+
+ g_print ("GLib Memory statistics (successful operations):\n");
+ profile_print_locked (local_data, TRUE);
+ g_print ("GLib Memory statistics (failing operations):\n");
+ profile_print_locked (local_data, FALSE);
+ g_print ("Total bytes: allocated=%"G_GSIZE_FORMAT", "
+ "zero-initialized=%"G_GSIZE_FORMAT" (%.2f%%), "
+ "freed=%"G_GSIZE_FORMAT" (%.2f%%), "
+ "remaining=%"G_GSIZE_FORMAT"\n",
+ local_allocs,
+ local_zinit,
+ ((gdouble) local_zinit) / local_allocs * 100.0,
+ local_frees,
+ ((gdouble) local_frees) / local_allocs * 100.0,
+ local_allocs - local_frees);
+}
+
+static gpointer
+profiler_try_malloc (gsize n_bytes)
+{
+ gsize *p;
+
+#ifdef G_ENABLE_DEBUG
+ if (g_trap_malloc_size == n_bytes)
+ G_BREAKPOINT ();
+#endif /* G_ENABLE_DEBUG */
+
+ p = standard_malloc (sizeof (gsize) * 2 + n_bytes);
+
+ if (p)
+ {
+ p[0] = 0; /* free count */
+ p[1] = n_bytes; /* length */
+ profiler_log (PROFILER_ALLOC, n_bytes, TRUE);
+ p += 2;
+ }
+ else
+ profiler_log (PROFILER_ALLOC, n_bytes, FALSE);
+
+ return p;
+}
+
+static gpointer
+profiler_malloc (gsize n_bytes)
+{
+ gpointer mem = profiler_try_malloc (n_bytes);
+
+ if (!mem)
+ g_mem_profile ();
+
+ return mem;
+}
+
+static gpointer
+profiler_calloc (gsize n_blocks,
+ gsize n_block_bytes)
+{
+ gsize l = n_blocks * n_block_bytes;
+ gsize *p;
+
+#ifdef G_ENABLE_DEBUG
+ if (g_trap_malloc_size == l)
+ G_BREAKPOINT ();
+#endif /* G_ENABLE_DEBUG */
+
+ p = standard_calloc (1, sizeof (gsize) * 2 + l);
+
+ if (p)
+ {
+ p[0] = 0; /* free count */
+ p[1] = l; /* length */
+ profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE);
+ p += 2;
+ }
+ else
+ {
+ profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE);
+ g_mem_profile ();
+ }
+
+ return p;
+}
+
+static void
+profiler_free (gpointer mem)
+{
+ gsize *p = mem;
+
+ p -= 2;
+ if (p[0]) /* free count */
+ {
+ g_warning ("free(%p): memory has been freed %"G_GSIZE_FORMAT" times already",
+ p + 2, p[0]);
+ profiler_log (PROFILER_FREE,
+ p[1], /* length */
+ FALSE);
+ }
+ else
+ {
+#ifdef G_ENABLE_DEBUG
+ if (g_trap_free_size == p[1])
+ G_BREAKPOINT ();
+#endif /* G_ENABLE_DEBUG */
+
+ profiler_log (PROFILER_FREE,
+ p[1], /* length */
+ TRUE);
+ memset (p + 2, 0xaa, p[1]);
+
+ /* for all those that miss standard_free (p); in this place, yes,
+ * we do leak all memory when profiling, and that is intentional
+ * to catch double frees. patch submissions are futile.
+ */
+ }
+ p[0] += 1;
+}
+
+static gpointer
+profiler_try_realloc (gpointer mem,
+ gsize n_bytes)
+{
+ gsize *p = mem;
+
+ p -= 2;
+
+#ifdef G_ENABLE_DEBUG
+ if (g_trap_realloc_size == n_bytes)
+ G_BREAKPOINT ();
+#endif /* G_ENABLE_DEBUG */
+
+ if (mem && p[0]) /* free count */
+ {
+ g_warning ("realloc(%p, %"G_GSIZE_FORMAT"): "
+ "memory has been freed %"G_GSIZE_FORMAT" times already",
+ p + 2, (gsize) n_bytes, p[0]);
+ profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
+
+ return NULL;
+ }
+ else
+ {
+ p = standard_realloc (mem ? p : NULL, sizeof (gsize) * 2 + n_bytes);
+
+ if (p)
+ {
+ if (mem)
+ profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE);
+ p[0] = 0;
+ p[1] = n_bytes;
+ profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE);
+ p += 2;
+ }
+ else
+ profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
+
+ return p;
+ }
+}
+
+static gpointer
+profiler_realloc (gpointer mem,
+ gsize n_bytes)
+{
+ mem = profiler_try_realloc (mem, n_bytes);
+
+ if (!mem)
+ g_mem_profile ();
+
+ return mem;
+}
+
+static GMemVTable profiler_table = {
+ profiler_malloc,
+ profiler_realloc,
+ profiler_free,
+ profiler_calloc,
+ profiler_try_malloc,
+ profiler_try_realloc,
+};
+GMemVTable *glib_mem_profiler_table = &profiler_table;
+
+#endif /* !G_DISABLE_CHECKS */
+
+/* --- MemChunks --- */
+#ifndef G_ALLOC_AND_FREE
+typedef struct _GAllocator GAllocator;
+typedef struct _GMemChunk GMemChunk;
+#define G_ALLOC_ONLY 1
+#define G_ALLOC_AND_FREE 2
+#endif
+
+struct _GMemChunk {
+ guint alloc_size; /* the size of an atom */
+};
+
+GMemChunk*
+g_mem_chunk_new (const gchar *name,
+ gint atom_size,
+ gsize area_size,
+ gint type)
+{
+ GMemChunk *mem_chunk;
+ g_return_val_if_fail (atom_size > 0, NULL);
+
+ mem_chunk = g_slice_new (GMemChunk);
+ mem_chunk->alloc_size = atom_size;
+ return mem_chunk;
+}
+
+void
+g_mem_chunk_destroy (GMemChunk *mem_chunk)
+{
+ g_return_if_fail (mem_chunk != NULL);
+
+ g_slice_free (GMemChunk, mem_chunk);
+}
+
+gpointer
+g_mem_chunk_alloc (GMemChunk *mem_chunk)
+{
+ g_return_val_if_fail (mem_chunk != NULL, NULL);
+
+ return g_slice_alloc (mem_chunk->alloc_size);
+}
+
+gpointer
+g_mem_chunk_alloc0 (GMemChunk *mem_chunk)
+{
+ g_return_val_if_fail (mem_chunk != NULL, NULL);
+
+ return g_slice_alloc0 (mem_chunk->alloc_size);
+}
+
+void
+g_mem_chunk_free (GMemChunk *mem_chunk,
+ gpointer mem)
+{
+ g_return_if_fail (mem_chunk != NULL);
+
+ g_slice_free1 (mem_chunk->alloc_size, mem);
+}
+
+void g_mem_chunk_clean (GMemChunk *mem_chunk) {}
+void g_mem_chunk_reset (GMemChunk *mem_chunk) {}
+void g_mem_chunk_print (GMemChunk *mem_chunk) {}
+void g_mem_chunk_info (void) {}
+void g_blow_chunks (void) {}
+
+GAllocator*
+g_allocator_new (const gchar *name,
+ guint n_preallocs)
+{
+ static struct _GAllocator {
+ gchar *name;
+ guint16 n_preallocs;
+ guint is_unused : 1;
+ guint type : 4;
+ GAllocator *last;
+ GMemChunk *mem_chunk;
+ gpointer free_list;
+ } dummy = {
+ "GAllocator is deprecated", 1, TRUE, 0, NULL, NULL, NULL,
+ };
+ /* some (broken) GAllocator uses depend on non-NULL allocators */
+ return (void*) &dummy;
+}
+
+void
+g_allocator_free (GAllocator *allocator)
+{
+}
+
+#ifdef ENABLE_GC_FRIENDLY_DEFAULT
+gboolean g_mem_gc_friendly = TRUE;
+#else
+gboolean g_mem_gc_friendly = FALSE;
+#endif
+
+static void
+g_mem_init_nomessage (void)
+{
+#if NOT_NEEDED_FOR_NAVIT
+ gchar buffer[1024];
+ const gchar *val;
+ const GDebugKey keys[] = {
+ { "gc-friendly", 1 },
+ };
+ gint flags;
+ if (g_mem_initialized)
+ return;
+ /* don't use g_malloc/g_message here */
+ val = _g_getenv_nomalloc ("G_DEBUG", buffer);
+ flags = !val ? 0 : g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
+ if (flags & 1) /* gc-friendly */
+ {
+ g_mem_gc_friendly = TRUE;
+ }
+#endif /* NOT_NEEDED_FOR_NAVIT */
+ g_mem_initialized = TRUE;
+}
+
+void
+_g_mem_thread_init_noprivate_nomessage (void)
+{
+ /* we may only create mutexes here, locking/
+ * unlocking a mutex does not yet work.
+ */
+ g_mem_init_nomessage();
+#ifndef G_DISABLE_CHECKS
+ gmem_profile_mutex = g_mutex_new ();
+#endif
+}
+
+#define __G_MEM_C__
+#include "galiasdef.c"
diff --git a/support/glib/gmem.h b/support/glib/gmem.h
new file mode 100644
index 00000000..8cb050ee
--- /dev/null
+++ b/support/glib/gmem.h
@@ -0,0 +1,152 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MEM_H__
+#define __G_MEM_H__
+
+#include <glib/gslice.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GMemVTable GMemVTable;
+
+
+#if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG
+# define G_MEM_ALIGN GLIB_SIZEOF_VOID_P
+#else /* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */
+# define G_MEM_ALIGN GLIB_SIZEOF_LONG
+#endif /* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */
+
+
+/* Memory allocation functions
+ */
+gpointer g_malloc (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_malloc0 (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_realloc (gpointer mem,
+ gsize n_bytes) G_GNUC_WARN_UNUSED_RESULT;
+void g_free (gpointer mem);
+gpointer g_try_malloc (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_try_malloc0 (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_try_realloc (gpointer mem,
+ gsize n_bytes) G_GNUC_WARN_UNUSED_RESULT;
+
+
+/* Convenience memory allocators
+ */
+#define g_new(struct_type, n_structs) \
+ ((struct_type *) g_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_new0(struct_type, n_structs) \
+ ((struct_type *) g_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_renew(struct_type, mem, n_structs) \
+ ((struct_type *) g_realloc ((mem), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+
+#define g_try_new(struct_type, n_structs) \
+ ((struct_type *) g_try_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_try_new0(struct_type, n_structs) \
+ ((struct_type *) g_try_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_try_renew(struct_type, mem, n_structs) \
+ ((struct_type *) g_try_realloc ((mem), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+
+
+/* Memory allocation virtualization for debugging purposes
+ * g_mem_set_vtable() has to be the very first GLib function called
+ * if being used
+ */
+struct _GMemVTable
+{
+ gpointer (*malloc) (gsize n_bytes);
+ gpointer (*realloc) (gpointer mem,
+ gsize n_bytes);
+ void (*free) (gpointer mem);
+ /* optional; set to NULL if not used ! */
+ gpointer (*calloc) (gsize n_blocks,
+ gsize n_block_bytes);
+ gpointer (*try_malloc) (gsize n_bytes);
+ gpointer (*try_realloc) (gpointer mem,
+ gsize n_bytes);
+};
+void g_mem_set_vtable (GMemVTable *vtable);
+gboolean g_mem_is_system_malloc (void);
+
+GLIB_VAR gboolean g_mem_gc_friendly;
+
+/* Memory profiler and checker, has to be enabled via g_mem_set_vtable()
+ */
+GLIB_VAR GMemVTable *glib_mem_profiler_table;
+void g_mem_profile (void);
+
+
+/* deprecated memchunks and allocators */
+#if !defined (G_DISABLE_DEPRECATED) || defined (GTK_COMPILATION) || defined (GDK_COMPILATION)
+typedef struct _GAllocator GAllocator;
+typedef struct _GMemChunk GMemChunk;
+#define g_mem_chunk_create(type, pre_alloc, alloc_type) ( \
+ g_mem_chunk_new (#type " mem chunks (" #pre_alloc ")", \
+ sizeof (type), \
+ sizeof (type) * (pre_alloc), \
+ (alloc_type)) \
+)
+#define g_chunk_new(type, chunk) ( \
+ (type *) g_mem_chunk_alloc (chunk) \
+)
+#define g_chunk_new0(type, chunk) ( \
+ (type *) g_mem_chunk_alloc0 (chunk) \
+)
+#define g_chunk_free(mem, mem_chunk) G_STMT_START { \
+ g_mem_chunk_free ((mem_chunk), (mem)); \
+} G_STMT_END
+#define G_ALLOC_ONLY 1
+#define G_ALLOC_AND_FREE 2
+GMemChunk* g_mem_chunk_new (const gchar *name,
+ gint atom_size,
+ gsize area_size,
+ gint type);
+void g_mem_chunk_destroy (GMemChunk *mem_chunk);
+gpointer g_mem_chunk_alloc (GMemChunk *mem_chunk);
+gpointer g_mem_chunk_alloc0 (GMemChunk *mem_chunk);
+void g_mem_chunk_free (GMemChunk *mem_chunk,
+ gpointer mem);
+void g_mem_chunk_clean (GMemChunk *mem_chunk);
+void g_mem_chunk_reset (GMemChunk *mem_chunk);
+void g_mem_chunk_print (GMemChunk *mem_chunk);
+void g_mem_chunk_info (void);
+void g_blow_chunks (void);
+GAllocator*g_allocator_new (const gchar *name,
+ guint n_preallocs);
+void g_allocator_free (GAllocator *allocator);
+#define G_ALLOCATOR_LIST (1)
+#define G_ALLOCATOR_SLIST (2)
+#define G_ALLOCATOR_NODE (3)
+#endif /* G_DISABLE_DEPRECATED */
+
+G_END_DECLS
+
+#endif /* __G_MEM_H__ */
diff --git a/support/glib/gmessages.c b/support/glib/gmessages.c
new file mode 100644
index 00000000..548a412c
--- /dev/null
+++ b/support/glib/gmessages.c
@@ -0,0 +1,1126 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <locale.h>
+#include <errno.h>
+
+#include "glib.h"
+#if NOT_NEEDED_FOR_NAVIT
+#include "gdebug.h"
+#endif /* NOT_NEEDED_FOR_NAVIT */
+#include "gprintfint.h"
+#include "gthreadprivate.h"
+#include "galias.h"
+#include "config.h"
+
+#if NOT_NEEDED_FOR_NAVIT
+#ifdef G_OS_WIN32
+#include <process.h> /* For getpid() */
+#include <io.h>
+# define STRICT /* Strict typing, please */
+# define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */
+# include <windows.h>
+# undef STRICT
+#endif
+
+/* --- structures --- */
+typedef struct _GLogDomain GLogDomain;
+typedef struct _GLogHandler GLogHandler;
+struct _GLogDomain
+{
+ gchar *log_domain;
+ GLogLevelFlags fatal_mask;
+ GLogHandler *handlers;
+ GLogDomain *next;
+};
+struct _GLogHandler
+{
+ guint id;
+ GLogLevelFlags log_level;
+ GLogFunc log_func;
+ gpointer data;
+ GLogHandler *next;
+};
+
+
+/* --- variables --- */
+static GMutex *g_messages_lock = NULL;
+static GLogDomain *g_log_domains = NULL;
+static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
+static GPrintFunc glib_print_func = NULL;
+static GPrintFunc glib_printerr_func = NULL;
+static GPrivate *g_log_depth = NULL;
+static GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
+static GLogFunc default_log_func = g_log_default_handler;
+static gpointer default_log_data = NULL;
+
+/* --- functions --- */
+#ifdef G_OS_WIN32
+# define STRICT
+# include <windows.h>
+# undef STRICT
+static gboolean win32_keep_fatal_message = FALSE;
+
+/* This default message will usually be overwritten. */
+/* Yes, a fixed size buffer is bad. So sue me. But g_error() is never
+ * called with huge strings, is it?
+ */
+static gchar fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting.";
+static gchar *fatal_msg_ptr = fatal_msg_buf;
+
+#undef write
+static inline int
+dowrite (int fd,
+ const void *buf,
+ unsigned int len)
+{
+ if (win32_keep_fatal_message)
+ {
+ memcpy (fatal_msg_ptr, buf, len);
+ fatal_msg_ptr += len;
+ *fatal_msg_ptr = 0;
+ return len;
+ }
+
+ write (fd, buf, len);
+
+ return len;
+}
+#define write(fd, buf, len) dowrite(fd, buf, len)
+
+#endif
+
+static void
+write_string (int fd,
+ const gchar *string)
+{
+ write (fd, string, strlen (string));
+}
+
+static void
+g_messages_prefixed_init (void)
+{
+ static gboolean initialized = FALSE;
+
+ if (!initialized)
+ {
+ const gchar *val;
+
+ initialized = TRUE;
+ val = g_getenv ("G_MESSAGES_PREFIXED");
+
+ if (val)
+ {
+ const GDebugKey keys[] = {
+ { "error", G_LOG_LEVEL_ERROR },
+ { "critical", G_LOG_LEVEL_CRITICAL },
+ { "warning", G_LOG_LEVEL_WARNING },
+ { "message", G_LOG_LEVEL_MESSAGE },
+ { "info", G_LOG_LEVEL_INFO },
+ { "debug", G_LOG_LEVEL_DEBUG }
+ };
+
+ g_log_msg_prefix = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
+ }
+ }
+}
+
+static GLogDomain*
+g_log_find_domain_L (const gchar *log_domain)
+{
+ register GLogDomain *domain;
+
+ domain = g_log_domains;
+ while (domain)
+ {
+ if (strcmp (domain->log_domain, log_domain) == 0)
+ return domain;
+ domain = domain->next;
+ }
+ return NULL;
+}
+
+static GLogDomain*
+g_log_domain_new_L (const gchar *log_domain)
+{
+ register GLogDomain *domain;
+
+ domain = g_new (GLogDomain, 1);
+ domain->log_domain = g_strdup (log_domain);
+ domain->fatal_mask = G_LOG_FATAL_MASK;
+ domain->handlers = NULL;
+
+ domain->next = g_log_domains;
+ g_log_domains = domain;
+
+ return domain;
+}
+
+static void
+g_log_domain_check_free_L (GLogDomain *domain)
+{
+ if (domain->fatal_mask == G_LOG_FATAL_MASK &&
+ domain->handlers == NULL)
+ {
+ register GLogDomain *last, *work;
+
+ last = NULL;
+
+ work = g_log_domains;
+ while (work)
+ {
+ if (work == domain)
+ {
+ if (last)
+ last->next = domain->next;
+ else
+ g_log_domains = domain->next;
+ g_free (domain->log_domain);
+ g_free (domain);
+ break;
+ }
+ last = work;
+ work = last->next;
+ }
+ }
+}
+
+static GLogFunc
+g_log_domain_get_handler_L (GLogDomain *domain,
+ GLogLevelFlags log_level,
+ gpointer *data)
+{
+ if (domain && log_level)
+ {
+ register GLogHandler *handler;
+
+ handler = domain->handlers;
+ while (handler)
+ {
+ if ((handler->log_level & log_level) == log_level)
+ {
+ *data = handler->data;
+ return handler->log_func;
+ }
+ handler = handler->next;
+ }
+ }
+
+ *data = default_log_data;
+ return default_log_func;
+}
+
+GLogLevelFlags
+g_log_set_always_fatal (GLogLevelFlags fatal_mask)
+{
+ GLogLevelFlags old_mask;
+
+ /* restrict the global mask to levels that are known to glib
+ * since this setting applies to all domains
+ */
+ fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1;
+ /* force errors to be fatal */
+ fatal_mask |= G_LOG_LEVEL_ERROR;
+ /* remove bogus flag */
+ fatal_mask &= ~G_LOG_FLAG_FATAL;
+
+ g_mutex_lock (g_messages_lock);
+ old_mask = g_log_always_fatal;
+ g_log_always_fatal = fatal_mask;
+ g_mutex_unlock (g_messages_lock);
+
+ return old_mask;
+}
+
+GLogLevelFlags
+g_log_set_fatal_mask (const gchar *log_domain,
+ GLogLevelFlags fatal_mask)
+{
+ GLogLevelFlags old_flags;
+ register GLogDomain *domain;
+
+ if (!log_domain)
+ log_domain = "";
+
+ /* force errors to be fatal */
+ fatal_mask |= G_LOG_LEVEL_ERROR;
+ /* remove bogus flag */
+ fatal_mask &= ~G_LOG_FLAG_FATAL;
+
+ g_mutex_lock (g_messages_lock);
+
+ domain = g_log_find_domain_L (log_domain);
+ if (!domain)
+ domain = g_log_domain_new_L (log_domain);
+ old_flags = domain->fatal_mask;
+
+ domain->fatal_mask = fatal_mask;
+ g_log_domain_check_free_L (domain);
+
+ g_mutex_unlock (g_messages_lock);
+
+ return old_flags;
+}
+
+guint
+g_log_set_handler (const gchar *log_domain,
+ GLogLevelFlags log_levels,
+ GLogFunc log_func,
+ gpointer user_data)
+{
+ static guint handler_id = 0;
+ GLogDomain *domain;
+ GLogHandler *handler;
+
+ g_return_val_if_fail ((log_levels & G_LOG_LEVEL_MASK) != 0, 0);
+ g_return_val_if_fail (log_func != NULL, 0);
+
+ if (!log_domain)
+ log_domain = "";
+
+ handler = g_new (GLogHandler, 1);
+
+ g_mutex_lock (g_messages_lock);
+
+ domain = g_log_find_domain_L (log_domain);
+ if (!domain)
+ domain = g_log_domain_new_L (log_domain);
+
+ handler->id = ++handler_id;
+ handler->log_level = log_levels;
+ handler->log_func = log_func;
+ handler->data = user_data;
+ handler->next = domain->handlers;
+ domain->handlers = handler;
+
+ g_mutex_unlock (g_messages_lock);
+
+ return handler_id;
+}
+
+GLogFunc
+g_log_set_default_handler (GLogFunc log_func,
+ gpointer user_data)
+{
+ GLogFunc old_log_func;
+
+ g_mutex_lock (g_messages_lock);
+ old_log_func = default_log_func;
+ default_log_func = log_func;
+ default_log_data = user_data;
+ g_mutex_unlock (g_messages_lock);
+
+ return old_log_func;
+}
+
+void
+g_log_remove_handler (const gchar *log_domain,
+ guint handler_id)
+{
+ register GLogDomain *domain;
+
+ g_return_if_fail (handler_id > 0);
+
+ if (!log_domain)
+ log_domain = "";
+
+ g_mutex_lock (g_messages_lock);
+ domain = g_log_find_domain_L (log_domain);
+ if (domain)
+ {
+ GLogHandler *work, *last;
+
+ last = NULL;
+ work = domain->handlers;
+ while (work)
+ {
+ if (work->id == handler_id)
+ {
+ if (last)
+ last->next = work->next;
+ else
+ domain->handlers = work->next;
+ g_log_domain_check_free_L (domain);
+ g_mutex_unlock (g_messages_lock);
+ g_free (work);
+ return;
+ }
+ last = work;
+ work = last->next;
+ }
+ }
+ g_mutex_unlock (g_messages_lock);
+ g_warning ("%s: could not find handler with id `%d' for domain \"%s\"",
+ G_STRLOC, handler_id, log_domain);
+}
+
+void
+g_logv (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *format,
+ va_list args1)
+{
+ gboolean was_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
+ gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
+ gint i;
+
+ log_level &= G_LOG_LEVEL_MASK;
+ if (!log_level)
+ return;
+
+ for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
+ {
+ register GLogLevelFlags test_level;
+
+ test_level = 1 << i;
+ if (log_level & test_level)
+ {
+ guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
+ GLogDomain *domain;
+ GLogFunc log_func;
+ GLogLevelFlags domain_fatal_mask;
+ gpointer data = NULL;
+
+ if (was_fatal)
+ test_level |= G_LOG_FLAG_FATAL;
+ if (was_recursion)
+ test_level |= G_LOG_FLAG_RECURSION;
+
+ /* check recursion and lookup handler */
+ g_mutex_lock (g_messages_lock);
+ domain = g_log_find_domain_L (log_domain ? log_domain : "");
+ if (depth)
+ test_level |= G_LOG_FLAG_RECURSION;
+ depth++;
+ domain_fatal_mask = domain ? domain->fatal_mask : G_LOG_FATAL_MASK;
+ if ((domain_fatal_mask | g_log_always_fatal) & test_level)
+ test_level |= G_LOG_FLAG_FATAL;
+ if (test_level & G_LOG_FLAG_RECURSION)
+ log_func = _g_log_fallback_handler;
+ else
+ log_func = g_log_domain_get_handler_L (domain, test_level, &data);
+ domain = NULL;
+ g_mutex_unlock (g_messages_lock);
+
+ g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
+
+ /* had to defer debug initialization until we can keep track of recursion */
+ if (!(test_level & G_LOG_FLAG_RECURSION) && !_g_debug_initialized)
+ {
+ GLogLevelFlags orig_test_level = test_level;
+
+ _g_debug_init ();
+ if ((domain_fatal_mask | g_log_always_fatal) & test_level)
+ test_level |= G_LOG_FLAG_FATAL;
+ if (test_level != orig_test_level)
+ {
+ /* need a relookup, not nice, but not too bad either */
+ g_mutex_lock (g_messages_lock);
+ domain = g_log_find_domain_L (log_domain ? log_domain : "");
+ log_func = g_log_domain_get_handler_L (domain, test_level, &data);
+ domain = NULL;
+ g_mutex_unlock (g_messages_lock);
+ }
+ }
+
+ if (test_level & G_LOG_FLAG_RECURSION)
+ {
+ /* we use a stack buffer of fixed size, since we're likely
+ * in an out-of-memory situation
+ */
+ gchar buffer[1025];
+ gint size;
+ size = _g_vsnprintf (buffer, 1024, format, args1);
+
+ log_func (log_domain, test_level, buffer, data);
+ }
+ else
+ {
+ gchar *msg = g_strdup_vprintf (format, args1);
+
+ log_func (log_domain, test_level, msg, data);
+
+ g_free (msg);
+ }
+
+ if (test_level & G_LOG_FLAG_FATAL)
+ {
+#ifdef G_OS_WIN32
+ gchar *locale_msg = g_locale_from_utf8 (fatal_msg_buf, -1, NULL, NULL, NULL);
+
+ MessageBox (NULL, locale_msg, NULL,
+ MB_ICONERROR|MB_SETFOREGROUND);
+ if (IsDebuggerPresent () && !(test_level & G_LOG_FLAG_RECURSION))
+ G_BREAKPOINT ();
+ else
+ abort ();
+#else
+#if defined (G_ENABLE_DEBUG) && defined (SIGTRAP)
+ if (!(test_level & G_LOG_FLAG_RECURSION))
+ G_BREAKPOINT ();
+ else
+ abort ();
+#else /* !G_ENABLE_DEBUG || !SIGTRAP */
+ abort ();
+#endif /* !G_ENABLE_DEBUG || !SIGTRAP */
+#endif /* !G_OS_WIN32 */
+ }
+
+ depth--;
+ g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
+ }
+ }
+}
+
+void
+g_log (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *format,
+ ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ g_logv (log_domain, log_level, format, args);
+ va_end (args);
+}
+
+void
+g_return_if_fail_warning (const char *log_domain,
+ const char *pretty_function,
+ const char *expression)
+{
+ /*
+ * Omit the prefix used by the PLT-reduction
+ * technique used in GTK+.
+ */
+ if (g_str_has_prefix (pretty_function, "IA__"))
+ pretty_function += 4;
+ g_log (log_domain,
+ G_LOG_LEVEL_CRITICAL,
+ "%s: assertion `%s' failed",
+ pretty_function,
+ expression);
+}
+
+void
+g_warn_message (const char *domain,
+ const char *file,
+ int line,
+ const char *func,
+ const char *warnexpr)
+{
+ char *s, lstr[32];
+ g_snprintf (lstr, 32, "%d", line);
+ if (warnexpr)
+ s = g_strconcat ("(", file, ":", lstr, "):",
+ func, func[0] ? ":" : "",
+ " runtime check failed: (", warnexpr, ")", NULL);
+ else
+ s = g_strconcat ("(", file, ":", lstr, "):",
+ func, func[0] ? ":" : "",
+ " ", "code should not be reached", NULL);
+ g_log (domain, G_LOG_LEVEL_WARNING, "%s", s);
+ g_free (s);
+}
+
+void
+g_assert_warning (const char *log_domain,
+ const char *file,
+ const int line,
+ const char *pretty_function,
+ const char *expression)
+{
+ /*
+ * Omit the prefix used by the PLT-reduction
+ * technique used in GTK+.
+ */
+ if (g_str_has_prefix (pretty_function, "IA__"))
+ pretty_function += 4;
+ g_log (log_domain,
+ G_LOG_LEVEL_ERROR,
+ expression
+ ? "file %s: line %d (%s): assertion failed: (%s)"
+ : "file %s: line %d (%s): should not be reached",
+ file,
+ line,
+ pretty_function,
+ expression);
+ abort ();
+}
+
+#define CHAR_IS_SAFE(wc) (!((wc < 0x20 && wc != '\t' && wc != '\n' && wc != '\r') || \
+ (wc == 0x7f) || \
+ (wc >= 0x80 && wc < 0xa0)))
+
+static gchar*
+strdup_convert (const gchar *string,
+ const gchar *charset)
+{
+ if (!g_utf8_validate (string, -1, NULL))
+ {
+ GString *gstring = g_string_new ("[Invalid UTF-8] ");
+ guchar *p;
+
+ for (p = (guchar *)string; *p; p++)
+ {
+ if (CHAR_IS_SAFE(*p) &&
+ !(*p == '\r' && *(p + 1) != '\n') &&
+ *p < 0x80)
+ g_string_append_c (gstring, *p);
+ else
+ g_string_append_printf (gstring, "\\x%02x", (guint)(guchar)*p);
+ }
+
+ return g_string_free (gstring, FALSE);
+ }
+ else
+ {
+ GError *err = NULL;
+
+ gchar *result = g_convert_with_fallback (string, -1, charset, "UTF-8", "?", NULL, NULL, &err);
+ if (result)
+ return result;
+ else
+ {
+ /* Not thread-safe, but doesn't matter if we print the warning twice
+ */
+ static gboolean warned = FALSE;
+ if (!warned)
+ {
+ warned = TRUE;
+ _g_fprintf (stderr, "GLib: Cannot convert message: %s\n", err->message);
+ }
+ g_error_free (err);
+
+ return g_strdup (string);
+ }
+ }
+}
+
+/* For a radix of 8 we need at most 3 output bytes for 1 input
+ * byte. Additionally we might need up to 2 output bytes for the
+ * readix prefix and 1 byte for the trailing NULL.
+ */
+#define FORMAT_UNSIGNED_BUFSIZE ((GLIB_SIZEOF_LONG * 3) + 3)
+
+static void
+format_unsigned (gchar *buf,
+ gulong num,
+ guint radix)
+{
+ gulong tmp;
+ gchar c;
+ gint i, n;
+
+ /* we may not call _any_ GLib functions here (or macros like g_return_if_fail()) */
+
+ if (radix != 8 && radix != 10 && radix != 16)
+ {
+ *buf = '\000';
+ return;
+ }
+
+ if (!num)
+ {
+ *buf++ = '0';
+ *buf = '\000';
+ return;
+ }
+
+ if (radix == 16)
+ {
+ *buf++ = '0';
+ *buf++ = 'x';
+ }
+ else if (radix == 8)
+ {
+ *buf++ = '0';
+ }
+
+ n = 0;
+ tmp = num;
+ while (tmp)
+ {
+ tmp /= radix;
+ n++;
+ }
+
+ i = n;
+
+ /* Again we can't use g_assert; actually this check should _never_ fail. */
+ if (n > FORMAT_UNSIGNED_BUFSIZE - 3)
+ {
+ *buf = '\000';
+ return;
+ }
+
+ while (num)
+ {
+ i--;
+ c = (num % radix);
+ if (c < 10)
+ buf[i] = c + '0';
+ else
+ buf[i] = c + 'a' - 10;
+ num /= radix;
+ }
+
+ buf[n] = '\000';
+}
+
+/* string size big enough to hold level prefix */
+#define STRING_BUFFER_SIZE (FORMAT_UNSIGNED_BUFSIZE + 32)
+
+#define ALERT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)
+
+static int
+mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE],
+ GLogLevelFlags log_level)
+{
+ gboolean to_stdout = TRUE;
+
+ /* we may not call _any_ GLib functions here */
+
+ switch (log_level & G_LOG_LEVEL_MASK)
+ {
+ case G_LOG_LEVEL_ERROR:
+ strcpy (level_prefix, "ERROR");
+ to_stdout = FALSE;
+ break;
+ case G_LOG_LEVEL_CRITICAL:
+ strcpy (level_prefix, "CRITICAL");
+ to_stdout = FALSE;
+ break;
+ case G_LOG_LEVEL_WARNING:
+ strcpy (level_prefix, "WARNING");
+ to_stdout = FALSE;
+ break;
+ case G_LOG_LEVEL_MESSAGE:
+ strcpy (level_prefix, "Message");
+ to_stdout = FALSE;
+ break;
+ case G_LOG_LEVEL_INFO:
+ strcpy (level_prefix, "INFO");
+ break;
+ case G_LOG_LEVEL_DEBUG:
+ strcpy (level_prefix, "DEBUG");
+ break;
+ default:
+ if (log_level)
+ {
+ strcpy (level_prefix, "LOG-");
+ format_unsigned (level_prefix + 4, log_level & G_LOG_LEVEL_MASK, 16);
+ }
+ else
+ strcpy (level_prefix, "LOG");
+ break;
+ }
+ if (log_level & G_LOG_FLAG_RECURSION)
+ strcat (level_prefix, " (recursed)");
+ if (log_level & ALERT_LEVELS)
+ strcat (level_prefix, " **");
+
+#ifdef G_OS_WIN32
+ win32_keep_fatal_message = (log_level & G_LOG_FLAG_FATAL) != 0;
+#endif
+ return to_stdout ? 1 : 2;
+}
+
+void
+_g_log_fallback_handler (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer unused_data)
+{
+ gchar level_prefix[STRING_BUFFER_SIZE];
+#ifndef G_OS_WIN32
+ gchar pid_string[FORMAT_UNSIGNED_BUFSIZE];
+#endif
+ gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
+ int fd;
+
+ /* we can not call _any_ GLib functions in this fallback handler,
+ * which is why we skip UTF-8 conversion, etc.
+ * since we either recursed or ran out of memory, we're in a pretty
+ * pathologic situation anyways, what we can do is giving the
+ * the process ID unconditionally however.
+ */
+
+ fd = mklevel_prefix (level_prefix, log_level);
+ if (!message)
+ message = "(NULL) message";
+
+#ifndef G_OS_WIN32
+ format_unsigned (pid_string, getpid (), 10);
+#endif
+
+ if (log_domain)
+ write_string (fd, "\n");
+ else
+ write_string (fd, "\n** ");
+
+#ifndef G_OS_WIN32
+ write_string (fd, "(process:");
+ write_string (fd, pid_string);
+ write_string (fd, "): ");
+#endif
+
+ if (log_domain)
+ {
+ write_string (fd, log_domain);
+ write_string (fd, "-");
+ }
+ write_string (fd, level_prefix);
+ write_string (fd, ": ");
+ write_string (fd, message);
+ if (is_fatal)
+ write_string (fd, "\naborting...\n");
+ else
+ write_string (fd, "\n");
+}
+
+static void
+escape_string (GString *string)
+{
+ const char *p = string->str;
+ gunichar wc;
+
+ while (p < string->str + string->len)
+ {
+ gboolean safe;
+
+ wc = g_utf8_get_char_validated (p, -1);
+ if (wc == (gunichar)-1 || wc == (gunichar)-2)
+ {
+ gchar *tmp;
+ guint pos;
+
+ pos = p - string->str;
+
+ /* Emit invalid UTF-8 as hex escapes
+ */
+ tmp = g_strdup_printf ("\\x%02x", (guint)(guchar)*p);
+ g_string_erase (string, pos, 1);
+ g_string_insert (string, pos, tmp);
+
+ p = string->str + (pos + 4); /* Skip over escape sequence */
+
+ g_free (tmp);
+ continue;
+ }
+ if (wc == '\r')
+ {
+ safe = *(p + 1) == '\n';
+ }
+ else
+ {
+ safe = CHAR_IS_SAFE (wc);
+ }
+
+ if (!safe)
+ {
+ gchar *tmp;
+ guint pos;
+
+ pos = p - string->str;
+
+ /* Largest char we escape is 0x0a, so we don't have to worry
+ * about 8-digit \Uxxxxyyyy
+ */
+ tmp = g_strdup_printf ("\\u%04x", wc);
+ g_string_erase (string, pos, g_utf8_next_char (p) - p);
+ g_string_insert (string, pos, tmp);
+ g_free (tmp);
+
+ p = string->str + (pos + 6); /* Skip over escape sequence */
+ }
+ else
+ p = g_utf8_next_char (p);
+ }
+}
+
+void
+g_log_default_handler (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer unused_data)
+{
+ gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
+ gchar level_prefix[STRING_BUFFER_SIZE], *string;
+ GString *gstring;
+ int fd;
+
+ /* we can be called externally with recursion for whatever reason */
+ if (log_level & G_LOG_FLAG_RECURSION)
+ {
+ _g_log_fallback_handler (log_domain, log_level, message, unused_data);
+ return;
+ }
+
+ g_messages_prefixed_init ();
+
+ fd = mklevel_prefix (level_prefix, log_level);
+
+ gstring = g_string_new (NULL);
+ if (log_level & ALERT_LEVELS)
+ g_string_append (gstring, "\n");
+ if (!log_domain)
+ g_string_append (gstring, "** ");
+
+ if ((g_log_msg_prefix & log_level) == log_level)
+ {
+ const gchar *prg_name = g_get_prgname ();
+
+ if (!prg_name)
+ g_string_append_printf (gstring, "(process:%lu): ", (gulong)getpid ());
+ else
+ g_string_append_printf (gstring, "(%s:%lu): ", prg_name, (gulong)getpid ());
+ }
+
+ if (log_domain)
+ {
+ g_string_append (gstring, log_domain);
+ g_string_append_c (gstring, '-');
+ }
+ g_string_append (gstring, level_prefix);
+
+ g_string_append (gstring, ": ");
+ if (!message)
+ g_string_append (gstring, "(NULL) message");
+ else
+ {
+ GString *msg;
+ const gchar *charset;
+
+ msg = g_string_new (message);
+ escape_string (msg);
+
+ if (g_get_charset (&charset))
+ g_string_append (gstring, msg->str); /* charset is UTF-8 already */
+ else
+ {
+ string = strdup_convert (msg->str, charset);
+ g_string_append (gstring, string);
+ g_free (string);
+ }
+
+ g_string_free (msg, TRUE);
+ }
+ if (is_fatal)
+ g_string_append (gstring, "\naborting...\n");
+ else
+ g_string_append (gstring, "\n");
+
+ string = g_string_free (gstring, FALSE);
+
+ write_string (fd, string);
+ g_free (string);
+}
+
+GPrintFunc
+g_set_print_handler (GPrintFunc func)
+{
+ GPrintFunc old_print_func;
+
+ g_mutex_lock (g_messages_lock);
+ old_print_func = glib_print_func;
+ glib_print_func = func;
+ g_mutex_unlock (g_messages_lock);
+
+ return old_print_func;
+}
+
+void
+g_print (const gchar *format,
+ ...)
+{
+ va_list args;
+ gchar *string;
+ GPrintFunc local_glib_print_func;
+
+ g_return_if_fail (format != NULL);
+
+ va_start (args, format);
+ string = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ g_mutex_lock (g_messages_lock);
+ local_glib_print_func = glib_print_func;
+ g_mutex_unlock (g_messages_lock);
+
+ if (local_glib_print_func)
+ local_glib_print_func (string);
+ else
+ {
+ const gchar *charset;
+
+ if (g_get_charset (&charset))
+ fputs (string, stdout); /* charset is UTF-8 already */
+ else
+ {
+ gchar *lstring = strdup_convert (string, charset);
+
+ fputs (lstring, stdout);
+ g_free (lstring);
+ }
+ fflush (stdout);
+ }
+ g_free (string);
+}
+
+GPrintFunc
+g_set_printerr_handler (GPrintFunc func)
+{
+ GPrintFunc old_printerr_func;
+
+ g_mutex_lock (g_messages_lock);
+ old_printerr_func = glib_printerr_func;
+ glib_printerr_func = func;
+ g_mutex_unlock (g_messages_lock);
+
+ return old_printerr_func;
+}
+
+void
+g_printerr (const gchar *format,
+ ...)
+{
+ va_list args;
+ gchar *string;
+ GPrintFunc local_glib_printerr_func;
+
+ g_return_if_fail (format != NULL);
+
+ va_start (args, format);
+ string = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ g_mutex_lock (g_messages_lock);
+ local_glib_printerr_func = glib_printerr_func;
+ g_mutex_unlock (g_messages_lock);
+
+ if (local_glib_printerr_func)
+ local_glib_printerr_func (string);
+ else
+ {
+ const gchar *charset;
+
+ if (g_get_charset (&charset))
+ fputs (string, stderr); /* charset is UTF-8 already */
+ else
+ {
+ gchar *lstring = strdup_convert (string, charset);
+
+ fputs (lstring, stderr);
+ g_free (lstring);
+ }
+ fflush (stderr);
+ }
+ g_free (string);
+}
+
+#endif /* NOT_NEEDED_FOR_NAVIT */
+gsize
+g_printf_string_upper_bound (const gchar *format,
+ va_list args)
+{
+#ifdef HAVE_API_WIN32_BASE
+ gchar c[16384];
+ return _g_vsnprintf (c, 16384, format, args) + 1;
+#else
+ gchar c;
+ return _g_vsnprintf (&c, 1, format, args) + 1;
+#endif
+}
+
+#if NOT_NEEDED_FOR_NAVIT
+void
+_g_messages_thread_init_nomessage (void)
+{
+ g_messages_lock = g_mutex_new ();
+ g_log_depth = g_private_new (NULL);
+ g_messages_prefixed_init ();
+ _g_debug_init ();
+}
+
+gboolean _g_debug_initialized = FALSE;
+guint _g_debug_flags = 0;
+
+void
+_g_debug_init (void)
+{
+ const gchar *val;
+
+ _g_debug_initialized = TRUE;
+
+ val = g_getenv ("G_DEBUG");
+ if (val != NULL)
+ {
+ const GDebugKey keys[] = {
+ {"fatal_warnings", G_DEBUG_FATAL_WARNINGS},
+ {"fatal_criticals", G_DEBUG_FATAL_CRITICALS}
+ };
+
+ _g_debug_flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
+ }
+
+ if (_g_debug_flags & G_DEBUG_FATAL_WARNINGS)
+ {
+ GLogLevelFlags fatal_mask;
+
+ fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+ fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
+ g_log_set_always_fatal (fatal_mask);
+ }
+
+ if (_g_debug_flags & G_DEBUG_FATAL_CRITICALS)
+ {
+ GLogLevelFlags fatal_mask;
+
+ fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+ fatal_mask |= G_LOG_LEVEL_CRITICAL;
+ g_log_set_always_fatal (fatal_mask);
+ }
+}
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+#define __G_MESSAGES_C__
+#include "galiasdef.c"
diff --git a/support/glib/gmessages.h b/support/glib/gmessages.h
new file mode 100644
index 00000000..af5a826f
--- /dev/null
+++ b/support/glib/gmessages.h
@@ -0,0 +1,341 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MESSAGES_H__
+#define __G_MESSAGES_H__
+
+#include <stdarg.h>
+#include <glib/gtypes.h>
+#include <glib/gmacros.h>
+
+/* Suppress warnings when GCC is in -pedantic mode and not -std=c99
+ */
+#if (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
+#pragma GCC system_header
+#endif
+
+G_BEGIN_DECLS
+
+/* calculate a string size, guaranteed to fit format + args.
+ */
+gsize g_printf_string_upper_bound (const gchar* format,
+ va_list args);
+
+/* Log level shift offset for user defined
+ * log levels (0-7 are used by GLib).
+ */
+#define G_LOG_LEVEL_USER_SHIFT (8)
+
+/* Glib log levels and flags.
+ */
+typedef enum
+{
+ /* log flags */
+ G_LOG_FLAG_RECURSION = 1 << 0,
+ G_LOG_FLAG_FATAL = 1 << 1,
+
+ /* GLib log levels */
+ G_LOG_LEVEL_ERROR = 1 << 2, /* always fatal */
+ G_LOG_LEVEL_CRITICAL = 1 << 3,
+ G_LOG_LEVEL_WARNING = 1 << 4,
+ G_LOG_LEVEL_MESSAGE = 1 << 5,
+ G_LOG_LEVEL_INFO = 1 << 6,
+ G_LOG_LEVEL_DEBUG = 1 << 7,
+
+ G_LOG_LEVEL_MASK = ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL)
+} GLogLevelFlags;
+
+/* GLib log levels that are considered fatal by default */
+#define G_LOG_FATAL_MASK (G_LOG_FLAG_RECURSION | G_LOG_LEVEL_ERROR)
+
+typedef void (*GLogFunc) (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data);
+
+/* Logging mechanism
+ */
+guint g_log_set_handler (const gchar *log_domain,
+ GLogLevelFlags log_levels,
+ GLogFunc log_func,
+ gpointer user_data);
+void g_log_remove_handler (const gchar *log_domain,
+ guint handler_id);
+void g_log_default_handler (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer unused_data);
+GLogFunc g_log_set_default_handler (GLogFunc log_func,
+ gpointer user_data);
+void g_log (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (3, 4);
+void g_logv (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *format,
+ va_list args);
+GLogLevelFlags g_log_set_fatal_mask (const gchar *log_domain,
+ GLogLevelFlags fatal_mask);
+GLogLevelFlags g_log_set_always_fatal (GLogLevelFlags fatal_mask);
+
+/* internal */
+G_GNUC_INTERNAL void _g_log_fallback_handler (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer unused_data);
+
+/* Internal functions, used to implement the following macros */
+void g_return_if_fail_warning (const char *log_domain,
+ const char *pretty_function,
+ const char *expression);
+void g_warn_message (const char *domain,
+ const char *file,
+ int line,
+ const char *func,
+ const char *warnexpr);
+#ifndef G_DISABLE_DEPRECATED
+void g_assert_warning (const char *log_domain,
+ const char *file,
+ const int line,
+ const char *pretty_function,
+ const char *expression) G_GNUC_NORETURN;
+#endif /* !G_DISABLE_DEPRECATED */
+
+
+#ifndef G_LOG_DOMAIN
+#define G_LOG_DOMAIN ((gchar*) 0)
+#endif /* G_LOG_DOMAIN */
+#ifdef G_HAVE_ISO_VARARGS
+/* for(;;); so that GCC knows that control doesn't go past g_error() */
+#define g_error(...) G_STMT_START { \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_ERROR, \
+ __VA_ARGS__); \
+ for (;;); \
+ } G_STMT_END
+
+#define g_message(...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_MESSAGE, \
+ __VA_ARGS__)
+#define g_critical(...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ __VA_ARGS__)
+#define g_warning(...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_WARNING, \
+ __VA_ARGS__)
+#define g_debug(...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_DEBUG, \
+ __VA_ARGS__)
+#elif defined(G_HAVE_GNUC_VARARGS)
+#define g_error(format...) G_STMT_START { \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_ERROR, \
+ format); \
+ for (;;); \
+ } G_STMT_END
+
+#define g_message(format...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_MESSAGE, \
+ format)
+#define g_critical(format...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ format)
+#define g_warning(format...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_WARNING, \
+ format)
+#define g_debug(format...) g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_DEBUG, \
+ format)
+#else /* no varargs macros */
+static void
+g_error (const gchar *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, format, args);
+ va_end (args);
+
+ for(;;);
+}
+static void
+g_message (const gchar *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, args);
+ va_end (args);
+}
+static void
+g_critical (const gchar *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, format, args);
+ va_end (args);
+}
+static void
+g_warning (const gchar *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, format, args);
+ va_end (args);
+}
+static void
+g_debug (const gchar *format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args);
+ va_end (args);
+}
+#endif /* !__GNUC__ */
+
+typedef void (*GPrintFunc) (const gchar *string);
+void g_print (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2);
+GPrintFunc g_set_print_handler (GPrintFunc func);
+void g_printerr (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2);
+GPrintFunc g_set_printerr_handler (GPrintFunc func);
+
+
+/* Provide macros for graceful error handling.
+ * The "return" macros will return from the current function.
+ * Two different definitions are given for the macros in
+ * order to support gcc's __PRETTY_FUNCTION__ capability.
+ */
+
+#define g_warn_if_reached() do { g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, NULL); } while (0)
+#define g_warn_if_fail(expr) do { if G_LIKELY (expr) ; else \
+ g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, #expr); } while (0)
+
+#ifdef G_DISABLE_CHECKS
+
+#define g_return_if_fail(expr) G_STMT_START{ (void)0; }G_STMT_END
+#define g_return_val_if_fail(expr,val) G_STMT_START{ (void)0; }G_STMT_END
+#define g_return_if_reached() G_STMT_START{ return; }G_STMT_END
+#define g_return_val_if_reached(val) G_STMT_START{ return (val); }G_STMT_END
+
+#else /* !G_DISABLE_CHECKS */
+
+#ifdef __GNUC__
+
+#define g_return_if_fail(expr) G_STMT_START{ \
+ if G_LIKELY(expr) { } else \
+ { \
+ g_return_if_fail_warning (G_LOG_DOMAIN, \
+ __PRETTY_FUNCTION__, \
+ #expr); \
+ return; \
+ }; }G_STMT_END
+
+#define g_return_val_if_fail(expr,val) G_STMT_START{ \
+ if G_LIKELY(expr) { } else \
+ { \
+ g_return_if_fail_warning (G_LOG_DOMAIN, \
+ __PRETTY_FUNCTION__, \
+ #expr); \
+ return (val); \
+ }; }G_STMT_END
+
+#define g_return_if_reached() G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d (%s): should not be reached", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__); \
+ return; }G_STMT_END
+
+#define g_return_val_if_reached(val) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d (%s): should not be reached", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__); \
+ return (val); }G_STMT_END
+
+#else /* !__GNUC__ */
+
+#define g_return_if_fail(expr) G_STMT_START{ \
+ if (expr) { } else \
+ { \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d: assertion `%s' failed", \
+ __FILE__, \
+ __LINE__, \
+ #expr); \
+ return; \
+ }; }G_STMT_END
+
+#define g_return_val_if_fail(expr, val) G_STMT_START{ \
+ if (expr) { } else \
+ { \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d: assertion `%s' failed", \
+ __FILE__, \
+ __LINE__, \
+ #expr); \
+ return (val); \
+ }; }G_STMT_END
+
+#define g_return_if_reached() G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d: should not be reached", \
+ __FILE__, \
+ __LINE__); \
+ return; }G_STMT_END
+
+#define g_return_val_if_reached(val) G_STMT_START{ \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d: should not be reached", \
+ __FILE__, \
+ __LINE__); \
+ return (val); }G_STMT_END
+
+#endif /* !__GNUC__ */
+
+#endif /* !G_DISABLE_CHECKS */
+
+G_END_DECLS
+
+#endif /* __G_MESSAGES_H__ */
diff --git a/support/glib/gprimes.c b/support/glib/gprimes.c
new file mode 100644
index 00000000..7beca710
--- /dev/null
+++ b/support/glib/gprimes.c
@@ -0,0 +1,90 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe
+ */
+
+#include "config.h"
+
+#include "glib.h"
+#include "galias.h"
+
+
+static const guint g_primes[] =
+{
+ 11,
+ 19,
+ 37,
+ 73,
+ 109,
+ 163,
+ 251,
+ 367,
+ 557,
+ 823,
+ 1237,
+ 1861,
+ 2777,
+ 4177,
+ 6247,
+ 9371,
+ 14057,
+ 21089,
+ 31627,
+ 47431,
+ 71143,
+ 106721,
+ 160073,
+ 240101,
+ 360163,
+ 540217,
+ 810343,
+ 1215497,
+ 1823231,
+ 2734867,
+ 4102283,
+ 6153409,
+ 9230113,
+ 13845163,
+};
+
+static const guint g_nprimes = sizeof (g_primes) / sizeof (g_primes[0]);
+
+guint
+g_spaced_primes_closest (guint num)
+{
+ gint i;
+
+ for (i = 0; i < g_nprimes; i++)
+ if (g_primes[i] > num)
+ return g_primes[i];
+
+ return g_primes[g_nprimes - 1];
+}
+
+#define __G_PRIMES_C__
+#include "galiasdef.c"
diff --git a/support/glib/gprintf.c b/support/glib/gprintf.c
new file mode 100644
index 00000000..6cbb214d
--- /dev/null
+++ b/support/glib/gprintf.c
@@ -0,0 +1,342 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997, 2002 Peter Mattis, Red Hat, Inc.
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#define _GNU_SOURCE /* For vasprintf */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "glib.h"
+#include "gprintf.h"
+#include "gprintfint.h"
+
+#include "galias.h"
+
+/**
+ * g_printf:
+ * @format: a standard printf() format string, but notice
+ * <link linkend="string-precision">string precision pitfalls</link>.
+ * @Varargs: the arguments to insert in the output.
+ *
+ * An implementation of the standard printf() function which supports
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_printf (gchar const *format,
+ ...)
+{
+ va_list args;
+ gint retval;
+
+ va_start (args, format);
+ retval = g_vprintf (format, args);
+ va_end (args);
+
+ return retval;
+}
+
+/**
+ * g_fprintf:
+ * @file: the stream to write to.
+ * @format: a standard printf() format string, but notice
+ * <link linkend="string-precision">string precision pitfalls</link>.
+ * @Varargs: the arguments to insert in the output.
+ *
+ * An implementation of the standard fprintf() function which supports
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_fprintf (FILE *file,
+ gchar const *format,
+ ...)
+{
+ va_list args;
+ gint retval;
+
+ va_start (args, format);
+ retval = g_vfprintf (file, format, args);
+ va_end (args);
+
+ return retval;
+}
+
+/**
+ * g_sprintf:
+ * @string: A pointer to a memory buffer to contain the resulting string. It
+ * is up to the caller to ensure that the allocated buffer is large
+ * enough to hold the formatted result
+ * @format: a standard printf() format string, but notice
+ * <link linkend="string-precision">string precision pitfalls</link>.
+ * @Varargs: the arguments to insert in the output.
+ *
+ * An implementation of the standard sprintf() function which supports
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_sprintf (gchar *string,
+ gchar const *format,
+ ...)
+{
+ va_list args;
+ gint retval;
+
+ va_start (args, format);
+ retval = g_vsprintf (string, format, args);
+ va_end (args);
+
+ return retval;
+}
+
+/**
+ * g_snprintf:
+ * @string: the buffer to hold the output.
+ * @n: the maximum number of bytes to produce (including the
+ * terminating nul character).
+ * @format: a standard printf() format string, but notice
+ * <link linkend="string-precision">string precision pitfalls</link>.
+ * @Varargs: the arguments to insert in the output.
+ *
+ * A safer form of the standard sprintf() function. The output is guaranteed
+ * to not exceed @n characters (including the terminating nul character), so
+ * it is easy to ensure that a buffer overflow cannot occur.
+ *
+ * See also g_strdup_printf().
+ *
+ * In versions of GLib prior to 1.2.3, this function may return -1 if the
+ * output was truncated, and the truncated string may not be nul-terminated.
+ * In versions prior to 1.3.12, this function returns the length of the output
+ * string.
+ *
+ * The return value of g_snprintf() conforms to the snprintf()
+ * function as standardized in ISO C99. Note that this is different from
+ * traditional snprintf(), which returns the length of the output string.
+ *
+ * The format string may contain positional parameters, as specified in
+ * the Single Unix Specification.
+ *
+ * Returns: the number of bytes which would be produced if the buffer
+ * was large enough.
+ **/
+gint
+g_snprintf (gchar *string,
+ gulong n,
+ gchar const *format,
+ ...)
+{
+ va_list args;
+ gint retval;
+
+ va_start (args, format);
+ retval = g_vsnprintf (string, n, format, args);
+ va_end (args);
+
+ return retval;
+}
+
+/**
+ * g_vprintf:
+ * @format: a standard printf() format string, but notice
+ * <link linkend="string-precision">string precision pitfalls</link>.
+ * @args: the list of arguments to insert in the output.
+ *
+ * An implementation of the standard vprintf() function which supports
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_vprintf (gchar const *format,
+ va_list args)
+{
+ g_return_val_if_fail (format != NULL, -1);
+
+ return _g_vprintf (format, args);
+}
+
+/**
+ * g_vfprintf:
+ * @file: the stream to write to.
+ * @format: a standard printf() format string, but notice
+ * <link linkend="string-precision">string precision pitfalls</link>.
+ * @args: the list of arguments to insert in the output.
+ *
+ * An implementation of the standard fprintf() function which supports
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_vfprintf (FILE *file,
+ gchar const *format,
+ va_list args)
+{
+ g_return_val_if_fail (format != NULL, -1);
+
+ return _g_vfprintf (file, format, args);
+}
+
+/**
+ * g_vsprintf:
+ * @string: the buffer to hold the output.
+ * @format: a standard printf() format string, but notice
+ * <link linkend="string-precision">string precision pitfalls</link>.
+ * @args: the list of arguments to insert in the output.
+ *
+ * An implementation of the standard vsprintf() function which supports
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_vsprintf (gchar *string,
+ gchar const *format,
+ va_list args)
+{
+ g_return_val_if_fail (string != NULL, -1);
+ g_return_val_if_fail (format != NULL, -1);
+
+ return _g_vsprintf (string, format, args);
+}
+
+/**
+ * g_vsnprintf:
+ * @string: the buffer to hold the output.
+ * @n: the maximum number of bytes to produce (including the
+ * terminating nul character).
+ * @format: a standard printf() format string, but notice
+ * <link linkend="string-precision">string precision pitfalls</link>.
+ * @args: the list of arguments to insert in the output.
+ *
+ * A safer form of the standard vsprintf() function. The output is guaranteed
+ * to not exceed @n characters (including the terminating nul character), so
+ * it is easy to ensure that a buffer overflow cannot occur.
+ *
+ * See also g_strdup_vprintf().
+ *
+ * In versions of GLib prior to 1.2.3, this function may return -1 if the
+ * output was truncated, and the truncated string may not be nul-terminated.
+ * In versions prior to 1.3.12, this function returns the length of the output
+ * string.
+ *
+ * The return value of g_vsnprintf() conforms to the vsnprintf() function
+ * as standardized in ISO C99. Note that this is different from traditional
+ * vsnprintf(), which returns the length of the output string.
+ *
+ * The format string may contain positional parameters, as specified in
+ * the Single Unix Specification.
+ *
+ * Returns: the number of bytes which would be produced if the buffer
+ * was large enough.
+ */
+gint
+g_vsnprintf (gchar *string,
+ gulong n,
+ gchar const *format,
+ va_list args)
+{
+ g_return_val_if_fail (n == 0 || string != NULL, -1);
+ g_return_val_if_fail (format != NULL, -1);
+
+ return _g_vsnprintf (string, n, format, args);
+}
+
+/**
+ * g_vasprintf:
+ * @string: the return location for the newly-allocated string.
+ * @format: a standard printf() format string, but notice
+ * <link linkend="string-precision">string precision pitfalls</link>.
+ * @args: the list of arguments to insert in the output.
+ *
+ * An implementation of the GNU vasprintf() function which supports
+ * positional parameters, as specified in the Single Unix Specification.
+ * This function is similar to g_vsprintf(), except that it allocates a
+ * string to hold the output, instead of putting the output in a buffer
+ * you allocate in advance.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.4
+ **/
+gint
+g_vasprintf (gchar **string,
+ gchar const *format,
+ va_list args)
+{
+ gint len;
+ g_return_val_if_fail (string != NULL, -1);
+
+#if !defined(HAVE_GOOD_PRINTF)
+
+ len = _g_gnulib_vasprintf (string, format, args);
+ if (len < 0)
+ *string = NULL;
+
+#elif defined (HAVE_VASPRINTF)
+
+ len = vasprintf (string, format, args);
+ if (len < 0)
+ *string = NULL;
+ else if (!g_mem_is_system_malloc ())
+ {
+ /* vasprintf returns malloc-allocated memory */
+ gchar *string1 = g_strndup (*string, len);
+ free (*string);
+ *string = string1;
+ }
+
+#else
+
+ {
+ va_list args2;
+
+ G_VA_COPY (args2, args);
+
+ *string = g_new (gchar, g_printf_string_upper_bound (format, args));
+
+ len = _g_vsprintf (*string, format, args2);
+ va_end (args2);
+ }
+#endif
+
+ return len;
+}
+
+#define __G_PRINTF_C__
+#include "galiasdef.c"
diff --git a/support/glib/gprintf.h b/support/glib/gprintf.h
new file mode 100644
index 00000000..d96870fb
--- /dev/null
+++ b/support/glib/gprintf.h
@@ -0,0 +1,52 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997, 2002 Peter Mattis, Red Hat, Inc.
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_PRINTF_H__
+#define __G_PRINTF_H__
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+G_BEGIN_DECLS
+
+gint g_printf (gchar const *format,
+ ...) G_GNUC_PRINTF (1, 2);
+gint g_fprintf (FILE *file,
+ gchar const *format,
+ ...) G_GNUC_PRINTF (2, 3);
+gint g_sprintf (gchar *string,
+ gchar const *format,
+ ...) G_GNUC_PRINTF (2, 3);
+
+gint g_vprintf (gchar const *format,
+ va_list args);
+gint g_vfprintf (FILE *file,
+ gchar const *format,
+ va_list args);
+gint g_vsprintf (gchar *string,
+ gchar const *format,
+ va_list args);
+gint g_vasprintf (gchar **string,
+ gchar const *format,
+ va_list args);
+
+G_END_DECLS
+
+#endif /* __G_PRINTF_H__ */
diff --git a/support/glib/gprintfint.h b/support/glib/gprintfint.h
new file mode 100644
index 00000000..0c975a1e
--- /dev/null
+++ b/support/glib/gprintfint.h
@@ -0,0 +1,59 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 2002. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __G_PRINTFINT_H__
+#define __G_PRINTFINT_H__
+
+#ifdef HAVE_GOOD_PRINTF
+
+#define _g_printf printf
+#define _g_fprintf fprintf
+#define _g_sprintf sprintf
+#define _g_snprintf snprintf
+
+#define _g_vprintf vprintf
+#define _g_vfprintf vfprintf
+#define _g_vsprintf vsprintf
+#define _g_vsnprintf vsnprintf
+
+#else
+
+#include "gnulib/printf.h"
+
+#define _g_printf _g_gnulib_printf
+#define _g_fprintf _g_gnulib_fprintf
+#define _g_sprintf _g_gnulib_sprintf
+#define _g_snprintf _g_gnulib_snprintf
+
+#define _g_vprintf _g_gnulib_vprintf
+#define _g_vfprintf _g_gnulib_vfprintf
+#define _g_vsprintf _g_gnulib_vsprintf
+#define _g_vsnprintf _g_gnulib_vsnprintf
+
+#endif
+
+#endif /* __G_PRINTF_H__ */
+
diff --git a/support/glib/gquark.h b/support/glib/gquark.h
new file mode 100644
index 00000000..a0cbe2fd
--- /dev/null
+++ b/support/glib/gquark.h
@@ -0,0 +1,52 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_QUARK_H__
+#define __G_QUARK_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef guint32 GQuark;
+
+/* Quarks (string<->id association)
+ */
+GQuark g_quark_try_string (const gchar *string);
+GQuark g_quark_from_static_string (const gchar *string);
+GQuark g_quark_from_string (const gchar *string);
+G_CONST_RETURN gchar* g_quark_to_string (GQuark quark) G_GNUC_CONST;
+
+G_CONST_RETURN gchar* g_intern_string (const gchar *string);
+G_CONST_RETURN gchar* g_intern_static_string (const gchar *string);
+
+G_END_DECLS
+
+#endif /* __G_QUARK_H__ */
diff --git a/support/glib/gslice.c b/support/glib/gslice.c
new file mode 100644
index 00000000..d61420d2
--- /dev/null
+++ b/support/glib/gslice.c
@@ -0,0 +1,1493 @@
+/* GLIB sliced memory - fast concurrent memory chunk allocator
+ * Copyright (C) 2005 Tim Janik
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/* MT safe */
+
+#include "config.h"
+
+#if defined HAVE_POSIX_MEMALIGN && defined POSIX_MEMALIGN_WITH_COMPLIANT_ALLOCS
+# define HAVE_COMPLIANT_POSIX_MEMALIGN 1
+#endif
+
+#ifdef HAVE_COMPLIANT_POSIX_MEMALIGN
+#define _XOPEN_SOURCE 600 /* posix_memalign() */
+#endif
+#include <stdlib.h> /* posix_memalign() */
+#include <string.h>
+#include <errno.h>
+#include "gmem.h" /* gslice.h */
+#include "gthreadprivate.h"
+#include "glib.h"
+#include "galias.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* sysconf() */
+#endif
+#ifdef G_OS_WIN32
+#include <windows.h>
+#include <process.h>
+#endif
+
+#include <stdio.h> /* fputs/fprintf */
+
+
+/* the GSlice allocator is split up into 4 layers, roughly modelled after the slab
+ * allocator and magazine extensions as outlined in:
+ * + [Bonwick94] Jeff Bonwick, The slab allocator: An object-caching kernel
+ * memory allocator. USENIX 1994, http://citeseer.ist.psu.edu/bonwick94slab.html
+ * + [Bonwick01] Bonwick and Jonathan Adams, Magazines and vmem: Extending the
+ * slab allocator to many cpu's and arbitrary resources.
+ * USENIX 2001, http://citeseer.ist.psu.edu/bonwick01magazines.html
+ * the layers are:
+ * - the thread magazines. for each (aligned) chunk size, a magazine (a list)
+ * of recently freed and soon to be allocated chunks is maintained per thread.
+ * this way, most alloc/free requests can be quickly satisfied from per-thread
+ * free lists which only require one g_private_get() call to retrive the
+ * thread handle.
+ * - the magazine cache. allocating and freeing chunks to/from threads only
+ * occours at magazine sizes from a global depot of magazines. the depot
+ * maintaines a 15 second working set of allocated magazines, so full
+ * magazines are not allocated and released too often.
+ * the chunk size dependent magazine sizes automatically adapt (within limits,
+ * see [3]) to lock contention to properly scale performance across a variety
+ * of SMP systems.
+ * - the slab allocator. this allocator allocates slabs (blocks of memory) close
+ * to the system page size or multiples thereof which have to be page aligned.
+ * the blocks are divided into smaller chunks which are used to satisfy
+ * allocations from the upper layers. the space provided by the reminder of
+ * the chunk size division is used for cache colorization (random distribution
+ * of chunk addresses) to improve processor cache utilization. multiple slabs
+ * with the same chunk size are kept in a partially sorted ring to allow O(1)
+ * freeing and allocation of chunks (as long as the allocation of an entirely
+ * new slab can be avoided).
+ * - the page allocator. on most modern systems, posix_memalign(3) or
+ * memalign(3) should be available, so this is used to allocate blocks with
+ * system page size based alignments and sizes or multiples thereof.
+ * if no memalign variant is provided, valloc() is used instead and
+ * block sizes are limited to the system page size (no multiples thereof).
+ * as a fallback, on system without even valloc(), a malloc(3)-based page
+ * allocator with alloc-only behaviour is used.
+ *
+ * NOTES:
+ * [1] some systems memalign(3) implementations may rely on boundary tagging for
+ * the handed out memory chunks. to avoid excessive page-wise fragmentation,
+ * we reserve 2 * sizeof (void*) per block size for the systems memalign(3),
+ * specified in NATIVE_MALLOC_PADDING.
+ * [2] using the slab allocator alone already provides for a fast and efficient
+ * allocator, it doesn't properly scale beyond single-threaded uses though.
+ * also, the slab allocator implements eager free(3)-ing, i.e. does not
+ * provide any form of caching or working set maintenance. so if used alone,
+ * it's vulnerable to trashing for sequences of balanced (alloc, free) pairs
+ * at certain thresholds.
+ * [3] magazine sizes are bound by an implementation specific minimum size and
+ * a chunk size specific maximum to limit magazine storage sizes to roughly
+ * 16KB.
+ * [4] allocating ca. 8 chunks per block/page keeps a good balance between
+ * external and internal fragmentation (<= 12.5%). [Bonwick94]
+ */
+#if NOT_NEEDED_FOR_NAVIT
+
+/* --- macros and constants --- */
+#define LARGEALIGNMENT (256)
+#define P2ALIGNMENT (2 * sizeof (gsize)) /* fits 2 pointers (assumed to be 2 * GLIB_SIZEOF_SIZE_T below) */
+#define ALIGN(size, base) ((base) * (gsize) (((size) + (base) - 1) / (base)))
+#define NATIVE_MALLOC_PADDING P2ALIGNMENT /* per-page padding left for native malloc(3) see [1] */
+#define SLAB_INFO_SIZE P2ALIGN (sizeof (SlabInfo) + NATIVE_MALLOC_PADDING)
+#define MAX_MAGAZINE_SIZE (256) /* see [3] and allocator_get_magazine_threshold() for this */
+#define MIN_MAGAZINE_SIZE (4)
+#define MAX_STAMP_COUNTER (7) /* distributes the load of gettimeofday() */
+#define MAX_SLAB_CHUNK_SIZE(al) (((al)->max_page_size - SLAB_INFO_SIZE) / 8) /* we want at last 8 chunks per page, see [4] */
+#define MAX_SLAB_INDEX(al) (SLAB_INDEX (al, MAX_SLAB_CHUNK_SIZE (al)) + 1)
+#define SLAB_INDEX(al, asize) ((asize) / P2ALIGNMENT - 1) /* asize must be P2ALIGNMENT aligned */
+#define SLAB_CHUNK_SIZE(al, ix) (((ix) + 1) * P2ALIGNMENT)
+#define SLAB_BPAGE_SIZE(al,csz) (8 * (csz) + SLAB_INFO_SIZE)
+
+/* optimized version of ALIGN (size, P2ALIGNMENT) */
+#if GLIB_SIZEOF_SIZE_T * 2 == 8 /* P2ALIGNMENT */
+#define P2ALIGN(size) (((size) + 0x7) & ~(gsize) 0x7)
+#elif GLIB_SIZEOF_SIZE_T * 2 == 16 /* P2ALIGNMENT */
+#define P2ALIGN(size) (((size) + 0xf) & ~(gsize) 0xf)
+#else
+#define P2ALIGN(size) ALIGN (size, P2ALIGNMENT)
+#endif
+
+/* special helpers to avoid gmessage.c dependency */
+static void mem_error (const char *format, ...) G_GNUC_PRINTF (1,2);
+#define mem_assert(cond) do { if (G_LIKELY (cond)) ; else mem_error ("assertion failed: %s", #cond); } while (0)
+
+/* --- structures --- */
+typedef struct _ChunkLink ChunkLink;
+typedef struct _SlabInfo SlabInfo;
+typedef struct _CachedMagazine CachedMagazine;
+struct _ChunkLink {
+ ChunkLink *next;
+ ChunkLink *data;
+};
+struct _SlabInfo {
+ ChunkLink *chunks;
+ guint n_allocated;
+ SlabInfo *next, *prev;
+};
+typedef struct {
+ ChunkLink *chunks;
+ gsize count; /* approximative chunks list length */
+} Magazine;
+typedef struct {
+ Magazine *magazine1; /* array of MAX_SLAB_INDEX (allocator) */
+ Magazine *magazine2; /* array of MAX_SLAB_INDEX (allocator) */
+} ThreadMemory;
+typedef struct {
+ gboolean always_malloc;
+ gboolean bypass_magazines;
+ gboolean debug_blocks;
+ gsize working_set_msecs;
+ guint color_increment;
+} SliceConfig;
+typedef struct {
+ /* const after initialization */
+ gsize min_page_size, max_page_size;
+ SliceConfig config;
+ gsize max_slab_chunk_size_for_magazine_cache;
+ /* magazine cache */
+ GMutex *magazine_mutex;
+ ChunkLink **magazines; /* array of MAX_SLAB_INDEX (allocator) */
+ guint *contention_counters; /* array of MAX_SLAB_INDEX (allocator) */
+ gint mutex_counter;
+ guint stamp_counter;
+ guint last_stamp;
+ /* slab allocator */
+ GMutex *slab_mutex;
+ SlabInfo **slab_stack; /* array of MAX_SLAB_INDEX (allocator) */
+ guint color_accu;
+} Allocator;
+
+/* --- g-slice prototypes --- */
+static gpointer slab_allocator_alloc_chunk (gsize chunk_size);
+static void slab_allocator_free_chunk (gsize chunk_size,
+ gpointer mem);
+static void private_thread_memory_cleanup (gpointer data);
+static gpointer allocator_memalign (gsize alignment,
+ gsize memsize);
+static void allocator_memfree (gsize memsize,
+ gpointer mem);
+static inline void magazine_cache_update_stamp (void);
+static inline gsize allocator_get_magazine_threshold (Allocator *allocator,
+ guint ix);
+
+/* --- g-slice memory checker --- */
+static void smc_notify_alloc (void *pointer,
+ size_t size);
+static int smc_notify_free (void *pointer,
+ size_t size);
+
+/* --- variables --- */
+static GPrivate *private_thread_memory = NULL;
+static gsize sys_page_size = 0;
+static Allocator allocator[1] = { { 0, }, };
+static SliceConfig slice_config = {
+ FALSE, /* always_malloc */
+ FALSE, /* bypass_magazines */
+ FALSE, /* debug_blocks */
+ 15 * 1000, /* working_set_msecs */
+ 1, /* color increment, alt: 0x7fffffff */
+};
+static GMutex *smc_tree_mutex = NULL; /* mutex for G_SLICE=debug-blocks */
+
+/* --- auxillary funcitons --- */
+void
+g_slice_set_config (GSliceConfig ckey,
+ gint64 value)
+{
+ g_return_if_fail (sys_page_size == 0);
+ switch (ckey)
+ {
+ case G_SLICE_CONFIG_ALWAYS_MALLOC:
+ slice_config.always_malloc = value != 0;
+ break;
+ case G_SLICE_CONFIG_BYPASS_MAGAZINES:
+ slice_config.bypass_magazines = value != 0;
+ break;
+ case G_SLICE_CONFIG_WORKING_SET_MSECS:
+ slice_config.working_set_msecs = value;
+ break;
+ case G_SLICE_CONFIG_COLOR_INCREMENT:
+ slice_config.color_increment = value;
+ default: ;
+ }
+}
+
+gint64
+g_slice_get_config (GSliceConfig ckey)
+{
+ switch (ckey)
+ {
+ case G_SLICE_CONFIG_ALWAYS_MALLOC:
+ return slice_config.always_malloc;
+ case G_SLICE_CONFIG_BYPASS_MAGAZINES:
+ return slice_config.bypass_magazines;
+ case G_SLICE_CONFIG_WORKING_SET_MSECS:
+ return slice_config.working_set_msecs;
+ case G_SLICE_CONFIG_CHUNK_SIZES:
+ return MAX_SLAB_INDEX (allocator);
+ case G_SLICE_CONFIG_COLOR_INCREMENT:
+ return slice_config.color_increment;
+ default:
+ return 0;
+ }
+}
+
+gint64*
+g_slice_get_config_state (GSliceConfig ckey,
+ gint64 address,
+ guint *n_values)
+{
+ guint i = 0;
+ g_return_val_if_fail (n_values != NULL, NULL);
+ *n_values = 0;
+ switch (ckey)
+ {
+ gint64 array[64];
+ case G_SLICE_CONFIG_CONTENTION_COUNTER:
+ array[i++] = SLAB_CHUNK_SIZE (allocator, address);
+ array[i++] = allocator->contention_counters[address];
+ array[i++] = allocator_get_magazine_threshold (allocator, address);
+ *n_values = i;
+ return g_memdup (array, sizeof (array[0]) * *n_values);
+ default:
+ return NULL;
+ }
+}
+
+static void
+slice_config_init (SliceConfig *config)
+{
+ /* don't use g_malloc/g_message here */
+ gchar buffer[1024];
+ const gchar *val = _g_getenv_nomalloc ("G_SLICE", buffer);
+ const GDebugKey keys[] = {
+ { "always-malloc", 1 << 0 },
+ { "debug-blocks", 1 << 1 },
+ };
+ gint flags = !val ? 0 : g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
+ *config = slice_config;
+ if (flags & (1 << 0)) /* always-malloc */
+ config->always_malloc = TRUE;
+ if (flags & (1 << 1)) /* debug-blocks */
+ config->debug_blocks = TRUE;
+}
+
+static void
+g_slice_init_nomessage (void)
+{
+ /* we may not use g_error() or friends here */
+ mem_assert (sys_page_size == 0);
+ mem_assert (MIN_MAGAZINE_SIZE >= 4);
+
+#ifdef G_OS_WIN32
+ {
+ SYSTEM_INFO system_info;
+ GetSystemInfo (&system_info);
+ sys_page_size = system_info.dwPageSize;
+ }
+#else
+ sys_page_size = sysconf (_SC_PAGESIZE); /* = sysconf (_SC_PAGE_SIZE); = getpagesize(); */
+#endif
+ mem_assert (sys_page_size >= 2 * LARGEALIGNMENT);
+ mem_assert ((sys_page_size & (sys_page_size - 1)) == 0);
+ slice_config_init (&allocator->config);
+ allocator->min_page_size = sys_page_size;
+#if HAVE_COMPLIANT_POSIX_MEMALIGN || HAVE_MEMALIGN
+ /* allow allocation of pages up to 8KB (with 8KB alignment).
+ * this is useful because many medium to large sized structures
+ * fit less than 8 times (see [4]) into 4KB pages.
+ * we allow very small page sizes here, to reduce wastage in
+ * threads if only small allocations are required (this does
+ * bear the risk of incresing allocation times and fragmentation
+ * though).
+ */
+ allocator->min_page_size = MAX (allocator->min_page_size, 4096);
+ allocator->max_page_size = MAX (allocator->min_page_size, 8192);
+ allocator->min_page_size = MIN (allocator->min_page_size, 128);
+#else
+ /* we can only align to system page size */
+ allocator->max_page_size = sys_page_size;
+#endif
+ allocator->magazine_mutex = NULL; /* _g_slice_thread_init_nomessage() */
+ allocator->magazines = g_new0 (ChunkLink*, MAX_SLAB_INDEX (allocator));
+ allocator->contention_counters = g_new0 (guint, MAX_SLAB_INDEX (allocator));
+ allocator->mutex_counter = 0;
+ allocator->stamp_counter = MAX_STAMP_COUNTER; /* force initial update */
+ allocator->last_stamp = 0;
+ allocator->slab_mutex = NULL; /* _g_slice_thread_init_nomessage() */
+ allocator->slab_stack = g_new0 (SlabInfo*, MAX_SLAB_INDEX (allocator));
+ allocator->color_accu = 0;
+ magazine_cache_update_stamp();
+ /* values cached for performance reasons */
+ allocator->max_slab_chunk_size_for_magazine_cache = MAX_SLAB_CHUNK_SIZE (allocator);
+ if (allocator->config.always_malloc || allocator->config.bypass_magazines)
+ allocator->max_slab_chunk_size_for_magazine_cache = 0; /* non-optimized cases */
+ /* at this point, g_mem_gc_friendly() should be initialized, this
+ * should have been accomplished by the above g_malloc/g_new calls
+ */
+}
+
+static inline guint
+allocator_categorize (gsize aligned_chunk_size)
+{
+ /* speed up the likely path */
+ if (G_LIKELY (aligned_chunk_size && aligned_chunk_size <= allocator->max_slab_chunk_size_for_magazine_cache))
+ return 1; /* use magazine cache */
+
+ /* the above will fail (max_slab_chunk_size_for_magazine_cache == 0) if the
+ * allocator is still uninitialized, or if we are not configured to use the
+ * magazine cache.
+ */
+ if (!sys_page_size)
+ g_slice_init_nomessage ();
+ if (!allocator->config.always_malloc &&
+ aligned_chunk_size &&
+ aligned_chunk_size <= MAX_SLAB_CHUNK_SIZE (allocator))
+ {
+ if (allocator->config.bypass_magazines)
+ return 2; /* use slab allocator, see [2] */
+ return 1; /* use magazine cache */
+ }
+ return 0; /* use malloc() */
+}
+
+void
+_g_slice_thread_init_nomessage (void)
+{
+ /* we may not use g_error() or friends here */
+ if (!sys_page_size)
+ g_slice_init_nomessage();
+ else
+ {
+ /* g_slice_init_nomessage() has been called already, probably due
+ * to a g_slice_alloc1() before g_thread_init().
+ */
+ }
+ private_thread_memory = g_private_new (private_thread_memory_cleanup);
+ allocator->magazine_mutex = g_mutex_new();
+ allocator->slab_mutex = g_mutex_new();
+ if (allocator->config.debug_blocks)
+ smc_tree_mutex = g_mutex_new();
+}
+
+static inline void
+g_mutex_lock_a (GMutex *mutex,
+ guint *contention_counter)
+{
+ gboolean contention = FALSE;
+ if (!g_mutex_trylock (mutex))
+ {
+ g_mutex_lock (mutex);
+ contention = TRUE;
+ }
+ if (contention)
+ {
+ allocator->mutex_counter++;
+ if (allocator->mutex_counter >= 1) /* quickly adapt to contention */
+ {
+ allocator->mutex_counter = 0;
+ *contention_counter = MIN (*contention_counter + 1, MAX_MAGAZINE_SIZE);
+ }
+ }
+ else /* !contention */
+ {
+ allocator->mutex_counter--;
+ if (allocator->mutex_counter < -11) /* moderately recover magazine sizes */
+ {
+ allocator->mutex_counter = 0;
+ *contention_counter = MAX (*contention_counter, 1) - 1;
+ }
+ }
+}
+
+static inline ThreadMemory*
+thread_memory_from_self (void)
+{
+ ThreadMemory *tmem = g_private_get (private_thread_memory);
+ if (G_UNLIKELY (!tmem))
+ {
+ static ThreadMemory *single_thread_memory = NULL; /* remember single-thread info for multi-threaded case */
+ if (single_thread_memory && g_thread_supported ())
+ {
+ g_mutex_lock (allocator->slab_mutex);
+ if (single_thread_memory)
+ {
+ /* GSlice has been used before g_thread_init(), and now
+ * we are running threaded. to cope with it, use the saved
+ * thread memory structure from when we weren't threaded.
+ */
+ tmem = single_thread_memory;
+ single_thread_memory = NULL; /* slab_mutex protected when multi-threaded */
+ }
+ g_mutex_unlock (allocator->slab_mutex);
+ }
+ if (!tmem)
+ {
+ const guint n_magazines = MAX_SLAB_INDEX (allocator);
+ tmem = g_malloc0 (sizeof (ThreadMemory) + sizeof (Magazine) * 2 * n_magazines);
+ tmem->magazine1 = (Magazine*) (tmem + 1);
+ tmem->magazine2 = &tmem->magazine1[n_magazines];
+ }
+ /* g_private_get/g_private_set works in the single-threaded xor the multi-
+ * threaded case. but not *across* g_thread_init(), after multi-thread
+ * initialization it returns NULL for previously set single-thread data.
+ */
+ g_private_set (private_thread_memory, tmem);
+ /* save single-thread thread memory structure, in case we need to
+ * pick it up again after multi-thread initialization happened.
+ */
+ if (!single_thread_memory && !g_thread_supported ())
+ single_thread_memory = tmem; /* no slab_mutex created yet */
+ }
+ return tmem;
+}
+
+static inline ChunkLink*
+magazine_chain_pop_head (ChunkLink **magazine_chunks)
+{
+ /* magazine chains are linked via ChunkLink->next.
+ * each ChunkLink->data of the toplevel chain may point to a subchain,
+ * linked via ChunkLink->next. ChunkLink->data of the subchains just
+ * contains uninitialized junk.
+ */
+ ChunkLink *chunk = (*magazine_chunks)->data;
+ if (G_UNLIKELY (chunk))
+ {
+ /* allocating from freed list */
+ (*magazine_chunks)->data = chunk->next;
+ }
+ else
+ {
+ chunk = *magazine_chunks;
+ *magazine_chunks = chunk->next;
+ }
+ return chunk;
+}
+
+#if 0 /* useful for debugging */
+static guint
+magazine_count (ChunkLink *head)
+{
+ guint count = 0;
+ if (!head)
+ return 0;
+ while (head)
+ {
+ ChunkLink *child = head->data;
+ count += 1;
+ for (child = head->data; child; child = child->next)
+ count += 1;
+ head = head->next;
+ }
+ return count;
+}
+#endif
+
+static inline gsize
+allocator_get_magazine_threshold (Allocator *allocator,
+ guint ix)
+{
+ /* the magazine size calculated here has a lower bound of MIN_MAGAZINE_SIZE,
+ * which is required by the implementation. also, for moderately sized chunks
+ * (say >= 64 bytes), magazine sizes shouldn't be much smaller then the number
+ * of chunks available per page/2 to avoid excessive traffic in the magazine
+ * cache for small to medium sized structures.
+ * the upper bound of the magazine size is effectively provided by
+ * MAX_MAGAZINE_SIZE. for larger chunks, this number is scaled down so that
+ * the content of a single magazine doesn't exceed ca. 16KB.
+ */
+ gsize chunk_size = SLAB_CHUNK_SIZE (allocator, ix);
+ guint threshold = MAX (MIN_MAGAZINE_SIZE, allocator->max_page_size / MAX (5 * chunk_size, 5 * 32));
+ guint contention_counter = allocator->contention_counters[ix];
+ if (G_UNLIKELY (contention_counter)) /* single CPU bias */
+ {
+ /* adapt contention counter thresholds to chunk sizes */
+ contention_counter = contention_counter * 64 / chunk_size;
+ threshold = MAX (threshold, contention_counter);
+ }
+ return threshold;
+}
+
+/* --- magazine cache --- */
+static inline void
+magazine_cache_update_stamp (void)
+{
+ if (allocator->stamp_counter >= MAX_STAMP_COUNTER)
+ {
+ GTimeVal tv;
+ g_get_current_time (&tv);
+ allocator->last_stamp = tv.tv_sec * 1000 + tv.tv_usec / 1000; /* milli seconds */
+ allocator->stamp_counter = 0;
+ }
+ else
+ allocator->stamp_counter++;
+}
+
+static inline ChunkLink*
+magazine_chain_prepare_fields (ChunkLink *magazine_chunks)
+{
+ ChunkLink *chunk1;
+ ChunkLink *chunk2;
+ ChunkLink *chunk3;
+ ChunkLink *chunk4;
+ /* checked upon initialization: mem_assert (MIN_MAGAZINE_SIZE >= 4); */
+ /* ensure a magazine with at least 4 unused data pointers */
+ chunk1 = magazine_chain_pop_head (&magazine_chunks);
+ chunk2 = magazine_chain_pop_head (&magazine_chunks);
+ chunk3 = magazine_chain_pop_head (&magazine_chunks);
+ chunk4 = magazine_chain_pop_head (&magazine_chunks);
+ chunk4->next = magazine_chunks;
+ chunk3->next = chunk4;
+ chunk2->next = chunk3;
+ chunk1->next = chunk2;
+ return chunk1;
+}
+
+/* access the first 3 fields of a specially prepared magazine chain */
+#define magazine_chain_prev(mc) ((mc)->data)
+#define magazine_chain_stamp(mc) ((mc)->next->data)
+#define magazine_chain_uint_stamp(mc) GPOINTER_TO_UINT ((mc)->next->data)
+#define magazine_chain_next(mc) ((mc)->next->next->data)
+#define magazine_chain_count(mc) ((mc)->next->next->next->data)
+
+static void
+magazine_cache_trim (Allocator *allocator,
+ guint ix,
+ guint stamp)
+{
+ /* g_mutex_lock (allocator->mutex); done by caller */
+ /* trim magazine cache from tail */
+ ChunkLink *current = magazine_chain_prev (allocator->magazines[ix]);
+ ChunkLink *trash = NULL;
+ while (ABS (stamp - magazine_chain_uint_stamp (current)) >= allocator->config.working_set_msecs)
+ {
+ /* unlink */
+ ChunkLink *prev = magazine_chain_prev (current);
+ ChunkLink *next = magazine_chain_next (current);
+ magazine_chain_next (prev) = next;
+ magazine_chain_prev (next) = prev;
+ /* clear special fields, put on trash stack */
+ magazine_chain_next (current) = NULL;
+ magazine_chain_count (current) = NULL;
+ magazine_chain_stamp (current) = NULL;
+ magazine_chain_prev (current) = trash;
+ trash = current;
+ /* fixup list head if required */
+ if (current == allocator->magazines[ix])
+ {
+ allocator->magazines[ix] = NULL;
+ break;
+ }
+ current = prev;
+ }
+ g_mutex_unlock (allocator->magazine_mutex);
+ /* free trash */
+ if (trash)
+ {
+ const gsize chunk_size = SLAB_CHUNK_SIZE (allocator, ix);
+ g_mutex_lock (allocator->slab_mutex);
+ while (trash)
+ {
+ current = trash;
+ trash = magazine_chain_prev (current);
+ magazine_chain_prev (current) = NULL; /* clear special field */
+ while (current)
+ {
+ ChunkLink *chunk = magazine_chain_pop_head (&current);
+ slab_allocator_free_chunk (chunk_size, chunk);
+ }
+ }
+ g_mutex_unlock (allocator->slab_mutex);
+ }
+}
+
+static void
+magazine_cache_push_magazine (guint ix,
+ ChunkLink *magazine_chunks,
+ gsize count) /* must be >= MIN_MAGAZINE_SIZE */
+{
+ ChunkLink *current = magazine_chain_prepare_fields (magazine_chunks);
+ ChunkLink *next, *prev;
+ g_mutex_lock (allocator->magazine_mutex);
+ /* add magazine at head */
+ next = allocator->magazines[ix];
+ if (next)
+ prev = magazine_chain_prev (next);
+ else
+ next = prev = current;
+ magazine_chain_next (prev) = current;
+ magazine_chain_prev (next) = current;
+ magazine_chain_prev (current) = prev;
+ magazine_chain_next (current) = next;
+ magazine_chain_count (current) = (gpointer) count;
+ /* stamp magazine */
+ magazine_cache_update_stamp();
+ magazine_chain_stamp (current) = GUINT_TO_POINTER (allocator->last_stamp);
+ allocator->magazines[ix] = current;
+ /* free old magazines beyond a certain threshold */
+ magazine_cache_trim (allocator, ix, allocator->last_stamp);
+ /* g_mutex_unlock (allocator->mutex); was done by magazine_cache_trim() */
+}
+
+static ChunkLink*
+magazine_cache_pop_magazine (guint ix,
+ gsize *countp)
+{
+ g_mutex_lock_a (allocator->magazine_mutex, &allocator->contention_counters[ix]);
+ if (!allocator->magazines[ix])
+ {
+ guint magazine_threshold = allocator_get_magazine_threshold (allocator, ix);
+ gsize i, chunk_size = SLAB_CHUNK_SIZE (allocator, ix);
+ ChunkLink *chunk, *head;
+ g_mutex_unlock (allocator->magazine_mutex);
+ g_mutex_lock (allocator->slab_mutex);
+ head = slab_allocator_alloc_chunk (chunk_size);
+ head->data = NULL;
+ chunk = head;
+ for (i = 1; i < magazine_threshold; i++)
+ {
+ chunk->next = slab_allocator_alloc_chunk (chunk_size);
+ chunk = chunk->next;
+ chunk->data = NULL;
+ }
+ chunk->next = NULL;
+ g_mutex_unlock (allocator->slab_mutex);
+ *countp = i;
+ return head;
+ }
+ else
+ {
+ ChunkLink *current = allocator->magazines[ix];
+ ChunkLink *prev = magazine_chain_prev (current);
+ ChunkLink *next = magazine_chain_next (current);
+ /* unlink */
+ magazine_chain_next (prev) = next;
+ magazine_chain_prev (next) = prev;
+ allocator->magazines[ix] = next == current ? NULL : next;
+ g_mutex_unlock (allocator->magazine_mutex);
+ /* clear special fields and hand out */
+ *countp = (gsize) magazine_chain_count (current);
+ magazine_chain_prev (current) = NULL;
+ magazine_chain_next (current) = NULL;
+ magazine_chain_count (current) = NULL;
+ magazine_chain_stamp (current) = NULL;
+ return current;
+ }
+}
+
+/* --- thread magazines --- */
+static void
+private_thread_memory_cleanup (gpointer data)
+{
+ ThreadMemory *tmem = data;
+ const guint n_magazines = MAX_SLAB_INDEX (allocator);
+ guint ix;
+ for (ix = 0; ix < n_magazines; ix++)
+ {
+ Magazine *mags[2];
+ guint j;
+ mags[0] = &tmem->magazine1[ix];
+ mags[1] = &tmem->magazine2[ix];
+ for (j = 0; j < 2; j++)
+ {
+ Magazine *mag = mags[j];
+ if (mag->count >= MIN_MAGAZINE_SIZE)
+ magazine_cache_push_magazine (ix, mag->chunks, mag->count);
+ else
+ {
+ const gsize chunk_size = SLAB_CHUNK_SIZE (allocator, ix);
+ g_mutex_lock (allocator->slab_mutex);
+ while (mag->chunks)
+ {
+ ChunkLink *chunk = magazine_chain_pop_head (&mag->chunks);
+ slab_allocator_free_chunk (chunk_size, chunk);
+ }
+ g_mutex_unlock (allocator->slab_mutex);
+ }
+ }
+ }
+ g_free (tmem);
+}
+
+static void
+thread_memory_magazine1_reload (ThreadMemory *tmem,
+ guint ix)
+{
+ Magazine *mag = &tmem->magazine1[ix];
+ mem_assert (mag->chunks == NULL); /* ensure that we may reset mag->count */
+ mag->count = 0;
+ mag->chunks = magazine_cache_pop_magazine (ix, &mag->count);
+}
+
+static void
+thread_memory_magazine2_unload (ThreadMemory *tmem,
+ guint ix)
+{
+ Magazine *mag = &tmem->magazine2[ix];
+ magazine_cache_push_magazine (ix, mag->chunks, mag->count);
+ mag->chunks = NULL;
+ mag->count = 0;
+}
+
+static inline void
+thread_memory_swap_magazines (ThreadMemory *tmem,
+ guint ix)
+{
+ Magazine xmag = tmem->magazine1[ix];
+ tmem->magazine1[ix] = tmem->magazine2[ix];
+ tmem->magazine2[ix] = xmag;
+}
+
+static inline gboolean
+thread_memory_magazine1_is_empty (ThreadMemory *tmem,
+ guint ix)
+{
+ return tmem->magazine1[ix].chunks == NULL;
+}
+
+static inline gboolean
+thread_memory_magazine2_is_full (ThreadMemory *tmem,
+ guint ix)
+{
+ return tmem->magazine2[ix].count >= allocator_get_magazine_threshold (allocator, ix);
+}
+
+static inline gpointer
+thread_memory_magazine1_alloc (ThreadMemory *tmem,
+ guint ix)
+{
+ Magazine *mag = &tmem->magazine1[ix];
+ ChunkLink *chunk = magazine_chain_pop_head (&mag->chunks);
+ if (G_LIKELY (mag->count > 0))
+ mag->count--;
+ return chunk;
+}
+
+static inline void
+thread_memory_magazine2_free (ThreadMemory *tmem,
+ guint ix,
+ gpointer mem)
+{
+ Magazine *mag = &tmem->magazine2[ix];
+ ChunkLink *chunk = mem;
+ chunk->data = NULL;
+ chunk->next = mag->chunks;
+ mag->chunks = chunk;
+ mag->count++;
+}
+
+#endif /* NOT_NEEDED_FOR_NAVIT */
+/* --- API functions --- */
+gpointer
+g_slice_alloc (gsize mem_size)
+{
+#if NOT_NEEDED_FOR_NAVIT
+ gsize chunk_size;
+ gpointer mem;
+ guint acat;
+ chunk_size = P2ALIGN (mem_size);
+ acat = allocator_categorize (chunk_size);
+ if (G_LIKELY (acat == 1)) /* allocate through magazine layer */
+ {
+ ThreadMemory *tmem = thread_memory_from_self();
+ guint ix = SLAB_INDEX (allocator, chunk_size);
+ if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))
+ {
+ thread_memory_swap_magazines (tmem, ix);
+ if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))
+ thread_memory_magazine1_reload (tmem, ix);
+ }
+ mem = thread_memory_magazine1_alloc (tmem, ix);
+ }
+ else if (acat == 2) /* allocate through slab allocator */
+ {
+ g_mutex_lock (allocator->slab_mutex);
+ mem = slab_allocator_alloc_chunk (chunk_size);
+ g_mutex_unlock (allocator->slab_mutex);
+ }
+ else /* delegate to system malloc */
+ mem = g_malloc (mem_size);
+ if (G_UNLIKELY (allocator->config.debug_blocks))
+ smc_notify_alloc (mem, mem_size);
+ return mem;
+#else /* NOT_NEEDED_FOR_NAVIT */
+ return g_malloc(mem_size);
+#endif /* NOT_NEEDED_FOR_NAVIT */
+}
+
+gpointer
+g_slice_alloc0 (gsize mem_size)
+{
+ gpointer mem = g_slice_alloc (mem_size);
+ if (mem)
+ memset (mem, 0, mem_size);
+ return mem;
+}
+
+gpointer
+g_slice_copy (gsize mem_size,
+ gconstpointer mem_block)
+{
+ gpointer mem = g_slice_alloc (mem_size);
+ if (mem)
+ memcpy (mem, mem_block, mem_size);
+ return mem;
+}
+
+void
+g_slice_free1 (gsize mem_size,
+ gpointer mem_block)
+{
+#if NOT_NEEDED_FOR_NAVIT
+ gsize chunk_size = P2ALIGN (mem_size);
+ guint acat = allocator_categorize (chunk_size);
+ if (G_UNLIKELY (!mem_block))
+ return;
+ if (G_UNLIKELY (allocator->config.debug_blocks) &&
+ !smc_notify_free (mem_block, mem_size))
+ abort();
+ if (G_LIKELY (acat == 1)) /* allocate through magazine layer */
+ {
+ ThreadMemory *tmem = thread_memory_from_self();
+ guint ix = SLAB_INDEX (allocator, chunk_size);
+ if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
+ {
+ thread_memory_swap_magazines (tmem, ix);
+ if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
+ thread_memory_magazine2_unload (tmem, ix);
+ }
+ if (G_UNLIKELY (g_mem_gc_friendly))
+ memset (mem_block, 0, chunk_size);
+ thread_memory_magazine2_free (tmem, ix, mem_block);
+ }
+ else if (acat == 2) /* allocate through slab allocator */
+ {
+ if (G_UNLIKELY (g_mem_gc_friendly))
+ memset (mem_block, 0, chunk_size);
+ g_mutex_lock (allocator->slab_mutex);
+ slab_allocator_free_chunk (chunk_size, mem_block);
+ g_mutex_unlock (allocator->slab_mutex);
+ }
+ else /* delegate to system malloc */
+ {
+ if (G_UNLIKELY (g_mem_gc_friendly))
+ memset (mem_block, 0, mem_size);
+ g_free (mem_block);
+ }
+#else /* NOT_NEEDED_FOR_NAVIT */
+ g_free(mem_block);
+#endif /* NOT_NEEDED_FOR_NAVIT */
+}
+
+void
+g_slice_free_chain_with_offset (gsize mem_size,
+ gpointer mem_chain,
+ gsize next_offset)
+{
+ gpointer slice = mem_chain;
+#if NOT_NEEDED_FOR_NAVIT
+ /* while the thread magazines and the magazine cache are implemented so that
+ * they can easily be extended to allow for free lists containing more free
+ * lists for the first level nodes, which would allow O(1) freeing in this
+ * function, the benefit of such an extension is questionable, because:
+ * - the magazine size counts will become mere lower bounds which confuses
+ * the code adapting to lock contention;
+ * - freeing a single node to the thread magazines is very fast, so this
+ * O(list_length) operation is multiplied by a fairly small factor;
+ * - memory usage histograms on larger applications seem to indicate that
+ * the amount of released multi node lists is negligible in comparison
+ * to single node releases.
+ * - the major performance bottle neck, namely g_private_get() or
+ * g_mutex_lock()/g_mutex_unlock() has already been moved out of the
+ * inner loop for freeing chained slices.
+ */
+ gsize chunk_size = P2ALIGN (mem_size);
+ guint acat = allocator_categorize (chunk_size);
+ if (G_LIKELY (acat == 1)) /* allocate through magazine layer */
+ {
+ ThreadMemory *tmem = thread_memory_from_self();
+ guint ix = SLAB_INDEX (allocator, chunk_size);
+ while (slice)
+ {
+ guint8 *current = slice;
+ slice = *(gpointer*) (current + next_offset);
+ if (G_UNLIKELY (allocator->config.debug_blocks) &&
+ !smc_notify_free (current, mem_size))
+ abort();
+ if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
+ {
+ thread_memory_swap_magazines (tmem, ix);
+ if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
+ thread_memory_magazine2_unload (tmem, ix);
+ }
+ if (G_UNLIKELY (g_mem_gc_friendly))
+ memset (current, 0, chunk_size);
+ thread_memory_magazine2_free (tmem, ix, current);
+ }
+ }
+ else if (acat == 2) /* allocate through slab allocator */
+ {
+ g_mutex_lock (allocator->slab_mutex);
+ while (slice)
+ {
+ guint8 *current = slice;
+ slice = *(gpointer*) (current + next_offset);
+ if (G_UNLIKELY (allocator->config.debug_blocks) &&
+ !smc_notify_free (current, mem_size))
+ abort();
+ if (G_UNLIKELY (g_mem_gc_friendly))
+ memset (current, 0, chunk_size);
+ slab_allocator_free_chunk (chunk_size, current);
+ }
+ g_mutex_unlock (allocator->slab_mutex);
+ }
+ else /* delegate to system malloc */
+#else /* NOT_NEEDED_FOR_NAVIT */
+ while (slice)
+ {
+ guint8 *current = slice;
+ slice = *(gpointer*) (current + next_offset);
+#if NOT_NEEDED_FOR_NAVIT
+ if (G_UNLIKELY (allocator->config.debug_blocks) &&
+ !smc_notify_free (current, mem_size))
+ abort();
+#endif /* NOT_NEEDED_FOR_NAVIT */
+ if (G_UNLIKELY (g_mem_gc_friendly))
+ memset (current, 0, mem_size);
+ g_free (current);
+ }
+#endif /* NOT_NEEDED_FOR_NAVIT */
+}
+
+#if NOT_NEEDED_FOR_NAVIT
+/* --- single page allocator --- */
+static void
+allocator_slab_stack_push (Allocator *allocator,
+ guint ix,
+ SlabInfo *sinfo)
+{
+ /* insert slab at slab ring head */
+ if (!allocator->slab_stack[ix])
+ {
+ sinfo->next = sinfo;
+ sinfo->prev = sinfo;
+ }
+ else
+ {
+ SlabInfo *next = allocator->slab_stack[ix], *prev = next->prev;
+ next->prev = sinfo;
+ prev->next = sinfo;
+ sinfo->next = next;
+ sinfo->prev = prev;
+ }
+ allocator->slab_stack[ix] = sinfo;
+}
+
+static gsize
+allocator_aligned_page_size (Allocator *allocator,
+ gsize n_bytes)
+{
+ gsize val = 1 << g_bit_storage (n_bytes - 1);
+ val = MAX (val, allocator->min_page_size);
+ return val;
+}
+
+static void
+allocator_add_slab (Allocator *allocator,
+ guint ix,
+ gsize chunk_size)
+{
+ ChunkLink *chunk;
+ SlabInfo *sinfo;
+ gsize addr, padding, n_chunks, color = 0;
+ gsize page_size = allocator_aligned_page_size (allocator, SLAB_BPAGE_SIZE (allocator, chunk_size));
+ /* allocate 1 page for the chunks and the slab */
+ gpointer aligned_memory = allocator_memalign (page_size, page_size - NATIVE_MALLOC_PADDING);
+ guint8 *mem = aligned_memory;
+ guint i;
+ if (!mem)
+ {
+ const gchar *syserr = "unknown error";
+#if HAVE_STRERROR
+ syserr = strerror (errno);
+#endif
+ mem_error ("failed to allocate %u bytes (alignment: %u): %s\n",
+ (guint) (page_size - NATIVE_MALLOC_PADDING), (guint) page_size, syserr);
+ }
+ /* mask page adress */
+ addr = ((gsize) mem / page_size) * page_size;
+ /* assert alignment */
+ mem_assert (aligned_memory == (gpointer) addr);
+ /* basic slab info setup */
+ sinfo = (SlabInfo*) (mem + page_size - SLAB_INFO_SIZE);
+ sinfo->n_allocated = 0;
+ sinfo->chunks = NULL;
+ /* figure cache colorization */
+ n_chunks = ((guint8*) sinfo - mem) / chunk_size;
+ padding = ((guint8*) sinfo - mem) - n_chunks * chunk_size;
+ if (padding)
+ {
+ color = (allocator->color_accu * P2ALIGNMENT) % padding;
+ allocator->color_accu += allocator->config.color_increment;
+ }
+ /* add chunks to free list */
+ chunk = (ChunkLink*) (mem + color);
+ sinfo->chunks = chunk;
+ for (i = 0; i < n_chunks - 1; i++)
+ {
+ chunk->next = (ChunkLink*) ((guint8*) chunk + chunk_size);
+ chunk = chunk->next;
+ }
+ chunk->next = NULL; /* last chunk */
+ /* add slab to slab ring */
+ allocator_slab_stack_push (allocator, ix, sinfo);
+}
+
+static gpointer
+slab_allocator_alloc_chunk (gsize chunk_size)
+{
+ ChunkLink *chunk;
+ guint ix = SLAB_INDEX (allocator, chunk_size);
+ /* ensure non-empty slab */
+ if (!allocator->slab_stack[ix] || !allocator->slab_stack[ix]->chunks)
+ allocator_add_slab (allocator, ix, chunk_size);
+ /* allocate chunk */
+ chunk = allocator->slab_stack[ix]->chunks;
+ allocator->slab_stack[ix]->chunks = chunk->next;
+ allocator->slab_stack[ix]->n_allocated++;
+ /* rotate empty slabs */
+ if (!allocator->slab_stack[ix]->chunks)
+ allocator->slab_stack[ix] = allocator->slab_stack[ix]->next;
+ return chunk;
+}
+
+static void
+slab_allocator_free_chunk (gsize chunk_size,
+ gpointer mem)
+{
+ ChunkLink *chunk;
+ gboolean was_empty;
+ guint ix = SLAB_INDEX (allocator, chunk_size);
+ gsize page_size = allocator_aligned_page_size (allocator, SLAB_BPAGE_SIZE (allocator, chunk_size));
+ gsize addr = ((gsize) mem / page_size) * page_size;
+ /* mask page adress */
+ guint8 *page = (guint8*) addr;
+ SlabInfo *sinfo = (SlabInfo*) (page + page_size - SLAB_INFO_SIZE);
+ /* assert valid chunk count */
+ mem_assert (sinfo->n_allocated > 0);
+ /* add chunk to free list */
+ was_empty = sinfo->chunks == NULL;
+ chunk = (ChunkLink*) mem;
+ chunk->next = sinfo->chunks;
+ sinfo->chunks = chunk;
+ sinfo->n_allocated--;
+ /* keep slab ring partially sorted, empty slabs at end */
+ if (was_empty)
+ {
+ /* unlink slab */
+ SlabInfo *next = sinfo->next, *prev = sinfo->prev;
+ next->prev = prev;
+ prev->next = next;
+ if (allocator->slab_stack[ix] == sinfo)
+ allocator->slab_stack[ix] = next == sinfo ? NULL : next;
+ /* insert slab at head */
+ allocator_slab_stack_push (allocator, ix, sinfo);
+ }
+ /* eagerly free complete unused slabs */
+ if (!sinfo->n_allocated)
+ {
+ /* unlink slab */
+ SlabInfo *next = sinfo->next, *prev = sinfo->prev;
+ next->prev = prev;
+ prev->next = next;
+ if (allocator->slab_stack[ix] == sinfo)
+ allocator->slab_stack[ix] = next == sinfo ? NULL : next;
+ /* free slab */
+ allocator_memfree (page_size, page);
+ }
+}
+
+/* --- memalign implementation --- */
+#ifdef HAVE_MALLOC_H
+#include <malloc.h> /* memalign() */
+#endif
+
+/* from config.h:
+ * define HAVE_POSIX_MEMALIGN 1 // if free(posix_memalign(3)) works, <stdlib.h>
+ * define HAVE_COMPLIANT_POSIX_MEMALIGN 1 // if free(posix_memalign(3)) works for sizes != 2^n, <stdlib.h>
+ * define HAVE_MEMALIGN 1 // if free(memalign(3)) works, <malloc.h>
+ * define HAVE_VALLOC 1 // if free(valloc(3)) works, <stdlib.h> or <malloc.h>
+ * if none is provided, we implement malloc(3)-based alloc-only page alignment
+ */
+
+#if !(HAVE_COMPLIANT_POSIX_MEMALIGN || HAVE_MEMALIGN || HAVE_VALLOC)
+static GTrashStack *compat_valloc_trash = NULL;
+#endif
+
+static gpointer
+allocator_memalign (gsize alignment,
+ gsize memsize)
+{
+ gpointer aligned_memory = NULL;
+ gint err = ENOMEM;
+#if HAVE_COMPLIANT_POSIX_MEMALIGN
+ err = posix_memalign (&aligned_memory, alignment, memsize);
+#elif HAVE_MEMALIGN
+ errno = 0;
+ aligned_memory = memalign (alignment, memsize);
+ err = errno;
+#elif HAVE_VALLOC
+ errno = 0;
+ aligned_memory = valloc (memsize);
+ err = errno;
+#else
+ /* simplistic non-freeing page allocator */
+ mem_assert (alignment == sys_page_size);
+ mem_assert (memsize <= sys_page_size);
+ if (!compat_valloc_trash)
+ {
+ const guint n_pages = 16;
+ guint8 *mem = malloc (n_pages * sys_page_size);
+ err = errno;
+ if (mem)
+ {
+ gint i = n_pages;
+ guint8 *amem = (guint8*) ALIGN ((gsize) mem, sys_page_size);
+ if (amem != mem)
+ i--; /* mem wasn't page aligned */
+ while (--i >= 0)
+ g_trash_stack_push (&compat_valloc_trash, amem + i * sys_page_size);
+ }
+ }
+ aligned_memory = g_trash_stack_pop (&compat_valloc_trash);
+#endif
+ if (!aligned_memory)
+ errno = err;
+ return aligned_memory;
+}
+
+static void
+allocator_memfree (gsize memsize,
+ gpointer mem)
+{
+#if HAVE_COMPLIANT_POSIX_MEMALIGN || HAVE_MEMALIGN || HAVE_VALLOC
+ free (mem);
+#else
+ mem_assert (memsize <= sys_page_size);
+ g_trash_stack_push (&compat_valloc_trash, mem);
+#endif
+}
+
+static void
+mem_error (const char *format,
+ ...)
+{
+ const char *pname;
+ va_list args;
+ /* at least, put out "MEMORY-ERROR", in case we segfault during the rest of the function */
+ fputs ("\n***MEMORY-ERROR***: ", stderr);
+ pname = g_get_prgname();
+ fprintf (stderr, "%s[%ld]: GSlice: ", pname ? pname : "", (long)getpid());
+ va_start (args, format);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ fputs ("\n", stderr);
+ abort();
+ _exit (1);
+}
+
+/* --- g-slice memory checker tree --- */
+typedef size_t SmcKType; /* key type */
+typedef size_t SmcVType; /* value type */
+typedef struct {
+ SmcKType key;
+ SmcVType value;
+} SmcEntry;
+static void smc_tree_insert (SmcKType key,
+ SmcVType value);
+static gboolean smc_tree_lookup (SmcKType key,
+ SmcVType *value_p);
+static gboolean smc_tree_remove (SmcKType key);
+
+
+/* --- g-slice memory checker implementation --- */
+static void
+smc_notify_alloc (void *pointer,
+ size_t size)
+{
+ size_t adress = (size_t) pointer;
+ if (pointer)
+ smc_tree_insert (adress, size);
+}
+
+#if 0
+static void
+smc_notify_ignore (void *pointer)
+{
+ size_t adress = (size_t) pointer;
+ if (pointer)
+ smc_tree_remove (adress);
+}
+#endif
+
+static int
+smc_notify_free (void *pointer,
+ size_t size)
+{
+ size_t adress = (size_t) pointer;
+ SmcVType real_size;
+ gboolean found_one;
+
+ if (!pointer)
+ return 1; /* ignore */
+ found_one = smc_tree_lookup (adress, &real_size);
+ if (!found_one)
+ {
+ fprintf (stderr, "GSlice: MemChecker: attempt to release non-allocated block: %p size=%" G_GSIZE_FORMAT "\n", pointer, size);
+ return 0;
+ }
+ if (real_size != size && (real_size || size))
+ {
+ fprintf (stderr, "GSlice: MemChecker: attempt to release block with invalid size: %p size=%" G_GSIZE_FORMAT " invalid-size=%" G_GSIZE_FORMAT "\n", pointer, real_size, size);
+ return 0;
+ }
+ if (!smc_tree_remove (adress))
+ {
+ fprintf (stderr, "GSlice: MemChecker: attempt to release non-allocated block: %p size=%" G_GSIZE_FORMAT "\n", pointer, size);
+ return 0;
+ }
+ return 1; /* all fine */
+}
+
+/* --- g-slice memory checker tree implementation --- */
+#define SMC_TRUNK_COUNT (4093 /* 16381 */) /* prime, to distribute trunk collisions (big, allocated just once) */
+#define SMC_BRANCH_COUNT (511) /* prime, to distribute branch collisions */
+#define SMC_TRUNK_EXTENT (SMC_BRANCH_COUNT * 2039) /* key adress space per trunk, should distribute uniformly across BRANCH_COUNT */
+#define SMC_TRUNK_HASH(k) ((k / SMC_TRUNK_EXTENT) % SMC_TRUNK_COUNT) /* generate new trunk hash per megabyte (roughly) */
+#define SMC_BRANCH_HASH(k) (k % SMC_BRANCH_COUNT)
+
+typedef struct {
+ SmcEntry *entries;
+ unsigned int n_entries;
+} SmcBranch;
+
+static SmcBranch **smc_tree_root = NULL;
+
+static void
+smc_tree_abort (int errval)
+{
+ const char *syserr = "unknown error";
+#if HAVE_STRERROR
+ syserr = strerror (errval);
+#endif
+ mem_error ("MemChecker: failure in debugging tree: %s", syserr);
+}
+
+static inline SmcEntry*
+smc_tree_branch_grow_L (SmcBranch *branch,
+ unsigned int index)
+{
+ unsigned int old_size = branch->n_entries * sizeof (branch->entries[0]);
+ unsigned int new_size = old_size + sizeof (branch->entries[0]);
+ SmcEntry *entry;
+ mem_assert (index <= branch->n_entries);
+ branch->entries = (SmcEntry*) realloc (branch->entries, new_size);
+ if (!branch->entries)
+ smc_tree_abort (errno);
+ entry = branch->entries + index;
+ g_memmove (entry + 1, entry, (branch->n_entries - index) * sizeof (entry[0]));
+ branch->n_entries += 1;
+ return entry;
+}
+
+static inline SmcEntry*
+smc_tree_branch_lookup_nearest_L (SmcBranch *branch,
+ SmcKType key)
+{
+ unsigned int n_nodes = branch->n_entries, offs = 0;
+ SmcEntry *check = branch->entries;
+ int cmp = 0;
+ while (offs < n_nodes)
+ {
+ unsigned int i = (offs + n_nodes) >> 1;
+ check = branch->entries + i;
+ cmp = key < check->key ? -1 : key != check->key;
+ if (cmp == 0)
+ return check; /* return exact match */
+ else if (cmp < 0)
+ n_nodes = i;
+ else /* (cmp > 0) */
+ offs = i + 1;
+ }
+ /* check points at last mismatch, cmp > 0 indicates greater key */
+ return cmp > 0 ? check + 1 : check; /* return insertion position for inexact match */
+}
+
+static void
+smc_tree_insert (SmcKType key,
+ SmcVType value)
+{
+ unsigned int ix0, ix1;
+ SmcEntry *entry;
+
+ g_mutex_lock (smc_tree_mutex);
+ ix0 = SMC_TRUNK_HASH (key);
+ ix1 = SMC_BRANCH_HASH (key);
+ if (!smc_tree_root)
+ {
+ smc_tree_root = calloc (SMC_TRUNK_COUNT, sizeof (smc_tree_root[0]));
+ if (!smc_tree_root)
+ smc_tree_abort (errno);
+ }
+ if (!smc_tree_root[ix0])
+ {
+ smc_tree_root[ix0] = calloc (SMC_BRANCH_COUNT, sizeof (smc_tree_root[0][0]));
+ if (!smc_tree_root[ix0])
+ smc_tree_abort (errno);
+ }
+ entry = smc_tree_branch_lookup_nearest_L (&smc_tree_root[ix0][ix1], key);
+ if (!entry || /* need create */
+ entry >= smc_tree_root[ix0][ix1].entries + smc_tree_root[ix0][ix1].n_entries || /* need append */
+ entry->key != key) /* need insert */
+ entry = smc_tree_branch_grow_L (&smc_tree_root[ix0][ix1], entry - smc_tree_root[ix0][ix1].entries);
+ entry->key = key;
+ entry->value = value;
+ g_mutex_unlock (smc_tree_mutex);
+}
+
+static gboolean
+smc_tree_lookup (SmcKType key,
+ SmcVType *value_p)
+{
+ SmcEntry *entry = NULL;
+ unsigned int ix0 = SMC_TRUNK_HASH (key), ix1 = SMC_BRANCH_HASH (key);
+ gboolean found_one = FALSE;
+ *value_p = 0;
+ g_mutex_lock (smc_tree_mutex);
+ if (smc_tree_root && smc_tree_root[ix0])
+ {
+ entry = smc_tree_branch_lookup_nearest_L (&smc_tree_root[ix0][ix1], key);
+ if (entry &&
+ entry < smc_tree_root[ix0][ix1].entries + smc_tree_root[ix0][ix1].n_entries &&
+ entry->key == key)
+ {
+ found_one = TRUE;
+ *value_p = entry->value;
+ }
+ }
+ g_mutex_unlock (smc_tree_mutex);
+ return found_one;
+}
+
+static gboolean
+smc_tree_remove (SmcKType key)
+{
+ unsigned int ix0 = SMC_TRUNK_HASH (key), ix1 = SMC_BRANCH_HASH (key);
+ gboolean found_one = FALSE;
+ g_mutex_lock (smc_tree_mutex);
+ if (smc_tree_root && smc_tree_root[ix0])
+ {
+ SmcEntry *entry = smc_tree_branch_lookup_nearest_L (&smc_tree_root[ix0][ix1], key);
+ if (entry &&
+ entry < smc_tree_root[ix0][ix1].entries + smc_tree_root[ix0][ix1].n_entries &&
+ entry->key == key)
+ {
+ unsigned int i = entry - smc_tree_root[ix0][ix1].entries;
+ smc_tree_root[ix0][ix1].n_entries -= 1;
+ g_memmove (entry, entry + 1, (smc_tree_root[ix0][ix1].n_entries - i) * sizeof (entry[0]));
+ if (!smc_tree_root[ix0][ix1].n_entries)
+ {
+ /* avoid useless pressure on the memory system */
+ free (smc_tree_root[ix0][ix1].entries);
+ smc_tree_root[ix0][ix1].entries = NULL;
+ }
+ found_one = TRUE;
+ }
+ }
+ g_mutex_unlock (smc_tree_mutex);
+ return found_one;
+}
+
+#ifdef G_ENABLE_DEBUG
+void
+g_slice_debug_tree_statistics (void)
+{
+ g_mutex_lock (smc_tree_mutex);
+ if (smc_tree_root)
+ {
+ unsigned int i, j, t = 0, o = 0, b = 0, su = 0, ex = 0, en = 4294967295u;
+ double tf, bf;
+ for (i = 0; i < SMC_TRUNK_COUNT; i++)
+ if (smc_tree_root[i])
+ {
+ t++;
+ for (j = 0; j < SMC_BRANCH_COUNT; j++)
+ if (smc_tree_root[i][j].n_entries)
+ {
+ b++;
+ su += smc_tree_root[i][j].n_entries;
+ en = MIN (en, smc_tree_root[i][j].n_entries);
+ ex = MAX (ex, smc_tree_root[i][j].n_entries);
+ }
+ else if (smc_tree_root[i][j].entries)
+ o++; /* formerly used, now empty */
+ }
+ en = b ? en : 0;
+ tf = MAX (t, 1.0); /* max(1) to be a valid divisor */
+ bf = MAX (b, 1.0); /* max(1) to be a valid divisor */
+ fprintf (stderr, "GSlice: MemChecker: %u trunks, %u branches, %u old branches\n", t, b, o);
+ fprintf (stderr, "GSlice: MemChecker: %f branches per trunk, %.2f%% utilization\n",
+ b / tf,
+ 100.0 - (SMC_BRANCH_COUNT - b / tf) / (0.01 * SMC_BRANCH_COUNT));
+ fprintf (stderr, "GSlice: MemChecker: %f entries per branch, %u minimum, %u maximum\n",
+ su / bf, en, ex);
+ }
+ else
+ fprintf (stderr, "GSlice: MemChecker: root=NULL\n");
+ g_mutex_unlock (smc_tree_mutex);
+
+ /* sample statistics (beast + GSLice + 24h scripted core & GUI activity):
+ * PID %CPU %MEM VSZ RSS COMMAND
+ * 8887 30.3 45.8 456068 414856 beast-0.7.1 empty.bse
+ * $ cat /proc/8887/statm # total-program-size resident-set-size shared-pages text/code data/stack library dirty-pages
+ * 114017 103714 2354 344 0 108676 0
+ * $ cat /proc/8887/status
+ * Name: beast-0.7.1
+ * VmSize: 456068 kB
+ * VmLck: 0 kB
+ * VmRSS: 414856 kB
+ * VmData: 434620 kB
+ * VmStk: 84 kB
+ * VmExe: 1376 kB
+ * VmLib: 13036 kB
+ * VmPTE: 456 kB
+ * Threads: 3
+ * (gdb) print g_slice_debug_tree_statistics ()
+ * GSlice: MemChecker: 422 trunks, 213068 branches, 0 old branches
+ * GSlice: MemChecker: 504.900474 branches per trunk, 98.81% utilization
+ * GSlice: MemChecker: 4.965039 entries per branch, 1 minimum, 37 maximum
+ */
+}
+#endif /* G_ENABLE_DEBUG */
+
+#define __G_SLICE_C__
+#include "galiasdef.c"
+#endif /* NOT_NEEDED_FOR_NAVIT */
diff --git a/support/glib/gslice.h b/support/glib/gslice.h
new file mode 100644
index 00000000..f9cc6442
--- /dev/null
+++ b/support/glib/gslice.h
@@ -0,0 +1,90 @@
+/* GLIB sliced memory - fast threaded memory chunk allocator
+ * Copyright (C) 2005 Tim Janik
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_SLICE_H__
+#define __G_SLICE_H__
+
+#ifndef __G_MEM_H__
+#error Include <glib.h> instead of <gslice.h>
+#endif
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/* slices - fast allocation/release of small memory blocks
+ */
+gpointer g_slice_alloc (gsize block_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_slice_alloc0 (gsize block_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_slice_copy (gsize block_size,
+ gconstpointer mem_block) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+void g_slice_free1 (gsize block_size,
+ gpointer mem_block);
+void g_slice_free_chain_with_offset (gsize block_size,
+ gpointer mem_chain,
+ gsize next_offset);
+#define g_slice_new(type) ((type*) g_slice_alloc (sizeof (type)))
+#define g_slice_new0(type) ((type*) g_slice_alloc0 (sizeof (type)))
+/* MemoryBlockType *
+ * g_slice_dup (MemoryBlockType,
+ * MemoryBlockType *mem_block);
+ * g_slice_free (MemoryBlockType,
+ * MemoryBlockType *mem_block);
+ * g_slice_free_chain (MemoryBlockType,
+ * MemoryBlockType *first_chain_block,
+ * memory_block_next_field);
+ * pseudo prototypes for the macro
+ * definitions following below.
+ */
+
+/* we go through extra hoops to ensure type safety */
+#define g_slice_dup(type, mem) \
+ (1 ? (type*) g_slice_copy (sizeof (type), (mem)) \
+ : ((void) ((type*) 0 == (mem)), (type*) 0))
+#define g_slice_free(type, mem) do { \
+ if (1) g_slice_free1 (sizeof (type), (mem)); \
+ else (void) ((type*) 0 == (mem)); \
+} while (0)
+#define g_slice_free_chain(type, mem_chain, next) do { \
+ if (1) g_slice_free_chain_with_offset (sizeof (type), \
+ (mem_chain), G_STRUCT_OFFSET (type, next)); \
+ else (void) ((type*) 0 == (mem_chain)); \
+} while (0)
+
+
+/* --- internal debugging API --- */
+typedef enum {
+ G_SLICE_CONFIG_ALWAYS_MALLOC = 1,
+ G_SLICE_CONFIG_BYPASS_MAGAZINES,
+ G_SLICE_CONFIG_WORKING_SET_MSECS,
+ G_SLICE_CONFIG_COLOR_INCREMENT,
+ G_SLICE_CONFIG_CHUNK_SIZES,
+ G_SLICE_CONFIG_CONTENTION_COUNTER
+} GSliceConfig;
+void g_slice_set_config (GSliceConfig ckey, gint64 value);
+gint64 g_slice_get_config (GSliceConfig ckey);
+gint64* g_slice_get_config_state (GSliceConfig ckey, gint64 address, guint *n_values);
+
+G_END_DECLS
+
+#endif /* __G_SLICE_H__ */
diff --git a/support/glib/gstrfuncs.c b/support/glib/gstrfuncs.c
new file mode 100644
index 00000000..24be1f30
--- /dev/null
+++ b/support/glib/gstrfuncs.c
@@ -0,0 +1,3125 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe
+ */
+
+#include "config.h"
+
+#define _GNU_SOURCE /* For stpcpy */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <errno.h>
+#include <ctype.h> /* For tolower() */
+#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)
+#include <signal.h>
+#endif
+
+#include "glib.h"
+#include "gprintf.h"
+#include "gprintfint.h"
+#include "glibintl.h"
+
+#include "galias.h"
+
+#ifdef G_OS_WIN32
+#include <windows.h>
+#endif
+
+/* do not include <unistd.h> in this place since it
+ * interferes with g_strsignal() on some OSes
+ */
+
+static const guint16 ascii_table_data[256] = {
+ 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
+ 0x004, 0x104, 0x104, 0x004, 0x104, 0x104, 0x004, 0x004,
+ 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
+ 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
+ 0x140, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0,
+ 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0,
+ 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459,
+ 0x459, 0x459, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0,
+ 0x0d0, 0x653, 0x653, 0x653, 0x653, 0x653, 0x653, 0x253,
+ 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253,
+ 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253,
+ 0x253, 0x253, 0x253, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0,
+ 0x0d0, 0x473, 0x473, 0x473, 0x473, 0x473, 0x473, 0x073,
+ 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073,
+ 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073,
+ 0x073, 0x073, 0x073, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x004
+ /* the upper 128 are all zeroes */
+};
+
+const guint16 * const g_ascii_table = ascii_table_data;
+
+gchar*
+g_strdup (const gchar *str)
+{
+ gchar *new_str;
+ gsize length;
+
+ if (str)
+ {
+ length = strlen (str) + 1;
+ new_str = g_new (char, length);
+ memcpy (new_str, str, length);
+ }
+ else
+ new_str = NULL;
+
+ return new_str;
+}
+
+gpointer
+g_memdup (gconstpointer mem,
+ guint byte_size)
+{
+ gpointer new_mem;
+
+ if (mem)
+ {
+ new_mem = g_malloc (byte_size);
+ memcpy (new_mem, mem, byte_size);
+ }
+ else
+ new_mem = NULL;
+
+ return new_mem;
+}
+
+/**
+ * g_strndup:
+ * @str: the string to duplicate
+ * @n: the maximum number of bytes to copy from @str
+ *
+ * Duplicates the first @n bytes of a string, returning a newly-allocated
+ * buffer @n + 1 bytes long which will always be nul-terminated.
+ * If @str is less than @n bytes long the buffer is padded with nuls.
+ * If @str is %NULL it returns %NULL.
+ * The returned value should be freed when no longer needed.
+ *
+ * <note><para>
+ * To copy a number of characters from a UTF-8 encoded string, use
+ * g_utf8_strncpy() instead.
+ * </para></note>
+ *
+ * Returns: a newly-allocated buffer containing the first @n bytes
+ * of @str, nul-terminated
+ */
+gchar*
+g_strndup (const gchar *str,
+ gsize n)
+{
+ gchar *new_str;
+
+ if (str)
+ {
+ new_str = g_new (gchar, n + 1);
+ strncpy (new_str, str, n);
+ new_str[n] = '\0';
+ }
+ else
+ new_str = NULL;
+
+ return new_str;
+}
+
+/**
+ * g_strnfill:
+ * @length: the length of the new string
+ * @fill_char: the byte to fill the string with
+ *
+ * Creates a new string @length bytes long filled with @fill_char.
+ * The returned string should be freed when no longer needed.
+ *
+ * Returns: a newly-allocated string filled the @fill_char
+ */
+gchar*
+g_strnfill (gsize length,
+ gchar fill_char)
+{
+ gchar *str;
+
+ str = g_new (gchar, length + 1);
+ memset (str, (guchar)fill_char, length);
+ str[length] = '\0';
+
+ return str;
+}
+
+/**
+ * g_stpcpy:
+ * @dest: destination buffer.
+ * @src: source string.
+ *
+ * Copies a nul-terminated string into the dest buffer, include the
+ * trailing nul, and return a pointer to the trailing nul byte.
+ * This is useful for concatenating multiple strings together
+ * without having to repeatedly scan for the end.
+ *
+ * Return value: a pointer to trailing nul byte.
+ **/
+gchar *
+g_stpcpy (gchar *dest,
+ const gchar *src)
+{
+#ifdef HAVE_STPCPY
+ g_return_val_if_fail (dest != NULL, NULL);
+ g_return_val_if_fail (src != NULL, NULL);
+ return stpcpy (dest, src);
+#else
+ register gchar *d = dest;
+ register const gchar *s = src;
+
+ g_return_val_if_fail (dest != NULL, NULL);
+ g_return_val_if_fail (src != NULL, NULL);
+ do
+ *d++ = *s;
+ while (*s++ != '\0');
+
+ return d - 1;
+#endif
+}
+
+gchar*
+g_strdup_vprintf (const gchar *format,
+ va_list args)
+{
+ gchar *string = NULL;
+
+ g_vasprintf (&string, format, args);
+
+ return string;
+}
+
+gchar*
+g_strdup_printf (const gchar *format,
+ ...)
+{
+ gchar *buffer;
+ va_list args;
+
+ va_start (args, format);
+ buffer = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ return buffer;
+}
+
+gchar*
+g_strconcat (const gchar *string1, ...)
+{
+ gsize l;
+ va_list args;
+ gchar *s;
+ gchar *concat;
+ gchar *ptr;
+
+ if (!string1)
+ return NULL;
+
+ l = 1 + strlen (string1);
+ va_start (args, string1);
+ s = va_arg (args, gchar*);
+ while (s)
+ {
+ l += strlen (s);
+ s = va_arg (args, gchar*);
+ }
+ va_end (args);
+
+ concat = g_new (gchar, l);
+ ptr = concat;
+
+ ptr = g_stpcpy (ptr, string1);
+ va_start (args, string1);
+ s = va_arg (args, gchar*);
+ while (s)
+ {
+ ptr = g_stpcpy (ptr, s);
+ s = va_arg (args, gchar*);
+ }
+ va_end (args);
+
+ return concat;
+}
+
+/**
+ * g_strtod:
+ * @nptr: the string to convert to a numeric value.
+ * @endptr: if non-%NULL, it returns the character after
+ * the last character used in the conversion.
+ *
+ * Converts a string to a #gdouble value.
+ * It calls the standard strtod() function to handle the conversion, but
+ * if the string is not completely converted it attempts the conversion
+ * again with g_ascii_strtod(), and returns the best match.
+ *
+ * This function should seldomly be used. The normal situation when reading
+ * numbers not for human consumption is to use g_ascii_strtod(). Only when
+ * you know that you must expect both locale formatted and C formatted numbers
+ * should you use this. Make sure that you don't pass strings such as comma
+ * separated lists of values, since the commas may be interpreted as a decimal
+ * point in some locales, causing unexpected results.
+ *
+ * Return value: the #gdouble value.
+ **/
+gdouble
+g_strtod (const gchar *nptr,
+ gchar **endptr)
+{
+ gchar *fail_pos_1;
+ gchar *fail_pos_2;
+ gdouble val_1;
+ gdouble val_2 = 0;
+
+ g_return_val_if_fail (nptr != NULL, 0);
+
+ fail_pos_1 = NULL;
+ fail_pos_2 = NULL;
+
+ val_1 = strtod (nptr, &fail_pos_1);
+
+ if (fail_pos_1 && fail_pos_1[0] != 0)
+ val_2 = g_ascii_strtod (nptr, &fail_pos_2);
+
+ if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2)
+ {
+ if (endptr)
+ *endptr = fail_pos_1;
+ return val_1;
+ }
+ else
+ {
+ if (endptr)
+ *endptr = fail_pos_2;
+ return val_2;
+ }
+}
+
+/**
+ * g_ascii_strtod:
+ * @nptr: the string to convert to a numeric value.
+ * @endptr: if non-%NULL, it returns the character after
+ * the last character used in the conversion.
+ *
+ * Converts a string to a #gdouble value.
+ *
+ * This function behaves like the standard strtod() function
+ * does in the C locale. It does this without actually changing
+ * the current locale, since that would not be thread-safe.
+ * A limitation of the implementation is that this function
+ * will still accept localized versions of infinities and NANs.
+ *
+ * This function is typically used when reading configuration
+ * files or other non-user input that should be locale independent.
+ * To handle input from the user you should normally use the
+ * locale-sensitive system strtod() function.
+ *
+ * To convert from a #gdouble to a string in a locale-insensitive
+ * way, use g_ascii_dtostr().
+ *
+ * If the correct value would cause overflow, plus or minus %HUGE_VAL
+ * is returned (according to the sign of the value), and %ERANGE is
+ * stored in %errno. If the correct value would cause underflow,
+ * zero is returned and %ERANGE is stored in %errno.
+ *
+ * This function resets %errno before calling strtod() so that
+ * you can reliably detect overflow and underflow.
+ *
+ * Return value: the #gdouble value.
+ **/
+gdouble
+g_ascii_strtod (const gchar *nptr,
+ gchar **endptr)
+{
+ gchar *fail_pos;
+ gdouble val;
+ struct lconv *locale_data;
+ const char *decimal_point;
+ int decimal_point_len;
+ const char *p, *decimal_point_pos;
+ const char *end = NULL; /* Silence gcc */
+ int strtod_errno;
+
+ g_return_val_if_fail (nptr != NULL, 0);
+
+ fail_pos = NULL;
+
+ locale_data = localeconv ();
+ decimal_point = locale_data->decimal_point;
+ decimal_point_len = strlen (decimal_point);
+
+#if NOT_NEEDED_FOR_NAVIT
+ g_assert (decimal_point_len != 0);
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+ decimal_point_pos = NULL;
+ end = NULL;
+
+ if (decimal_point[0] != '.' ||
+ decimal_point[1] != 0)
+ {
+ p = nptr;
+ /* Skip leading space */
+ while (g_ascii_isspace (*p))
+ p++;
+
+ /* Skip leading optional sign */
+ if (*p == '+' || *p == '-')
+ p++;
+
+ if (p[0] == '0' &&
+ (p[1] == 'x' || p[1] == 'X'))
+ {
+ p += 2;
+ /* HEX - find the (optional) decimal point */
+
+ while (g_ascii_isxdigit (*p))
+ p++;
+
+ if (*p == '.')
+ decimal_point_pos = p++;
+
+ while (g_ascii_isxdigit (*p))
+ p++;
+
+ if (*p == 'p' || *p == 'P')
+ p++;
+ if (*p == '+' || *p == '-')
+ p++;
+ while (g_ascii_isdigit (*p))
+ p++;
+
+ end = p;
+ }
+ else if (g_ascii_isdigit (*p) || *p == '.')
+ {
+ while (g_ascii_isdigit (*p))
+ p++;
+
+ if (*p == '.')
+ decimal_point_pos = p++;
+
+ while (g_ascii_isdigit (*p))
+ p++;
+
+ if (*p == 'e' || *p == 'E')
+ p++;
+ if (*p == '+' || *p == '-')
+ p++;
+ while (g_ascii_isdigit (*p))
+ p++;
+
+ end = p;
+ }
+ /* For the other cases, we need not convert the decimal point */
+ }
+
+ if (decimal_point_pos)
+ {
+ char *copy, *c;
+
+ /* We need to convert the '.' to the locale specific decimal point */
+ copy = g_malloc (end - nptr + 1 + decimal_point_len);
+
+ c = copy;
+ memcpy (c, nptr, decimal_point_pos - nptr);
+ c += decimal_point_pos - nptr;
+ memcpy (c, decimal_point, decimal_point_len);
+ c += decimal_point_len;
+ memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
+ c += end - (decimal_point_pos + 1);
+ *c = 0;
+
+ errno = 0;
+ val = strtod (copy, &fail_pos);
+ strtod_errno = errno;
+
+ if (fail_pos)
+ {
+ if (fail_pos - copy > decimal_point_pos - nptr)
+ fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
+ else
+ fail_pos = (char *)nptr + (fail_pos - copy);
+ }
+
+ g_free (copy);
+
+ }
+ else if (end)
+ {
+ char *copy;
+
+ copy = g_malloc (end - (char *)nptr + 1);
+ memcpy (copy, nptr, end - nptr);
+ *(copy + (end - (char *)nptr)) = 0;
+
+ errno = 0;
+ val = strtod (copy, &fail_pos);
+ strtod_errno = errno;
+
+ if (fail_pos)
+ {
+ fail_pos = (char *)nptr + (fail_pos - copy);
+ }
+
+ g_free (copy);
+ }
+ else
+ {
+ errno = 0;
+ val = strtod (nptr, &fail_pos);
+ strtod_errno = errno;
+ }
+
+ if (endptr)
+ *endptr = fail_pos;
+
+ errno = strtod_errno;
+
+ return val;
+}
+
+
+/**
+ * g_ascii_dtostr:
+ * @buffer: A buffer to place the resulting string in
+ * @buf_len: The length of the buffer.
+ * @d: The #gdouble to convert
+ *
+ * Converts a #gdouble to a string, using the '.' as
+ * decimal point.
+ *
+ * This functions generates enough precision that converting
+ * the string back using g_ascii_strtod() gives the same machine-number
+ * (on machines with IEEE compatible 64bit doubles). It is
+ * guaranteed that the size of the resulting string will never
+ * be larger than @G_ASCII_DTOSTR_BUF_SIZE bytes.
+ *
+ * Return value: The pointer to the buffer with the converted string.
+ **/
+gchar *
+g_ascii_dtostr (gchar *buffer,
+ gint buf_len,
+ gdouble d)
+{
+ return g_ascii_formatd (buffer, buf_len, "%.17g", d);
+}
+
+/**
+ * g_ascii_formatd:
+ * @buffer: A buffer to place the resulting string in
+ * @buf_len: The length of the buffer.
+ * @format: The printf()-style format to use for the
+ * code to use for converting.
+ * @d: The #gdouble to convert
+ *
+ * Converts a #gdouble to a string, using the '.' as
+ * decimal point. To format the number you pass in
+ * a printf()-style format string. Allowed conversion
+ * specifiers are 'e', 'E', 'f', 'F', 'g' and 'G'.
+ *
+ * If you just want to want to serialize the value into a
+ * string, use g_ascii_dtostr().
+ *
+ * Return value: The pointer to the buffer with the converted string.
+ **/
+gchar *
+g_ascii_formatd (gchar *buffer,
+ gint buf_len,
+ const gchar *format,
+ gdouble d)
+{
+ struct lconv *locale_data;
+ const char *decimal_point;
+ int decimal_point_len;
+ gchar *p;
+ int rest_len;
+ gchar format_char;
+
+ g_return_val_if_fail (buffer != NULL, NULL);
+ g_return_val_if_fail (format[0] == '%', NULL);
+ g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL);
+
+ format_char = format[strlen (format) - 1];
+
+ g_return_val_if_fail (format_char == 'e' || format_char == 'E' ||
+ format_char == 'f' || format_char == 'F' ||
+ format_char == 'g' || format_char == 'G',
+ NULL);
+
+ if (format[0] != '%')
+ return NULL;
+
+ if (strpbrk (format + 1, "'l%"))
+ return NULL;
+
+ if (!(format_char == 'e' || format_char == 'E' ||
+ format_char == 'f' || format_char == 'F' ||
+ format_char == 'g' || format_char == 'G'))
+ return NULL;
+
+
+ _g_snprintf (buffer, buf_len, format, d);
+
+ locale_data = localeconv ();
+ decimal_point = locale_data->decimal_point;
+ decimal_point_len = strlen (decimal_point);
+
+#if NOT_NEEDED_FOR_NAVIT
+ g_assert (decimal_point_len != 0);
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+ if (decimal_point[0] != '.' ||
+ decimal_point[1] != 0)
+ {
+ p = buffer;
+
+ while (g_ascii_isspace (*p))
+ p++;
+
+ if (*p == '+' || *p == '-')
+ p++;
+
+ while (isdigit ((guchar)*p))
+ p++;
+
+ if (strncmp (p, decimal_point, decimal_point_len) == 0)
+ {
+ *p = '.';
+ p++;
+ if (decimal_point_len > 1)
+ {
+ rest_len = strlen (p + (decimal_point_len-1));
+ memmove (p, p + (decimal_point_len-1), rest_len);
+ p[rest_len] = 0;
+ }
+ }
+ }
+
+ return buffer;
+}
+
+static guint64
+g_parse_long_long (const gchar *nptr,
+ const gchar **endptr,
+ guint base,
+ gboolean *negative)
+{
+ /* this code is based on on the strtol(3) code from GNU libc released under
+ * the GNU Lesser General Public License.
+ *
+ * Copyright (C) 1991,92,94,95,96,97,98,99,2000,01,02
+ * Free Software Foundation, Inc.
+ */
+#define ISSPACE(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || \
+ (c) == '\r' || (c) == '\t' || (c) == '\v')
+#define ISUPPER(c) ((c) >= 'A' && (c) <= 'Z')
+#define ISLOWER(c) ((c) >= 'a' && (c) <= 'z')
+#define ISALPHA(c) (ISUPPER (c) || ISLOWER (c))
+#define TOUPPER(c) (ISLOWER (c) ? (c) - 'a' + 'A' : (c))
+#define TOLOWER(c) (ISUPPER (c) ? (c) - 'A' + 'a' : (c))
+ gboolean overflow;
+ guint64 cutoff;
+ guint64 cutlim;
+ guint64 ui64;
+ const gchar *s, *save;
+ guchar c;
+
+ g_return_val_if_fail (nptr != NULL, 0);
+
+ *negative = FALSE;
+ if (base == 1 || base > 36)
+ {
+ errno = EINVAL;
+ if (endptr)
+ *endptr = nptr;
+ return 0;
+ }
+
+ save = s = nptr;
+
+ /* Skip white space. */
+ while (ISSPACE (*s))
+ ++s;
+
+ if (G_UNLIKELY (!*s))
+ goto noconv;
+
+ /* Check for a sign. */
+ if (*s == '-')
+ {
+ *negative = TRUE;
+ ++s;
+ }
+ else if (*s == '+')
+ ++s;
+
+ /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
+ if (*s == '0')
+ {
+ if ((base == 0 || base == 16) && TOUPPER (s[1]) == 'X')
+ {
+ s += 2;
+ base = 16;
+ }
+ else if (base == 0)
+ base = 8;
+ }
+ else if (base == 0)
+ base = 10;
+
+ /* Save the pointer so we can check later if anything happened. */
+ save = s;
+ cutoff = G_MAXUINT64 / base;
+ cutlim = G_MAXUINT64 % base;
+
+ overflow = FALSE;
+ ui64 = 0;
+ c = *s;
+ for (; c; c = *++s)
+ {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (ISALPHA (c))
+ c = TOUPPER (c) - 'A' + 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ /* Check for overflow. */
+ if (ui64 > cutoff || (ui64 == cutoff && c > cutlim))
+ overflow = TRUE;
+ else
+ {
+ ui64 *= base;
+ ui64 += c;
+ }
+ }
+
+ /* Check if anything actually happened. */
+ if (s == save)
+ goto noconv;
+
+ /* Store in ENDPTR the address of one character
+ past the last character we converted. */
+ if (endptr)
+ *endptr = s;
+
+ if (G_UNLIKELY (overflow))
+ {
+ errno = ERANGE;
+ return G_MAXUINT64;
+ }
+
+ return ui64;
+
+ noconv:
+ /* We must handle a special case here: the base is 0 or 16 and the
+ first two characters are '0' and 'x', but the rest are no
+ hexadecimal digits. This is no error case. We return 0 and
+ ENDPTR points to the `x`. */
+ if (endptr)
+ {
+ if (save - nptr >= 2 && TOUPPER (save[-1]) == 'X'
+ && save[-2] == '0')
+ *endptr = &save[-1];
+ else
+ /* There was no number to convert. */
+ *endptr = nptr;
+ }
+ return 0;
+}
+
+/**
+ * g_ascii_strtoull:
+ * @nptr: the string to convert to a numeric value.
+ * @endptr: if non-%NULL, it returns the character after
+ * the last character used in the conversion.
+ * @base: to be used for the conversion, 2..36 or 0
+ *
+ * Converts a string to a #guint64 value.
+ * This function behaves like the standard strtoull() function
+ * does in the C locale. It does this without actually
+ * changing the current locale, since that would not be
+ * thread-safe.
+ *
+ * This function is typically used when reading configuration
+ * files or other non-user input that should be locale independent.
+ * To handle input from the user you should normally use the
+ * locale-sensitive system strtoull() function.
+ *
+ * If the correct value would cause overflow, %G_MAXUINT64
+ * is returned, and %ERANGE is stored in %errno. If the base is
+ * outside the valid range, zero is returned, and %EINVAL is stored
+ * in %errno. If the string conversion fails, zero is returned, and
+ * @endptr returns @nptr (if @endptr is non-%NULL).
+ *
+ * Return value: the #guint64 value or zero on error.
+ *
+ * Since: 2.2
+ **/
+guint64
+g_ascii_strtoull (const gchar *nptr,
+ gchar **endptr,
+ guint base)
+{
+ gboolean negative;
+ guint64 result;
+
+ result = g_parse_long_long (nptr, (const gchar **) endptr, base, &negative);
+
+ /* Return the result of the appropriate sign. */
+ return negative ? -result : result;
+}
+
+/**
+ * g_ascii_strtoll:
+ * @nptr: the string to convert to a numeric value.
+ * @endptr: if non-%NULL, it returns the character after
+ * the last character used in the conversion.
+ * @base: to be used for the conversion, 2..36 or 0
+ *
+ * Converts a string to a #gint64 value.
+ * This function behaves like the standard strtoll() function
+ * does in the C locale. It does this without actually
+ * changing the current locale, since that would not be
+ * thread-safe.
+ *
+ * This function is typically used when reading configuration
+ * files or other non-user input that should be locale independent.
+ * To handle input from the user you should normally use the
+ * locale-sensitive system strtoll() function.
+ *
+ * If the correct value would cause overflow, %G_MAXINT64 or %G_MININT64
+ * is returned, and %ERANGE is stored in %errno. If the base is
+ * outside the valid range, zero is returned, and %EINVAL is stored
+ * in %errno. If the string conversion fails, zero is returned, and
+ * @endptr returns @nptr (if @endptr is non-%NULL).
+ *
+ * Return value: the #gint64 value or zero on error.
+ *
+ * Since: 2.12
+ **/
+gint64
+g_ascii_strtoll (const gchar *nptr,
+ gchar **endptr,
+ guint base)
+{
+ gboolean negative;
+ guint64 result;
+
+ result = g_parse_long_long (nptr, (const gchar **) endptr, base, &negative);
+
+ if (negative && result > (guint64) G_MININT64)
+ {
+ errno = ERANGE;
+ return G_MININT64;
+ }
+ else if (!negative && result > (guint64) G_MAXINT64)
+ {
+ errno = ERANGE;
+ return G_MAXINT64;
+ }
+ else if (negative)
+ return - (gint64) result;
+ else
+ return (gint64) result;
+}
+
+#if NOT_NEEDED_FOR_NAVIT
+G_CONST_RETURN gchar*
+g_strerror (gint errnum)
+{
+ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
+ char *msg;
+ int saved_errno = errno;
+
+#ifdef HAVE_STRERROR
+ const char *msg_locale;
+
+ msg_locale = strerror (errnum);
+ if (g_get_charset (NULL))
+ {
+ errno = saved_errno;
+ return msg_locale;
+ }
+ else
+ {
+ gchar *msg_utf8 = g_locale_to_utf8 (msg_locale, -1, NULL, NULL, NULL);
+ if (msg_utf8)
+ {
+ /* Stick in the quark table so that we can return a static result
+ */
+ GQuark msg_quark = g_quark_from_string (msg_utf8);
+ g_free (msg_utf8);
+
+ msg_utf8 = (gchar *) g_quark_to_string (msg_quark);
+ errno = saved_errno;
+ return msg_utf8;
+ }
+ }
+#elif NO_SYS_ERRLIST
+ switch (errnum)
+ {
+#ifdef E2BIG
+ case E2BIG: return "argument list too long";
+#endif
+#ifdef EACCES
+ case EACCES: return "permission denied";
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE: return "address already in use";
+#endif
+#ifdef EADDRNOTAVAIL
+ case EADDRNOTAVAIL: return "can't assign requested address";
+#endif
+#ifdef EADV
+ case EADV: return "advertise error";
+#endif
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT: return "address family not supported by protocol family";
+#endif
+#ifdef EAGAIN
+ case EAGAIN: return "try again";
+#endif
+#ifdef EALIGN
+ case EALIGN: return "EALIGN";
+#endif
+#ifdef EALREADY
+ case EALREADY: return "operation already in progress";
+#endif
+#ifdef EBADE
+ case EBADE: return "bad exchange descriptor";
+#endif
+#ifdef EBADF
+ case EBADF: return "bad file number";
+#endif
+#ifdef EBADFD
+ case EBADFD: return "file descriptor in bad state";
+#endif
+#ifdef EBADMSG
+ case EBADMSG: return "not a data message";
+#endif
+#ifdef EBADR
+ case EBADR: return "bad request descriptor";
+#endif
+#ifdef EBADRPC
+ case EBADRPC: return "RPC structure is bad";
+#endif
+#ifdef EBADRQC
+ case EBADRQC: return "bad request code";
+#endif
+#ifdef EBADSLT
+ case EBADSLT: return "invalid slot";
+#endif
+#ifdef EBFONT
+ case EBFONT: return "bad font file format";
+#endif
+#ifdef EBUSY
+ case EBUSY: return "mount device busy";
+#endif
+#ifdef ECHILD
+ case ECHILD: return "no children";
+#endif
+#ifdef ECHRNG
+ case ECHRNG: return "channel number out of range";
+#endif
+#ifdef ECOMM
+ case ECOMM: return "communication error on send";
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED: return "software caused connection abort";
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED: return "connection refused";
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET: return "connection reset by peer";
+#endif
+#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK))
+ case EDEADLK: return "resource deadlock avoided";
+#endif
+#ifdef EDEADLOCK
+ case EDEADLOCK: return "resource deadlock avoided";
+#endif
+#ifdef EDESTADDRREQ
+ case EDESTADDRREQ: return "destination address required";
+#endif
+#ifdef EDIRTY
+ case EDIRTY: return "mounting a dirty fs w/o force";
+#endif
+#ifdef EDOM
+ case EDOM: return "math argument out of range";
+#endif
+#ifdef EDOTDOT
+ case EDOTDOT: return "cross mount point";
+#endif
+#ifdef EDQUOT
+ case EDQUOT: return "disk quota exceeded";
+#endif
+#ifdef EDUPPKG
+ case EDUPPKG: return "duplicate package name";
+#endif
+#ifdef EEXIST
+ case EEXIST: return "file already exists";
+#endif
+#ifdef EFAULT
+ case EFAULT: return "bad address in system call argument";
+#endif
+#ifdef EFBIG
+ case EFBIG: return "file too large";
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN: return "host is down";
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH: return "host is unreachable";
+#endif
+#ifdef EIDRM
+ case EIDRM: return "identifier removed";
+#endif
+#ifdef EINIT
+ case EINIT: return "initialization error";
+#endif
+#ifdef EINPROGRESS
+ case EINPROGRESS: return "operation now in progress";
+#endif
+#ifdef EINTR
+ case EINTR: return "interrupted system call";
+#endif
+#ifdef EINVAL
+ case EINVAL: return "invalid argument";
+#endif
+#ifdef EIO
+ case EIO: return "I/O error";
+#endif
+#ifdef EISCONN
+ case EISCONN: return "socket is already connected";
+#endif
+#ifdef EISDIR
+ case EISDIR: return "is a directory";
+#endif
+#ifdef EISNAME
+ case EISNAM: return "is a name file";
+#endif
+#ifdef ELBIN
+ case ELBIN: return "ELBIN";
+#endif
+#ifdef EL2HLT
+ case EL2HLT: return "level 2 halted";
+#endif
+#ifdef EL2NSYNC
+ case EL2NSYNC: return "level 2 not synchronized";
+#endif
+#ifdef EL3HLT
+ case EL3HLT: return "level 3 halted";
+#endif
+#ifdef EL3RST
+ case EL3RST: return "level 3 reset";
+#endif
+#ifdef ELIBACC
+ case ELIBACC: return "can not access a needed shared library";
+#endif
+#ifdef ELIBBAD
+ case ELIBBAD: return "accessing a corrupted shared library";
+#endif
+#ifdef ELIBEXEC
+ case ELIBEXEC: return "can not exec a shared library directly";
+#endif
+#ifdef ELIBMAX
+ case ELIBMAX: return "attempting to link in more shared libraries than system limit";
+#endif
+#ifdef ELIBSCN
+ case ELIBSCN: return ".lib section in a.out corrupted";
+#endif
+#ifdef ELNRNG
+ case ELNRNG: return "link number out of range";
+#endif
+#ifdef ELOOP
+ case ELOOP: return "too many levels of symbolic links";
+#endif
+#ifdef EMFILE
+ case EMFILE: return "too many open files";
+#endif
+#ifdef EMLINK
+ case EMLINK: return "too many links";
+#endif
+#ifdef EMSGSIZE
+ case EMSGSIZE: return "message too long";
+#endif
+#ifdef EMULTIHOP
+ case EMULTIHOP: return "multihop attempted";
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG: return "file name too long";
+#endif
+#ifdef ENAVAIL
+ case ENAVAIL: return "not available";
+#endif
+#ifdef ENET
+ case ENET: return "ENET";
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN: return "network is down";
+#endif
+#ifdef ENETRESET
+ case ENETRESET: return "network dropped connection on reset";
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH: return "network is unreachable";
+#endif
+#ifdef ENFILE
+ case ENFILE: return "file table overflow";
+#endif
+#ifdef ENOANO
+ case ENOANO: return "anode table overflow";
+#endif
+#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
+ case ENOBUFS: return "no buffer space available";
+#endif
+#ifdef ENOCSI
+ case ENOCSI: return "no CSI structure available";
+#endif
+#ifdef ENODATA
+ case ENODATA: return "no data available";
+#endif
+#ifdef ENODEV
+ case ENODEV: return "no such device";
+#endif
+#ifdef ENOENT
+ case ENOENT: return "no such file or directory";
+#endif
+#ifdef ENOEXEC
+ case ENOEXEC: return "exec format error";
+#endif
+#ifdef ENOLCK
+ case ENOLCK: return "no locks available";
+#endif
+#ifdef ENOLINK
+ case ENOLINK: return "link has be severed";
+#endif
+#ifdef ENOMEM
+ case ENOMEM: return "not enough memory";
+#endif
+#ifdef ENOMSG
+ case ENOMSG: return "no message of desired type";
+#endif
+#ifdef ENONET
+ case ENONET: return "machine is not on the network";
+#endif
+#ifdef ENOPKG
+ case ENOPKG: return "package not installed";
+#endif
+#ifdef ENOPROTOOPT
+ case ENOPROTOOPT: return "bad proocol option";
+#endif
+#ifdef ENOSPC
+ case ENOSPC: return "no space left on device";
+#endif
+#ifdef ENOSR
+ case ENOSR: return "out of stream resources";
+#endif
+#ifdef ENOSTR
+ case ENOSTR: return "not a stream device";
+#endif
+#ifdef ENOSYM
+ case ENOSYM: return "unresolved symbol name";
+#endif
+#ifdef ENOSYS
+ case ENOSYS: return "function not implemented";
+#endif
+#ifdef ENOTBLK
+ case ENOTBLK: return "block device required";
+#endif
+#ifdef ENOTCONN
+ case ENOTCONN: return "socket is not connected";
+#endif
+#ifdef ENOTDIR
+ case ENOTDIR: return "not a directory";
+#endif
+#ifdef ENOTEMPTY
+ case ENOTEMPTY: return "directory not empty";
+#endif
+#ifdef ENOTNAM
+ case ENOTNAM: return "not a name file";
+#endif
+#ifdef ENOTSOCK
+ case ENOTSOCK: return "socket operation on non-socket";
+#endif
+#ifdef ENOTTY
+ case ENOTTY: return "inappropriate device for ioctl";
+#endif
+#ifdef ENOTUNIQ
+ case ENOTUNIQ: return "name not unique on network";
+#endif
+#ifdef ENXIO
+ case ENXIO: return "no such device or address";
+#endif
+#ifdef EOPNOTSUPP
+ case EOPNOTSUPP: return "operation not supported on socket";
+#endif
+#ifdef EPERM
+ case EPERM: return "not owner";
+#endif
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT: return "protocol family not supported";
+#endif
+#ifdef EPIPE
+ case EPIPE: return "broken pipe";
+#endif
+#ifdef EPROCLIM
+ case EPROCLIM: return "too many processes";
+#endif
+#ifdef EPROCUNAVAIL
+ case EPROCUNAVAIL: return "bad procedure for program";
+#endif
+#ifdef EPROGMISMATCH
+ case EPROGMISMATCH: return "program version wrong";
+#endif
+#ifdef EPROGUNAVAIL
+ case EPROGUNAVAIL: return "RPC program not available";
+#endif
+#ifdef EPROTO
+ case EPROTO: return "protocol error";
+#endif
+#ifdef EPROTONOSUPPORT
+ case EPROTONOSUPPORT: return "protocol not suppored";
+#endif
+#ifdef EPROTOTYPE
+ case EPROTOTYPE: return "protocol wrong type for socket";
+#endif
+#ifdef ERANGE
+ case ERANGE: return "math result unrepresentable";
+#endif
+#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
+ case EREFUSED: return "EREFUSED";
+#endif
+#ifdef EREMCHG
+ case EREMCHG: return "remote address changed";
+#endif
+#ifdef EREMDEV
+ case EREMDEV: return "remote device";
+#endif
+#ifdef EREMOTE
+ case EREMOTE: return "pathname hit remote file system";
+#endif
+#ifdef EREMOTEIO
+ case EREMOTEIO: return "remote i/o error";
+#endif
+#ifdef EREMOTERELEASE
+ case EREMOTERELEASE: return "EREMOTERELEASE";
+#endif
+#ifdef EROFS
+ case EROFS: return "read-only file system";
+#endif
+#ifdef ERPCMISMATCH
+ case ERPCMISMATCH: return "RPC version is wrong";
+#endif
+#ifdef ERREMOTE
+ case ERREMOTE: return "object is remote";
+#endif
+#ifdef ESHUTDOWN
+ case ESHUTDOWN: return "can't send afer socket shutdown";
+#endif
+#ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT: return "socket type not supported";
+#endif
+#ifdef ESPIPE
+ case ESPIPE: return "invalid seek";
+#endif
+#ifdef ESRCH
+ case ESRCH: return "no such process";
+#endif
+#ifdef ESRMNT
+ case ESRMNT: return "srmount error";
+#endif
+#ifdef ESTALE
+ case ESTALE: return "stale remote file handle";
+#endif
+#ifdef ESUCCESS
+ case ESUCCESS: return "Error 0";
+#endif
+#ifdef ETIME
+ case ETIME: return "timer expired";
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT: return "connection timed out";
+#endif
+#ifdef ETOOMANYREFS
+ case ETOOMANYREFS: return "too many references: can't splice";
+#endif
+#ifdef ETXTBSY
+ case ETXTBSY: return "text file or pseudo-device busy";
+#endif
+#ifdef EUCLEAN
+ case EUCLEAN: return "structure needs cleaning";
+#endif
+#ifdef EUNATCH
+ case EUNATCH: return "protocol driver not attached";
+#endif
+#ifdef EUSERS
+ case EUSERS: return "too many users";
+#endif
+#ifdef EVERSION
+ case EVERSION: return "version mismatch";
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+ case EWOULDBLOCK: return "operation would block";
+#endif
+#ifdef EXDEV
+ case EXDEV: return "cross-domain link";
+#endif
+#ifdef EXFULL
+ case EXFULL: return "message tables full";
+#endif
+ }
+#else /* NO_SYS_ERRLIST */
+#if NOT_NEEDED_FOR_NAVIT
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+
+ if ((errnum > 0) && (errnum <= sys_nerr))
+ return sys_errlist [errnum];
+#else /* NOT_NEEDED_FOR_NAVIT */
+ return NULL;
+#endif /* NOT_NEEDED_FOR_NAVIT */
+#endif /* NO_SYS_ERRLIST */
+
+ msg = g_static_private_get (&msg_private);
+ if (!msg)
+ {
+ msg = g_new (gchar, 64);
+ g_static_private_set (&msg_private, msg, g_free);
+ }
+
+ _g_sprintf (msg, "unknown error (%d)", errnum);
+
+ errno = saved_errno;
+ return msg;
+}
+
+G_CONST_RETURN gchar*
+g_strsignal (gint signum)
+{
+ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
+ char *msg;
+
+#ifdef HAVE_STRSIGNAL
+ const char *msg_locale;
+
+#if defined(G_OS_BEOS) || defined(G_WITH_CYGWIN)
+extern const char *strsignal(int);
+#else
+ /* this is declared differently (const) in string.h on BeOS */
+ extern char *strsignal (int sig);
+#endif /* !G_OS_BEOS && !G_WITH_CYGWIN */
+ msg_locale = strsignal (signum);
+ if (g_get_charset (NULL))
+ return msg_locale;
+ else
+ {
+ gchar *msg_utf8 = g_locale_to_utf8 (msg_locale, -1, NULL, NULL, NULL);
+ if (msg_utf8)
+ {
+ /* Stick in the quark table so that we can return a static result
+ */
+ GQuark msg_quark = g_quark_from_string (msg_utf8);
+ g_free (msg_utf8);
+
+ return g_quark_to_string (msg_quark);
+ }
+ }
+#elif NO_SYS_SIGLIST
+ switch (signum)
+ {
+#ifdef SIGHUP
+ case SIGHUP: return "Hangup";
+#endif
+#ifdef SIGINT
+ case SIGINT: return "Interrupt";
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT: return "Quit";
+#endif
+#ifdef SIGILL
+ case SIGILL: return "Illegal instruction";
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP: return "Trace/breakpoint trap";
+#endif
+#ifdef SIGABRT
+ case SIGABRT: return "IOT trap/Abort";
+#endif
+#ifdef SIGBUS
+ case SIGBUS: return "Bus error";
+#endif
+#ifdef SIGFPE
+ case SIGFPE: return "Floating point exception";
+#endif
+#ifdef SIGKILL
+ case SIGKILL: return "Killed";
+#endif
+#ifdef SIGUSR1
+ case SIGUSR1: return "User defined signal 1";
+#endif
+#ifdef SIGSEGV
+ case SIGSEGV: return "Segmentation fault";
+#endif
+#ifdef SIGUSR2
+ case SIGUSR2: return "User defined signal 2";
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE: return "Broken pipe";
+#endif
+#ifdef SIGALRM
+ case SIGALRM: return "Alarm clock";
+#endif
+#ifdef SIGTERM
+ case SIGTERM: return "Terminated";
+#endif
+#ifdef SIGSTKFLT
+ case SIGSTKFLT: return "Stack fault";
+#endif
+#ifdef SIGCHLD
+ case SIGCHLD: return "Child exited";
+#endif
+#ifdef SIGCONT
+ case SIGCONT: return "Continued";
+#endif
+#ifdef SIGSTOP
+ case SIGSTOP: return "Stopped (signal)";
+#endif
+#ifdef SIGTSTP
+ case SIGTSTP: return "Stopped";
+#endif
+#ifdef SIGTTIN
+ case SIGTTIN: return "Stopped (tty input)";
+#endif
+#ifdef SIGTTOU
+ case SIGTTOU: return "Stopped (tty output)";
+#endif
+#ifdef SIGURG
+ case SIGURG: return "Urgent condition";
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU: return "CPU time limit exceeded";
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ: return "File size limit exceeded";
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM: return "Virtual time alarm";
+#endif
+#ifdef SIGPROF
+ case SIGPROF: return "Profile signal";
+#endif
+#ifdef SIGWINCH
+ case SIGWINCH: return "Window size changed";
+#endif
+#ifdef SIGIO
+ case SIGIO: return "Possible I/O";
+#endif
+#ifdef SIGPWR
+ case SIGPWR: return "Power failure";
+#endif
+#ifdef SIGUNUSED
+ case SIGUNUSED: return "Unused signal";
+#endif
+ }
+#else /* NO_SYS_SIGLIST */
+
+#if NOT_NEEDED_FOR_NAVIT
+#ifdef NO_SYS_SIGLIST_DECL
+ extern char *sys_siglist[]; /*(see Tue Jan 19 00:44:24 1999 in changelog)*/
+#endif
+
+ return (char*) /* this function should return const --josh */ sys_siglist [signum];
+#else /* NOT_NEEDED_FOR_NAVIT */
+ return NULL;
+#endif /* NOT_NEEDED_FOR_NAVIT */
+#endif /* NO_SYS_SIGLIST */
+
+ msg = g_static_private_get (&msg_private);
+ if (!msg)
+ {
+ msg = g_new (gchar, 64);
+ g_static_private_set (&msg_private, msg, g_free);
+ }
+
+ _g_sprintf (msg, "unknown signal (%d)", signum);
+
+ return msg;
+}
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+/* Functions g_strlcpy and g_strlcat were originally developed by
+ * Todd C. Miller <Todd.Miller@courtesan.com> to simplify writing secure code.
+ * See ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.3
+ * for more information.
+ */
+
+#ifdef HAVE_STRLCPY
+/* Use the native ones, if available; they might be implemented in assembly */
+gsize
+g_strlcpy (gchar *dest,
+ const gchar *src,
+ gsize dest_size)
+{
+ g_return_val_if_fail (dest != NULL, 0);
+ g_return_val_if_fail (src != NULL, 0);
+
+ return strlcpy (dest, src, dest_size);
+}
+
+gsize
+g_strlcat (gchar *dest,
+ const gchar *src,
+ gsize dest_size)
+{
+ g_return_val_if_fail (dest != NULL, 0);
+ g_return_val_if_fail (src != NULL, 0);
+
+ return strlcat (dest, src, dest_size);
+}
+
+#else /* ! HAVE_STRLCPY */
+/* g_strlcpy
+ *
+ * Copy string src to buffer dest (of buffer size dest_size). At most
+ * dest_size-1 characters will be copied. Always NUL terminates
+ * (unless dest_size == 0). This function does NOT allocate memory.
+ * Unlike strncpy, this function doesn't pad dest (so it's often faster).
+ * Returns size of attempted result, strlen(src),
+ * so if retval >= dest_size, truncation occurred.
+ */
+gsize
+g_strlcpy (gchar *dest,
+ const gchar *src,
+ gsize dest_size)
+{
+ register gchar *d = dest;
+ register const gchar *s = src;
+ register gsize n = dest_size;
+
+ g_return_val_if_fail (dest != NULL, 0);
+ g_return_val_if_fail (src != NULL, 0);
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0)
+ do
+ {
+ register gchar c = *s++;
+
+ *d++ = c;
+ if (c == 0)
+ break;
+ }
+ while (--n != 0);
+
+ /* If not enough room in dest, add NUL and traverse rest of src */
+ if (n == 0)
+ {
+ if (dest_size != 0)
+ *d = 0;
+ while (*s++)
+ ;
+ }
+
+ return s - src - 1; /* count does not include NUL */
+}
+
+/* g_strlcat
+ *
+ * Appends string src to buffer dest (of buffer size dest_size).
+ * At most dest_size-1 characters will be copied.
+ * Unlike strncat, dest_size is the full size of dest, not the space left over.
+ * This function does NOT allocate memory.
+ * This always NUL terminates (unless siz == 0 or there were no NUL characters
+ * in the dest_size characters of dest to start with).
+ * Returns size of attempted result, which is
+ * MIN (dest_size, strlen (original dest)) + strlen (src),
+ * so if retval >= dest_size, truncation occurred.
+ */
+gsize
+g_strlcat (gchar *dest,
+ const gchar *src,
+ gsize dest_size)
+{
+ register gchar *d = dest;
+ register const gchar *s = src;
+ register gsize bytes_left = dest_size;
+ gsize dlength; /* Logically, MIN (strlen (d), dest_size) */
+
+ g_return_val_if_fail (dest != NULL, 0);
+ g_return_val_if_fail (src != NULL, 0);
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (*d != 0 && bytes_left-- != 0)
+ d++;
+ dlength = d - dest;
+ bytes_left = dest_size - dlength;
+
+ if (bytes_left == 0)
+ return dlength + strlen (s);
+
+ while (*s != 0)
+ {
+ if (bytes_left != 1)
+ {
+ *d++ = *s;
+ bytes_left--;
+ }
+ s++;
+ }
+ *d = 0;
+
+ return dlength + (s - src); /* count does not include NUL */
+}
+#endif /* ! HAVE_STRLCPY */
+
+/**
+ * g_ascii_strdown:
+ * @str: a string.
+ * @len: length of @str in bytes, or -1 if @str is nul-terminated.
+ *
+ * Converts all upper case ASCII letters to lower case ASCII letters.
+ *
+ * Return value: a newly-allocated string, with all the upper case
+ * characters in @str converted to lower case, with
+ * semantics that exactly match g_ascii_tolower(). (Note
+ * that this is unlike the old g_strdown(), which modified
+ * the string in place.)
+ **/
+gchar*
+g_ascii_strdown (const gchar *str,
+ gssize len)
+{
+ gchar *result, *s;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ if (len < 0)
+ len = strlen (str);
+
+ result = g_strndup (str, len);
+ for (s = result; *s; s++)
+ *s = g_ascii_tolower (*s);
+
+ return result;
+}
+
+/**
+ * g_ascii_strup:
+ * @str: a string.
+ * @len: length of @str in bytes, or -1 if @str is nul-terminated.
+ *
+ * Converts all lower case ASCII letters to upper case ASCII letters.
+ *
+ * Return value: a newly allocated string, with all the lower case
+ * characters in @str converted to upper case, with
+ * semantics that exactly match g_ascii_toupper(). (Note
+ * that this is unlike the old g_strup(), which modified
+ * the string in place.)
+ **/
+gchar*
+g_ascii_strup (const gchar *str,
+ gssize len)
+{
+ gchar *result, *s;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ if (len < 0)
+ len = strlen (str);
+
+ result = g_strndup (str, len);
+ for (s = result; *s; s++)
+ *s = g_ascii_toupper (*s);
+
+ return result;
+}
+
+/**
+ * g_strdown:
+ * @string: the string to convert.
+ *
+ * Converts a string to lower case.
+ *
+ * Return value: the string
+ *
+ * Deprecated:2.2: This function is totally broken for the reasons discussed
+ * in the g_strncasecmp() docs - use g_ascii_strdown() or g_utf8_strdown()
+ * instead.
+ **/
+gchar*
+g_strdown (gchar *string)
+{
+ register guchar *s;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ s = (guchar *) string;
+
+ while (*s)
+ {
+ if (isupper (*s))
+ *s = tolower (*s);
+ s++;
+ }
+
+ return (gchar *) string;
+}
+
+/**
+ * g_strup:
+ * @string: the string to convert.
+ *
+ * Converts a string to upper case.
+ *
+ * Return value: the string
+ *
+ * Deprecated:2.2: This function is totally broken for the reasons discussed
+ * in the g_strncasecmp() docs - use g_ascii_strup() or g_utf8_strup() instead.
+ **/
+gchar*
+g_strup (gchar *string)
+{
+ register guchar *s;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ s = (guchar *) string;
+
+ while (*s)
+ {
+ if (islower (*s))
+ *s = toupper (*s);
+ s++;
+ }
+
+ return (gchar *) string;
+}
+
+gchar*
+g_strreverse (gchar *string)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+
+ if (*string)
+ {
+ register gchar *h, *t;
+
+ h = string;
+ t = string + strlen (string) - 1;
+
+ while (h < t)
+ {
+ register gchar c;
+
+ c = *h;
+ *h = *t;
+ h++;
+ *t = c;
+ t--;
+ }
+ }
+
+ return string;
+}
+
+/**
+ * g_ascii_tolower:
+ * @c: any character.
+ *
+ * Convert a character to ASCII lower case.
+ *
+ * Unlike the standard C library tolower() function, this only
+ * recognizes standard ASCII letters and ignores the locale, returning
+ * all non-ASCII characters unchanged, even if they are lower case
+ * letters in a particular character set. Also unlike the standard
+ * library function, this takes and returns a char, not an int, so
+ * don't call it on %EOF but no need to worry about casting to #guchar
+ * before passing a possibly non-ASCII character in.
+ *
+ * Return value: the result of converting @c to lower case.
+ * If @c is not an ASCII upper case letter,
+ * @c is returned unchanged.
+ **/
+gchar
+g_ascii_tolower (gchar c)
+{
+ return g_ascii_isupper (c) ? c - 'A' + 'a' : c;
+}
+
+/**
+ * g_ascii_toupper:
+ * @c: any character.
+ *
+ * Convert a character to ASCII upper case.
+ *
+ * Unlike the standard C library toupper() function, this only
+ * recognizes standard ASCII letters and ignores the locale, returning
+ * all non-ASCII characters unchanged, even if they are upper case
+ * letters in a particular character set. Also unlike the standard
+ * library function, this takes and returns a char, not an int, so
+ * don't call it on %EOF but no need to worry about casting to #guchar
+ * before passing a possibly non-ASCII character in.
+ *
+ * Return value: the result of converting @c to upper case.
+ * If @c is not an ASCII lower case letter,
+ * @c is returned unchanged.
+ **/
+gchar
+g_ascii_toupper (gchar c)
+{
+ return g_ascii_islower (c) ? c - 'a' + 'A' : c;
+}
+
+/**
+ * g_ascii_digit_value:
+ * @c: an ASCII character.
+ *
+ * Determines the numeric value of a character as a decimal
+ * digit. Differs from g_unichar_digit_value() because it takes
+ * a char, so there's no worry about sign extension if characters
+ * are signed.
+ *
+ * Return value: If @c is a decimal digit (according to
+ * g_ascii_isdigit()), its numeric value. Otherwise, -1.
+ **/
+int
+g_ascii_digit_value (gchar c)
+{
+ if (g_ascii_isdigit (c))
+ return c - '0';
+ return -1;
+}
+
+/**
+ * g_ascii_xdigit_value:
+ * @c: an ASCII character.
+ *
+ * Determines the numeric value of a character as a hexidecimal
+ * digit. Differs from g_unichar_xdigit_value() because it takes
+ * a char, so there's no worry about sign extension if characters
+ * are signed.
+ *
+ * Return value: If @c is a hex digit (according to
+ * g_ascii_isxdigit()), its numeric value. Otherwise, -1.
+ **/
+int
+g_ascii_xdigit_value (gchar c)
+{
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return g_ascii_digit_value (c);
+}
+
+/**
+ * g_ascii_strcasecmp:
+ * @s1: string to compare with @s2.
+ * @s2: string to compare with @s1.
+ *
+ * Compare two strings, ignoring the case of ASCII characters.
+ *
+ * Unlike the BSD strcasecmp() function, this only recognizes standard
+ * ASCII letters and ignores the locale, treating all non-ASCII
+ * bytes as if they are not letters.
+ *
+ * This function should be used only on strings that are known to be
+ * in encodings where the bytes corresponding to ASCII letters always
+ * represent themselves. This includes UTF-8 and the ISO-8859-*
+ * charsets, but not for instance double-byte encodings like the
+ * Windows Codepage 932, where the trailing bytes of double-byte
+ * characters include all ASCII letters. If you compare two CP932
+ * strings using this function, you will get false matches.
+ *
+ * Return value: 0 if the strings match, a negative value if @s1 &lt; @s2,
+ * or a positive value if @s1 &gt; @s2.
+ **/
+gint
+g_ascii_strcasecmp (const gchar *s1,
+ const gchar *s2)
+{
+ gint c1, c2;
+
+ g_return_val_if_fail (s1 != NULL, 0);
+ g_return_val_if_fail (s2 != NULL, 0);
+
+ while (*s1 && *s2)
+ {
+ c1 = (gint)(guchar) TOLOWER (*s1);
+ c2 = (gint)(guchar) TOLOWER (*s2);
+ if (c1 != c2)
+ return (c1 - c2);
+ s1++; s2++;
+ }
+
+ return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
+}
+
+/**
+ * g_ascii_strncasecmp:
+ * @s1: string to compare with @s2.
+ * @s2: string to compare with @s1.
+ * @n: number of characters to compare.
+ *
+ * Compare @s1 and @s2, ignoring the case of ASCII characters and any
+ * characters after the first @n in each string.
+ *
+ * Unlike the BSD strcasecmp() function, this only recognizes standard
+ * ASCII letters and ignores the locale, treating all non-ASCII
+ * characters as if they are not letters.
+ *
+ * The same warning as in g_ascii_strcasecmp() applies: Use this
+ * function only on strings known to be in encodings where bytes
+ * corresponding to ASCII letters always represent themselves.
+ *
+ * Return value: 0 if the strings match, a negative value if @s1 &lt; @s2,
+ * or a positive value if @s1 &gt; @s2.
+ **/
+gint
+g_ascii_strncasecmp (const gchar *s1,
+ const gchar *s2,
+ gsize n)
+{
+ gint c1, c2;
+
+ g_return_val_if_fail (s1 != NULL, 0);
+ g_return_val_if_fail (s2 != NULL, 0);
+
+ while (n && *s1 && *s2)
+ {
+ n -= 1;
+ c1 = (gint)(guchar) TOLOWER (*s1);
+ c2 = (gint)(guchar) TOLOWER (*s2);
+ if (c1 != c2)
+ return (c1 - c2);
+ s1++; s2++;
+ }
+
+ if (n)
+ return (((gint) (guchar) *s1) - ((gint) (guchar) *s2));
+ else
+ return 0;
+}
+
+/**
+ * g_strcasecmp:
+ * @s1: a string.
+ * @s2: a string to compare with @s1.
+ *
+ * A case-insensitive string comparison, corresponding to the standard
+ * strcasecmp() function on platforms which support it.
+ *
+ * Return value: 0 if the strings match, a negative value if @s1 &lt; @s2,
+ * or a positive value if @s1 &gt; @s2.
+ *
+ * Deprecated:2.2: See g_strncasecmp() for a discussion of why this function
+ * is deprecated and how to replace it.
+ **/
+gint
+g_strcasecmp (const gchar *s1,
+ const gchar *s2)
+{
+#ifdef HAVE_STRCASECMP
+ g_return_val_if_fail (s1 != NULL, 0);
+ g_return_val_if_fail (s2 != NULL, 0);
+
+ return strcasecmp (s1, s2);
+#else
+ gint c1, c2;
+
+ g_return_val_if_fail (s1 != NULL, 0);
+ g_return_val_if_fail (s2 != NULL, 0);
+
+ while (*s1 && *s2)
+ {
+ /* According to A. Cox, some platforms have islower's that
+ * don't work right on non-uppercase
+ */
+ c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1;
+ c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2;
+ if (c1 != c2)
+ return (c1 - c2);
+ s1++; s2++;
+ }
+
+ return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
+#endif
+}
+
+/**
+ * g_strncasecmp:
+ * @s1: a string.
+ * @s2: a string to compare with @s1.
+ * @n: the maximum number of characters to compare.
+ *
+ * A case-insensitive string comparison, corresponding to the standard
+ * strncasecmp() function on platforms which support it.
+ * It is similar to g_strcasecmp() except it only compares the first @n
+ * characters of the strings.
+ *
+ * Return value: 0 if the strings match, a negative value if @s1 &lt; @s2,
+ * or a positive value if @s1 &gt; @s2.
+ *
+ * Deprecated:2.2: The problem with g_strncasecmp() is that it does the
+ * comparison by calling toupper()/tolower(). These functions are
+ * locale-specific and operate on single bytes. However, it is impossible
+ * to handle things correctly from an I18N standpoint by operating on
+ * bytes, since characters may be multibyte. Thus g_strncasecmp() is
+ * broken if your string is guaranteed to be ASCII, since it's
+ * locale-sensitive, and it's broken if your string is localized, since
+ * it doesn't work on many encodings at all, including UTF-8, EUC-JP,
+ * etc.
+ *
+ * There are therefore two replacement functions: g_ascii_strncasecmp(),
+ * which only works on ASCII and is not locale-sensitive, and
+ * g_utf8_casefold(), which is good for case-insensitive sorting of UTF-8.
+ **/
+gint
+g_strncasecmp (const gchar *s1,
+ const gchar *s2,
+ guint n)
+{
+#ifdef HAVE_STRNCASECMP
+ return strncasecmp (s1, s2, n);
+#else
+ gint c1, c2;
+
+ g_return_val_if_fail (s1 != NULL, 0);
+ g_return_val_if_fail (s2 != NULL, 0);
+
+ while (n && *s1 && *s2)
+ {
+ n -= 1;
+ /* According to A. Cox, some platforms have islower's that
+ * don't work right on non-uppercase
+ */
+ c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1;
+ c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2;
+ if (c1 != c2)
+ return (c1 - c2);
+ s1++; s2++;
+ }
+
+ if (n)
+ return (((gint) (guchar) *s1) - ((gint) (guchar) *s2));
+ else
+ return 0;
+#endif
+}
+
+gchar*
+g_strdelimit (gchar *string,
+ const gchar *delimiters,
+ gchar new_delim)
+{
+ register gchar *c;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ if (!delimiters)
+ delimiters = G_STR_DELIMITERS;
+
+ for (c = string; *c; c++)
+ {
+ if (strchr (delimiters, *c))
+ *c = new_delim;
+ }
+
+ return string;
+}
+
+gchar*
+g_strcanon (gchar *string,
+ const gchar *valid_chars,
+ gchar substitutor)
+{
+ register gchar *c;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (valid_chars != NULL, NULL);
+
+ for (c = string; *c; c++)
+ {
+ if (!strchr (valid_chars, *c))
+ *c = substitutor;
+ }
+
+ return string;
+}
+
+gchar*
+g_strcompress (const gchar *source)
+{
+ const gchar *p = source, *octal;
+ gchar *dest = g_malloc (strlen (source) + 1);
+ gchar *q = dest;
+
+ while (*p)
+ {
+ if (*p == '\\')
+ {
+ p++;
+ switch (*p)
+ {
+ case '\0':
+#if NOT_NEEDED_FOR_NAVIT
+ g_warning ("g_strcompress: trailing \\");
+#endif /* NOT_NEEDED_FOR_NAVIT */
+ goto out;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ *q = 0;
+ octal = p;
+ while ((p < octal + 3) && (*p >= '0') && (*p <= '7'))
+ {
+ *q = (*q * 8) + (*p - '0');
+ p++;
+ }
+ q++;
+ p--;
+ break;
+ case 'b':
+ *q++ = '\b';
+ break;
+ case 'f':
+ *q++ = '\f';
+ break;
+ case 'n':
+ *q++ = '\n';
+ break;
+ case 'r':
+ *q++ = '\r';
+ break;
+ case 't':
+ *q++ = '\t';
+ break;
+ default: /* Also handles \" and \\ */
+ *q++ = *p;
+ break;
+ }
+ }
+ else
+ *q++ = *p;
+ p++;
+ }
+out:
+ *q = 0;
+
+ return dest;
+}
+
+gchar *
+g_strescape (const gchar *source,
+ const gchar *exceptions)
+{
+ const guchar *p;
+ gchar *dest;
+ gchar *q;
+ guchar excmap[256];
+
+ g_return_val_if_fail (source != NULL, NULL);
+
+ p = (guchar *) source;
+ /* Each source byte needs maximally four destination chars (\777) */
+ q = dest = g_malloc (strlen (source) * 4 + 1);
+
+ memset (excmap, 0, 256);
+ if (exceptions)
+ {
+ guchar *e = (guchar *) exceptions;
+
+ while (*e)
+ {
+ excmap[*e] = 1;
+ e++;
+ }
+ }
+
+ while (*p)
+ {
+ if (excmap[*p])
+ *q++ = *p;
+ else
+ {
+ switch (*p)
+ {
+ case '\b':
+ *q++ = '\\';
+ *q++ = 'b';
+ break;
+ case '\f':
+ *q++ = '\\';
+ *q++ = 'f';
+ break;
+ case '\n':
+ *q++ = '\\';
+ *q++ = 'n';
+ break;
+ case '\r':
+ *q++ = '\\';
+ *q++ = 'r';
+ break;
+ case '\t':
+ *q++ = '\\';
+ *q++ = 't';
+ break;
+ case '\\':
+ *q++ = '\\';
+ *q++ = '\\';
+ break;
+ case '"':
+ *q++ = '\\';
+ *q++ = '"';
+ break;
+ default:
+ if ((*p < ' ') || (*p >= 0177))
+ {
+ *q++ = '\\';
+ *q++ = '0' + (((*p) >> 6) & 07);
+ *q++ = '0' + (((*p) >> 3) & 07);
+ *q++ = '0' + ((*p) & 07);
+ }
+ else
+ *q++ = *p;
+ break;
+ }
+ }
+ p++;
+ }
+ *q = 0;
+ return dest;
+}
+
+gchar*
+g_strchug (gchar *string)
+{
+ guchar *start;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ for (start = (guchar*) string; *start && g_ascii_isspace (*start); start++)
+ ;
+
+ g_memmove (string, start, strlen ((gchar *) start) + 1);
+
+ return string;
+}
+
+gchar*
+g_strchomp (gchar *string)
+{
+ gsize len;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ len = strlen (string);
+ while (len--)
+ {
+ if (g_ascii_isspace ((guchar) string[len]))
+ string[len] = '\0';
+ else
+ break;
+ }
+
+ return string;
+}
+
+#if NOT_NEEDED_FOR_NAVIT
+/**
+ * g_strsplit:
+ * @string: a string to split.
+ * @delimiter: a string which specifies the places at which to split the string.
+ * The delimiter is not included in any of the resulting strings, unless
+ * @max_tokens is reached.
+ * @max_tokens: the maximum number of pieces to split @string into. If this is
+ * less than 1, the string is split completely.
+ *
+ * Splits a string into a maximum of @max_tokens pieces, using the given
+ * @delimiter. If @max_tokens is reached, the remainder of @string is appended
+ * to the last token.
+ *
+ * As a special case, the result of splitting the empty string "" is an empty
+ * vector, not a vector containing a single string. The reason for this
+ * special case is that being able to represent a empty vector is typically
+ * more useful than consistent handling of empty elements. If you do need
+ * to represent empty elements, you'll need to check for the empty string
+ * before calling g_strsplit().
+ *
+ * Return value: a newly-allocated %NULL-terminated array of strings. Use
+ * g_strfreev() to free it.
+ **/
+gchar**
+g_strsplit (const gchar *string,
+ const gchar *delimiter,
+ gint max_tokens)
+{
+ GSList *string_list = NULL, *slist;
+ gchar **str_array, *s;
+ guint n = 0;
+ const gchar *remainder;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (delimiter != NULL, NULL);
+ g_return_val_if_fail (delimiter[0] != '\0', NULL);
+
+ if (max_tokens < 1)
+ max_tokens = G_MAXINT;
+
+ remainder = string;
+ s = strstr (remainder, delimiter);
+ if (s)
+ {
+ gsize delimiter_len = strlen (delimiter);
+
+ while (--max_tokens && s)
+ {
+ gsize len;
+
+ len = s - remainder;
+ string_list = g_slist_prepend (string_list,
+ g_strndup (remainder, len));
+ n++;
+ remainder = s + delimiter_len;
+ s = strstr (remainder, delimiter);
+ }
+ }
+ if (*string)
+ {
+ n++;
+ string_list = g_slist_prepend (string_list, g_strdup (remainder));
+ }
+
+ str_array = g_new (gchar*, n + 1);
+
+ str_array[n--] = NULL;
+ for (slist = string_list; slist; slist = slist->next)
+ str_array[n--] = slist->data;
+
+ g_slist_free (string_list);
+
+ return str_array;
+}
+
+/**
+ * g_strsplit_set:
+ * @string: The string to be tokenized
+ * @delimiters: A nul-terminated string containing bytes that are used
+ * to split the string.
+ * @max_tokens: The maximum number of tokens to split @string into.
+ * If this is less than 1, the string is split completely
+ *
+ * Splits @string into a number of tokens not containing any of the characters
+ * in @delimiter. A token is the (possibly empty) longest string that does not
+ * contain any of the characters in @delimiters. If @max_tokens is reached, the
+ * remainder is appended to the last token.
+ *
+ * For example the result of g_strsplit_set ("abc:def/ghi", ":/", -1) is a
+ * %NULL-terminated vector containing the three strings "abc", "def",
+ * and "ghi".
+ *
+ * The result if g_strsplit_set (":def/ghi:", ":/", -1) is a %NULL-terminated
+ * vector containing the four strings "", "def", "ghi", and "".
+ *
+ * As a special case, the result of splitting the empty string "" is an empty
+ * vector, not a vector containing a single string. The reason for this
+ * special case is that being able to represent a empty vector is typically
+ * more useful than consistent handling of empty elements. If you do need
+ * to represent empty elements, you'll need to check for the empty string
+ * before calling g_strsplit_set().
+ *
+ * Note that this function works on bytes not characters, so it can't be used
+ * to delimit UTF-8 strings for anything but ASCII characters.
+ *
+ * Return value: a newly-allocated %NULL-terminated array of strings. Use
+ * g_strfreev() to free it.
+ *
+ * Since: 2.4
+ **/
+gchar **
+g_strsplit_set (const gchar *string,
+ const gchar *delimiters,
+ gint max_tokens)
+{
+ gboolean delim_table[256];
+ GSList *tokens, *list;
+ gint n_tokens;
+ const gchar *s;
+ const gchar *current;
+ gchar *token;
+ gchar **result;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (delimiters != NULL, NULL);
+
+ if (max_tokens < 1)
+ max_tokens = G_MAXINT;
+
+ if (*string == '\0')
+ {
+ result = g_new (char *, 1);
+ result[0] = NULL;
+ return result;
+ }
+
+ memset (delim_table, FALSE, sizeof (delim_table));
+ for (s = delimiters; *s != '\0'; ++s)
+ delim_table[*(guchar *)s] = TRUE;
+
+ tokens = NULL;
+ n_tokens = 0;
+
+ s = current = string;
+ while (*s != '\0')
+ {
+ if (delim_table[*(guchar *)s] && n_tokens + 1 < max_tokens)
+ {
+ gchar *token;
+
+ token = g_strndup (current, s - current);
+ tokens = g_slist_prepend (tokens, token);
+ ++n_tokens;
+
+ current = s + 1;
+ }
+
+ ++s;
+ }
+
+ token = g_strndup (current, s - current);
+ tokens = g_slist_prepend (tokens, token);
+ ++n_tokens;
+
+ result = g_new (gchar *, n_tokens + 1);
+
+ result[n_tokens] = NULL;
+ for (list = tokens; list != NULL; list = list->next)
+ result[--n_tokens] = list->data;
+
+ g_slist_free (tokens);
+
+ return result;
+}
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+/**
+ * g_strfreev:
+ * @str_array: a %NULL-terminated array of strings to free.
+
+ * Frees a %NULL-terminated array of strings, and the array itself.
+ * If called on a %NULL value, g_strfreev() simply returns.
+ **/
+void
+g_strfreev (gchar **str_array)
+{
+ if (str_array)
+ {
+ int i;
+
+ for (i = 0; str_array[i] != NULL; i++)
+ g_free (str_array[i]);
+
+ g_free (str_array);
+ }
+}
+
+/**
+ * g_strdupv:
+ * @str_array: %NULL-terminated array of strings.
+ *
+ * Copies %NULL-terminated array of strings. The copy is a deep copy;
+ * the new array should be freed by first freeing each string, then
+ * the array itself. g_strfreev() does this for you. If called
+ * on a %NULL value, g_strdupv() simply returns %NULL.
+ *
+ * Return value: a new %NULL-terminated array of strings.
+ **/
+gchar**
+g_strdupv (gchar **str_array)
+{
+ if (str_array)
+ {
+ gint i;
+ gchar **retval;
+
+ i = 0;
+ while (str_array[i])
+ ++i;
+
+ retval = g_new (gchar*, i + 1);
+
+ i = 0;
+ while (str_array[i])
+ {
+ retval[i] = g_strdup (str_array[i]);
+ ++i;
+ }
+ retval[i] = NULL;
+
+ return retval;
+ }
+ else
+ return NULL;
+}
+
+gchar*
+g_strjoinv (const gchar *separator,
+ gchar **str_array)
+{
+ gchar *string;
+ gchar *ptr;
+
+ g_return_val_if_fail (str_array != NULL, NULL);
+
+ if (separator == NULL)
+ separator = "";
+
+ if (*str_array)
+ {
+ gint i;
+ gsize len;
+ gsize separator_len;
+
+ separator_len = strlen (separator);
+ /* First part, getting length */
+ len = 1 + strlen (str_array[0]);
+ for (i = 1; str_array[i] != NULL; i++)
+ len += strlen (str_array[i]);
+ len += separator_len * (i - 1);
+
+ /* Second part, building string */
+ string = g_new (gchar, len);
+ ptr = g_stpcpy (string, *str_array);
+ for (i = 1; str_array[i] != NULL; i++)
+ {
+ ptr = g_stpcpy (ptr, separator);
+ ptr = g_stpcpy (ptr, str_array[i]);
+ }
+ }
+ else
+ string = g_strdup ("");
+
+ return string;
+}
+
+gchar*
+g_strjoin (const gchar *separator,
+ ...)
+{
+ gchar *string, *s;
+ va_list args;
+ gsize len;
+ gsize separator_len;
+ gchar *ptr;
+
+ if (separator == NULL)
+ separator = "";
+
+ separator_len = strlen (separator);
+
+ va_start (args, separator);
+
+ s = va_arg (args, gchar*);
+
+ if (s)
+ {
+ /* First part, getting length */
+ len = 1 + strlen (s);
+
+ s = va_arg (args, gchar*);
+ while (s)
+ {
+ len += separator_len + strlen (s);
+ s = va_arg (args, gchar*);
+ }
+ va_end (args);
+
+ /* Second part, building string */
+ string = g_new (gchar, len);
+
+ va_start (args, separator);
+
+ s = va_arg (args, gchar*);
+ ptr = g_stpcpy (string, s);
+
+ s = va_arg (args, gchar*);
+ while (s)
+ {
+ ptr = g_stpcpy (ptr, separator);
+ ptr = g_stpcpy (ptr, s);
+ s = va_arg (args, gchar*);
+ }
+ }
+ else
+ string = g_strdup ("");
+
+ va_end (args);
+
+ return string;
+}
+
+#if NOT_NEEDED_FOR_NAVIT
+
+/**
+ * g_strstr_len:
+ * @haystack: a string.
+ * @haystack_len: the maximum length of @haystack. Note that -1 is
+ * a valid length, if @haystack is nul-terminated, meaning it will
+ * search through the whole string.
+ * @needle: the string to search for.
+ *
+ * Searches the string @haystack for the first occurrence
+ * of the string @needle, limiting the length of the search
+ * to @haystack_len.
+ *
+ * Return value: a pointer to the found occurrence, or
+ * %NULL if not found.
+ **/
+gchar *
+g_strstr_len (const gchar *haystack,
+ gssize haystack_len,
+ const gchar *needle)
+{
+ g_return_val_if_fail (haystack != NULL, NULL);
+ g_return_val_if_fail (needle != NULL, NULL);
+
+ if (haystack_len < 0)
+ return strstr (haystack, needle);
+ else
+ {
+ const gchar *p = haystack;
+ gsize needle_len = strlen (needle);
+ const gchar *end;
+ gsize i;
+
+ if (needle_len == 0)
+ return (gchar *)haystack;
+
+ if (haystack_len < needle_len)
+ return NULL;
+
+ end = haystack + haystack_len - needle_len;
+
+ while (p <= end && *p)
+ {
+ for (i = 0; i < needle_len; i++)
+ if (p[i] != needle[i])
+ goto next;
+
+ return (gchar *)p;
+
+ next:
+ p++;
+ }
+
+ return NULL;
+ }
+}
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+/**
+ * g_strrstr:
+ * @haystack: a nul-terminated string.
+ * @needle: the nul-terminated string to search for.
+ *
+ * Searches the string @haystack for the last occurrence
+ * of the string @needle.
+ *
+ * Return value: a pointer to the found occurrence, or
+ * %NULL if not found.
+ **/
+gchar *
+g_strrstr (const gchar *haystack,
+ const gchar *needle)
+{
+ gsize i;
+ gsize needle_len;
+ gsize haystack_len;
+ const gchar *p;
+
+ g_return_val_if_fail (haystack != NULL, NULL);
+ g_return_val_if_fail (needle != NULL, NULL);
+
+ needle_len = strlen (needle);
+ haystack_len = strlen (haystack);
+
+ if (needle_len == 0)
+ return (gchar *)haystack;
+
+ if (haystack_len < needle_len)
+ return NULL;
+
+ p = haystack + haystack_len - needle_len;
+
+ while (p >= haystack)
+ {
+ for (i = 0; i < needle_len; i++)
+ if (p[i] != needle[i])
+ goto next;
+
+ return (gchar *)p;
+
+ next:
+ p--;
+ }
+
+ return NULL;
+}
+
+#if NOT_NEEDED_FOR_NAVIT
+/**
+ * g_strrstr_len:
+ * @haystack: a nul-terminated string.
+ * @haystack_len: the maximum length of @haystack.
+ * @needle: the nul-terminated string to search for.
+ *
+ * Searches the string @haystack for the last occurrence
+ * of the string @needle, limiting the length of the search
+ * to @haystack_len.
+ *
+ * Return value: a pointer to the found occurrence, or
+ * %NULL if not found.
+ **/
+gchar *
+g_strrstr_len (const gchar *haystack,
+ gssize haystack_len,
+ const gchar *needle)
+{
+ g_return_val_if_fail (haystack != NULL, NULL);
+ g_return_val_if_fail (needle != NULL, NULL);
+
+ if (haystack_len < 0)
+ return g_strrstr (haystack, needle);
+ else
+ {
+ gsize needle_len = strlen (needle);
+ const gchar *haystack_max = haystack + haystack_len;
+ const gchar *p = haystack;
+ gsize i;
+
+ while (p < haystack_max && *p)
+ p++;
+
+ if (p < haystack + needle_len)
+ return NULL;
+
+ p -= needle_len;
+
+ while (p >= haystack)
+ {
+ for (i = 0; i < needle_len; i++)
+ if (p[i] != needle[i])
+ goto next;
+
+ return (gchar *)p;
+
+ next:
+ p--;
+ }
+
+ return NULL;
+ }
+}
+
+
+/**
+ * g_str_has_suffix:
+ * @str: a nul-terminated string.
+ * @suffix: the nul-terminated suffix to look for.
+ *
+ * Looks whether the string @str ends with @suffix.
+ *
+ * Return value: %TRUE if @str end with @suffix, %FALSE otherwise.
+ *
+ * Since: 2.2
+ **/
+gboolean
+g_str_has_suffix (const gchar *str,
+ const gchar *suffix)
+{
+ int str_len;
+ int suffix_len;
+
+ g_return_val_if_fail (str != NULL, FALSE);
+ g_return_val_if_fail (suffix != NULL, FALSE);
+
+ str_len = strlen (str);
+ suffix_len = strlen (suffix);
+
+ if (str_len < suffix_len)
+ return FALSE;
+
+ return strcmp (str + str_len - suffix_len, suffix) == 0;
+}
+
+/**
+ * g_str_has_prefix:
+ * @str: a nul-terminated string.
+ * @prefix: the nul-terminated prefix to look for.
+ *
+ * Looks whether the string @str begins with @prefix.
+ *
+ * Return value: %TRUE if @str begins with @prefix, %FALSE otherwise.
+ *
+ * Since: 2.2
+ **/
+gboolean
+g_str_has_prefix (const gchar *str,
+ const gchar *prefix)
+{
+ int str_len;
+ int prefix_len;
+
+ g_return_val_if_fail (str != NULL, FALSE);
+ g_return_val_if_fail (prefix != NULL, FALSE);
+
+ str_len = strlen (str);
+ prefix_len = strlen (prefix);
+
+ if (str_len < prefix_len)
+ return FALSE;
+
+ return strncmp (str, prefix, prefix_len) == 0;
+}
+
+
+/**
+ * g_strip_context:
+ * @msgid: a string
+ * @msgval: another string
+ *
+ * An auxiliary function for gettext() support (see Q_()).
+ *
+ * Return value: @msgval, unless @msgval is identical to @msgid and contains
+ * a '|' character, in which case a pointer to the substring of msgid after
+ * the first '|' character is returned.
+ *
+ * Since: 2.4
+ **/
+G_CONST_RETURN gchar *
+g_strip_context (const gchar *msgid,
+ const gchar *msgval)
+{
+ if (msgval == msgid)
+ {
+ const char *c = strchr (msgid, '|');
+ if (c != NULL)
+ return c + 1;
+ }
+
+ return msgval;
+}
+
+
+/**
+ * g_strv_length:
+ * @str_array: a %NULL-terminated array of strings.
+ *
+ * Returns the length of the given %NULL-terminated
+ * string array @str_array.
+ *
+ * Return value: length of @str_array.
+ *
+ * Since: 2.6
+ **/
+guint
+g_strv_length (gchar **str_array)
+{
+ guint i = 0;
+
+ g_return_val_if_fail (str_array != NULL, 0);
+
+ while (str_array[i])
+ ++i;
+
+ return i;
+}
+
+
+/**
+ * g_dpgettext:
+ * @domain: the translation domain to use, or %NULL to use
+ * the domain set with textdomain()
+ * @msgctxtid: a combined message context and message id, separated
+ * by a \004 character
+ * @msgidoffset: the offset of the message id in @msgctxid
+ *
+ * This function is a variant of g_dgettext() which supports
+ * a disambiguating message context. GNU gettext uses the
+ * '\004' character to separate the message context and
+ * message id in @msgctxtid.
+ * If 0 is passed as @msgidoffset, this function will fall back to
+ * trying to use the deprecated convention of using "|" as a separation
+ * character.
+ *
+ * This uses g_dgettext() internally. See that functions for differences
+ * with dgettext() proper.
+ *
+ * Applications should normally not use this function directly,
+ * but use the C_() macro for translations with context.
+ *
+ * Returns: The translated string
+ *
+ * Since: 2.16
+ */
+G_CONST_RETURN gchar *
+g_dpgettext (const gchar *domain,
+ const gchar *msgctxtid,
+ gsize msgidoffset)
+{
+ const gchar *translation;
+ gchar *sep;
+
+ translation = g_dgettext (domain, msgctxtid);
+
+ if (translation == msgctxtid)
+ {
+ if (msgidoffset > 0)
+ return msgctxtid + msgidoffset;
+
+ sep = strchr (msgctxtid, '|');
+
+ if (sep)
+ {
+ /* try with '\004' instead of '|', in case
+ * xgettext -kQ_:1g was used
+ */
+ gchar *tmp = g_alloca (strlen (msgctxtid) + 1);
+ strcpy (tmp, msgctxtid);
+ tmp[sep - msgctxtid] = '\004';
+
+ translation = g_dgettext (domain, tmp);
+
+ if (translation == tmp)
+ return sep + 1;
+ }
+ }
+
+ return translation;
+}
+
+/* This function is taken from gettext.h
+ * GNU gettext uses '\004' to separate context and msgid in .mo files.
+ */
+/**
+ * g_dpgettext2:
+ * @domain: the translation domain to use, or %NULL to use
+ * the domain set with textdomain()
+ * @context: the message context
+ * @msgid: the message
+ *
+ * This function is a variant of g_dgettext() which supports
+ * a disambiguating message context. GNU gettext uses the
+ * '\004' character to separate the message context and
+ * message id in @msgctxtid.
+ *
+ * This uses g_dgettext() internally. See that functions for differences
+ * with dgettext() proper.
+ *
+ * This function differs from C_() in that it is not a macro and
+ * thus you may use non-string-literals as context and msgid arguments.
+ *
+ * Returns: The translated string
+ *
+ * Since: 2.18
+ */
+G_CONST_RETURN char *
+g_dpgettext2 (const char *domain,
+ const char *msgctxt,
+ const char *msgid)
+{
+ size_t msgctxt_len = strlen (msgctxt) + 1;
+ size_t msgid_len = strlen (msgid) + 1;
+ const char *translation;
+ char* msg_ctxt_id;
+
+ msg_ctxt_id = g_alloca (msgctxt_len + msgid_len);
+
+ 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 = g_dgettext (domain, msg_ctxt_id);
+
+ if (translation == msg_ctxt_id)
+ {
+ /* try the old way of doing message contexts, too */
+ msg_ctxt_id[msgctxt_len - 1] = '|';
+ translation = g_dgettext (domain, msg_ctxt_id);
+
+ if (translation == msg_ctxt_id)
+ return msgid;
+ }
+
+ return translation;
+}
+
+static gboolean
+_g_dgettext_should_translate (void)
+{
+ static gsize translate = 0;
+ enum {
+ SHOULD_TRANSLATE = 1,
+ SHOULD_NOT_TRANSLATE = 2
+ };
+
+ if (G_UNLIKELY (g_once_init_enter (&translate)))
+ {
+ gboolean should_translate = TRUE;
+
+ const char *default_domain = textdomain (NULL);
+ const char *translator_comment = gettext ("");
+#ifndef G_OS_WIN32
+ const char *translate_locale = setlocale (LC_MESSAGES, NULL);
+#else
+ const char *translate_locale = g_win32_getlocale ();
+#endif
+ /* We should NOT translate only if all the following hold:
+ * - user has called textdomain() and set textdomain to non-default
+ * - default domain has no translations
+ * - locale does not start with "en_" and is not "C"
+ *
+ * Rationale:
+ * - If text domain is still the default domain, maybe user calls
+ * it later. Continue with old behavior of translating.
+ * - If locale starts with "en_", we can continue using the
+ * translations even if the app doesn't have translations for
+ * this locale. That is, en_UK and en_CA for example.
+ * - If locale is "C", maybe user calls setlocale(LC_ALL,"") later.
+ * Continue with old behavior of translating.
+ */
+ if (0 != strcmp (default_domain, "messages") &&
+ '\0' == *translator_comment &&
+ 0 != strncmp (translate_locale, "en_", 3) &&
+ 0 != strcmp (translate_locale, "C"))
+ should_translate = FALSE;
+
+ g_once_init_leave (&translate,
+ should_translate ?
+ SHOULD_TRANSLATE :
+ SHOULD_NOT_TRANSLATE);
+ }
+
+ return translate == SHOULD_TRANSLATE;
+}
+
+/**
+ * g_dgettext:
+ * @domain: the translation domain to use, or %NULL to use
+ * the domain set with textdomain()
+ * @msgid: message to translate
+ *
+ * This function is a wrapper of dgettext() which does not translate
+ * the message if the default domain as set with textdomain() has no
+ * translations for the current locale.
+ *
+ * The advantage of using this function over dgettext() proper is that
+ * libraries using this function (like GTK+) will not use translations
+ * if the application using the library does not have translations for
+ * the current locale. This results in a consistent English-only
+ * interface instead of one having partial translations. For this
+ * feature to work, the call to textdomain() and setlocale() should
+ * precede any g_dgettext() invocations. For GTK+, it means calling
+ * textdomain() before gtk_init or its variants.
+ *
+ * This function disables translations if and only if upon its first
+ * call all the following conditions hold:
+ * <itemizedlist>
+ * <listitem>@domain is not %NULL</listitem>
+ * <listitem>textdomain() has been called to set a default text domain</listitem>
+ * <listitem>there is no translations available for the default text domain
+ * and the current locale</listitem>
+ * <listitem>current locale is not "C" or any English locales (those
+ * starting with "en_")</listitem>
+ * </itemizedlist>
+ *
+ * Note that this behavior may not be desired for example if an application
+ * has its untranslated messages in a language other than English. In those
+ * cases the application should call textdomain() after initializing GTK+.
+ *
+ * Applications should normally not use this function directly,
+ * but use the _() macro for translations.
+ *
+ * Returns: The translated string
+ *
+ * Since: 2.18
+ */
+G_CONST_RETURN gchar *
+g_dgettext (const gchar *domain,
+ const gchar *msgid)
+{
+ if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
+ return msgid;
+
+ return dgettext (domain, msgid);
+}
+
+/**
+ * g_dngettext:
+ * @domain: the translation domain to use, or %NULL to use
+ * the domain set with textdomain()
+ * @msgid: message to translate
+ * @msgid_plural: plural form of the message
+ * @n: the quantity for which translation is needed
+ *
+ * This function is a wrapper of dngettext() which does not translate
+ * the message if the default domain as set with textdomain() has no
+ * translations for the current locale.
+ *
+ * See g_dgettext() for details of how this differs from dngettext()
+ * proper.
+ *
+ * Returns: The translated string
+ *
+ * Since: 2.18
+ */
+G_CONST_RETURN gchar *
+g_dngettext (const gchar *domain,
+ const gchar *msgid,
+ const gchar *msgid_plural,
+ gulong n)
+{
+ if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
+ return n == 1 ? msgid : msgid_plural;
+
+ return dngettext (domain, msgid, msgid_plural, n);
+}
+
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+#define __G_STRFUNCS_C__
+#include "galiasdef.c"
diff --git a/support/glib/gstrfuncs.h b/support/glib/gstrfuncs.h
new file mode 100644
index 00000000..ee291f80
--- /dev/null
+++ b/support/glib/gstrfuncs.h
@@ -0,0 +1,266 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_STRFUNCS_H__
+#define __G_STRFUNCS_H__
+
+#include <stdarg.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/* Functions like the ones in <ctype.h> that are not affected by locale. */
+typedef enum {
+ G_ASCII_ALNUM = 1 << 0,
+ G_ASCII_ALPHA = 1 << 1,
+ G_ASCII_CNTRL = 1 << 2,
+ G_ASCII_DIGIT = 1 << 3,
+ G_ASCII_GRAPH = 1 << 4,
+ G_ASCII_LOWER = 1 << 5,
+ G_ASCII_PRINT = 1 << 6,
+ G_ASCII_PUNCT = 1 << 7,
+ G_ASCII_SPACE = 1 << 8,
+ G_ASCII_UPPER = 1 << 9,
+ G_ASCII_XDIGIT = 1 << 10
+} GAsciiType;
+
+GLIB_VAR const guint16 * const g_ascii_table;
+
+#define g_ascii_isalnum(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_ALNUM) != 0)
+
+#define g_ascii_isalpha(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_ALPHA) != 0)
+
+#define g_ascii_iscntrl(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_CNTRL) != 0)
+
+#define g_ascii_isdigit(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_DIGIT) != 0)
+
+#define g_ascii_isgraph(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_GRAPH) != 0)
+
+#define g_ascii_islower(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_LOWER) != 0)
+
+#define g_ascii_isprint(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_PRINT) != 0)
+
+#define g_ascii_ispunct(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_PUNCT) != 0)
+
+#define g_ascii_isspace(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_SPACE) != 0)
+
+#define g_ascii_isupper(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_UPPER) != 0)
+
+#define g_ascii_isxdigit(c) \
+ ((g_ascii_table[(guchar) (c)] & G_ASCII_XDIGIT) != 0)
+
+gchar g_ascii_tolower (gchar c) G_GNUC_CONST;
+gchar g_ascii_toupper (gchar c) G_GNUC_CONST;
+
+gint g_ascii_digit_value (gchar c) G_GNUC_CONST;
+gint g_ascii_xdigit_value (gchar c) G_GNUC_CONST;
+
+/* String utility functions that modify a string argument or
+ * return a constant string that must not be freed.
+ */
+#define G_STR_DELIMITERS "_-|> <."
+gchar* g_strdelimit (gchar *string,
+ const gchar *delimiters,
+ gchar new_delimiter);
+gchar* g_strcanon (gchar *string,
+ const gchar *valid_chars,
+ gchar substitutor);
+G_CONST_RETURN gchar* g_strerror (gint errnum) G_GNUC_CONST;
+G_CONST_RETURN gchar* g_strsignal (gint signum) G_GNUC_CONST;
+gchar* g_strreverse (gchar *string);
+gsize g_strlcpy (gchar *dest,
+ const gchar *src,
+ gsize dest_size);
+gsize g_strlcat (gchar *dest,
+ const gchar *src,
+ gsize dest_size);
+gchar * g_strstr_len (const gchar *haystack,
+ gssize haystack_len,
+ const gchar *needle);
+gchar * g_strrstr (const gchar *haystack,
+ const gchar *needle);
+gchar * g_strrstr_len (const gchar *haystack,
+ gssize haystack_len,
+ const gchar *needle);
+
+gboolean g_str_has_suffix (const gchar *str,
+ const gchar *suffix);
+gboolean g_str_has_prefix (const gchar *str,
+ const gchar *prefix);
+
+/* String to/from double conversion functions */
+
+gdouble g_strtod (const gchar *nptr,
+ gchar **endptr);
+gdouble g_ascii_strtod (const gchar *nptr,
+ gchar **endptr);
+guint64 g_ascii_strtoull (const gchar *nptr,
+ gchar **endptr,
+ guint base);
+gint64 g_ascii_strtoll (const gchar *nptr,
+ gchar **endptr,
+ guint base);
+/* 29 bytes should enough for all possible values that
+ * g_ascii_dtostr can produce.
+ * Then add 10 for good measure */
+#define G_ASCII_DTOSTR_BUF_SIZE (29 + 10)
+gchar * g_ascii_dtostr (gchar *buffer,
+ gint buf_len,
+ gdouble d);
+gchar * g_ascii_formatd (gchar *buffer,
+ gint buf_len,
+ const gchar *format,
+ gdouble d);
+
+/* removes leading spaces */
+gchar* g_strchug (gchar *string);
+/* removes trailing spaces */
+gchar* g_strchomp (gchar *string);
+/* removes leading & trailing spaces */
+#define g_strstrip( string ) g_strchomp (g_strchug (string))
+
+gint g_ascii_strcasecmp (const gchar *s1,
+ const gchar *s2);
+gint g_ascii_strncasecmp (const gchar *s1,
+ const gchar *s2,
+ gsize n);
+gchar* g_ascii_strdown (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+gchar* g_ascii_strup (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+
+#ifndef G_DISABLE_DEPRECATED
+
+/* The following four functions are deprecated and will be removed in
+ * the next major release. They use the locale-specific tolower and
+ * toupper, which is almost never the right thing.
+ */
+
+gint g_strcasecmp (const gchar *s1,
+ const gchar *s2);
+gint g_strncasecmp (const gchar *s1,
+ const gchar *s2,
+ guint n);
+gchar* g_strdown (gchar *string);
+gchar* g_strup (gchar *string);
+
+#endif /* G_DISABLE_DEPRECATED */
+
+/* String utility functions that return a newly allocated string which
+ * ought to be freed with g_free from the caller at some point.
+ */
+gchar* g_strdup (const gchar *str) G_GNUC_MALLOC;
+gchar* g_strdup_printf (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2) G_GNUC_MALLOC;
+gchar* g_strdup_vprintf (const gchar *format,
+ va_list args) G_GNUC_MALLOC;
+gchar* g_strndup (const gchar *str,
+ gsize n) G_GNUC_MALLOC;
+gchar* g_strnfill (gsize length,
+ gchar fill_char) G_GNUC_MALLOC;
+gchar* g_strconcat (const gchar *string1,
+ ...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
+gchar* g_strjoin (const gchar *separator,
+ ...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
+
+/* Make a copy of a string interpreting C string -style escape
+ * sequences. Inverse of g_strescape. The recognized sequences are \b
+ * \f \n \r \t \\ \" and the octal format.
+ */
+gchar* g_strcompress (const gchar *source) G_GNUC_MALLOC;
+
+/* Copy a string escaping nonprintable characters like in C strings.
+ * Inverse of g_strcompress. The exceptions parameter, if non-NULL, points
+ * to a string containing characters that are not to be escaped.
+ *
+ * Deprecated API: gchar* g_strescape (const gchar *source);
+ * Luckily this function wasn't used much, using NULL as second parameter
+ * provides mostly identical semantics.
+ */
+gchar* g_strescape (const gchar *source,
+ const gchar *exceptions) G_GNUC_MALLOC;
+
+gpointer g_memdup (gconstpointer mem,
+ guint byte_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(2);
+
+/* NULL terminated string arrays.
+ * g_strsplit(), g_strsplit_set() split up string into max_tokens tokens
+ * at delim and return a newly allocated string array.
+ * g_strjoinv() concatenates all of str_array's strings, sliding in an
+ * optional separator, the returned string is newly allocated.
+ * g_strfreev() frees the array itself and all of its strings.
+ * g_strdupv() copies a NULL-terminated array of strings
+ * g_strv_length() returns the length of a NULL-terminated array of strings
+ */
+gchar** g_strsplit (const gchar *string,
+ const gchar *delimiter,
+ gint max_tokens) G_GNUC_MALLOC;
+gchar ** g_strsplit_set (const gchar *string,
+ const gchar *delimiters,
+ gint max_tokens) G_GNUC_MALLOC;
+gchar* g_strjoinv (const gchar *separator,
+ gchar **str_array) G_GNUC_MALLOC;
+void g_strfreev (gchar **str_array);
+gchar** g_strdupv (gchar **str_array) G_GNUC_MALLOC;
+guint g_strv_length (gchar **str_array);
+
+gchar* g_stpcpy (gchar *dest,
+ const char *src);
+
+G_CONST_RETURN gchar *g_strip_context (const gchar *msgid,
+ const gchar *msgval) G_GNUC_FORMAT(1);
+
+G_CONST_RETURN gchar *g_dgettext (const gchar *domain,
+ const gchar *msgid) G_GNUC_FORMAT(2);
+
+G_CONST_RETURN gchar *g_dngettext (const gchar *domain,
+ const gchar *msgid,
+ const gchar *msgid_plural,
+ gulong n) G_GNUC_FORMAT(3);
+G_CONST_RETURN gchar *g_dpgettext (const gchar *domain,
+ const gchar *msgctxtid,
+ gsize msgidoffset) G_GNUC_FORMAT(2);
+G_CONST_RETURN gchar *g_dpgettext2 (const gchar *domain,
+ const gchar *context,
+ const gchar *msgid) G_GNUC_FORMAT(3);
+
+G_END_DECLS
+
+#endif /* __G_STRFUNCS_H__ */
diff --git a/support/glib/gstring.c b/support/glib/gstring.c
new file mode 100644
index 00000000..9a7bb6a9
--- /dev/null
+++ b/support/glib/gstring.c
@@ -0,0 +1,1488 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe
+ */
+
+#include "config.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "glib.h"
+#include "gprintf.h"
+
+#include "galias.h"
+
+#if NOT_NEEDED_FOR_NAVIT
+struct _GStringChunk
+{
+ GHashTable *const_table;
+ GSList *storage_list;
+ gsize storage_next;
+ gsize this_size;
+ gsize default_size;
+};
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+/* Hash Functions.
+ */
+
+/**
+ * g_str_equal:
+ * @v1: a key
+ * @v2: a key to compare with @v1
+ *
+ * Compares two strings for byte-by-byte equality and returns %TRUE
+ * if they are equal. It can be passed to g_hash_table_new() as the
+ * @key_equal_func parameter, when using strings as keys in a #GHashTable.
+ *
+ * Returns: %TRUE if the two keys match
+ */
+gboolean
+g_str_equal (gconstpointer v1,
+ gconstpointer v2)
+{
+ const gchar *string1 = v1;
+ const gchar *string2 = v2;
+
+ return strcmp (string1, string2) == 0;
+}
+
+/**
+ * g_str_hash:
+ * @v: a string key
+ *
+ * Converts a string to a hash value.
+ * It can be passed to g_hash_table_new() as the @hash_func
+ * parameter, when using strings as keys in a #GHashTable.
+ *
+ * Returns: a hash value corresponding to the key
+ */
+guint
+g_str_hash (gconstpointer v)
+{
+ /* 31 bit hash function */
+ const signed char *p = v;
+ guint32 h = *p;
+
+ if (h)
+ for (p += 1; *p != '\0'; p++)
+ h = (h << 5) - h + *p;
+
+ return h;
+}
+
+#if NOT_NEEDED_FOR_NAVIT
+#define MY_MAXSIZE ((gsize)-1)
+
+static inline gsize
+nearest_power (gsize base, gsize num)
+{
+ if (num > MY_MAXSIZE / 2)
+ {
+ return MY_MAXSIZE;
+ }
+ else
+ {
+ gsize n = base;
+
+ while (n < num)
+ n <<= 1;
+
+ return n;
+ }
+}
+
+/* String Chunks.
+ */
+
+/**
+ * g_string_chunk_new:
+ * @size: the default size of the blocks of memory which are
+ * allocated to store the strings. If a particular string
+ * is larger than this default size, a larger block of
+ * memory will be allocated for it.
+ *
+ * Creates a new #GStringChunk.
+ *
+ * Returns: a new #GStringChunk
+ */
+GStringChunk*
+g_string_chunk_new (gsize size)
+{
+ GStringChunk *new_chunk = g_new (GStringChunk, 1);
+ gsize actual_size = 1;
+
+ actual_size = nearest_power (1, size);
+
+ new_chunk->const_table = NULL;
+ new_chunk->storage_list = NULL;
+ new_chunk->storage_next = actual_size;
+ new_chunk->default_size = actual_size;
+ new_chunk->this_size = actual_size;
+
+ return new_chunk;
+}
+
+/**
+ * g_string_chunk_free:
+ * @chunk: a #GStringChunk
+ *
+ * Frees all memory allocated by the #GStringChunk.
+ * After calling g_string_chunk_free() it is not safe to
+ * access any of the strings which were contained within it.
+ */
+void
+g_string_chunk_free (GStringChunk *chunk)
+{
+ GSList *tmp_list;
+
+ g_return_if_fail (chunk != NULL);
+
+ if (chunk->storage_list)
+ {
+ for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
+ g_free (tmp_list->data);
+
+ g_slist_free (chunk->storage_list);
+ }
+
+ if (chunk->const_table)
+ g_hash_table_destroy (chunk->const_table);
+
+ g_free (chunk);
+}
+
+/**
+ * g_string_chunk_clear:
+ * @chunk: a #GStringChunk
+ *
+ * Frees all strings contained within the #GStringChunk.
+ * After calling g_string_chunk_clear() it is not safe to
+ * access any of the strings which were contained within it.
+ *
+ * Since: 2.14
+ */
+void
+g_string_chunk_clear (GStringChunk *chunk)
+{
+ GSList *tmp_list;
+
+ g_return_if_fail (chunk != NULL);
+
+ if (chunk->storage_list)
+ {
+ for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
+ g_free (tmp_list->data);
+
+ g_slist_free (chunk->storage_list);
+
+ chunk->storage_list = NULL;
+ chunk->storage_next = chunk->default_size;
+ chunk->this_size = chunk->default_size;
+ }
+
+ if (chunk->const_table)
+ g_hash_table_remove_all (chunk->const_table);
+}
+
+/**
+ * g_string_chunk_insert:
+ * @chunk: a #GStringChunk
+ * @string: the string to add
+ *
+ * Adds a copy of @string to the #GStringChunk.
+ * It returns a pointer to the new copy of the string
+ * in the #GStringChunk. The characters in the string
+ * can be changed, if necessary, though you should not
+ * change anything after the end of the string.
+ *
+ * Unlike g_string_chunk_insert_const(), this function
+ * does not check for duplicates. Also strings added
+ * with g_string_chunk_insert() will not be searched
+ * by g_string_chunk_insert_const() when looking for
+ * duplicates.
+ *
+ * Returns: a pointer to the copy of @string within
+ * the #GStringChunk
+ */
+gchar*
+g_string_chunk_insert (GStringChunk *chunk,
+ const gchar *string)
+{
+ g_return_val_if_fail (chunk != NULL, NULL);
+
+ return g_string_chunk_insert_len (chunk, string, -1);
+}
+
+/**
+ * g_string_chunk_insert_const:
+ * @chunk: a #GStringChunk
+ * @string: the string to add
+ *
+ * Adds a copy of @string to the #GStringChunk, unless the same
+ * string has already been added to the #GStringChunk with
+ * g_string_chunk_insert_const().
+ *
+ * This function is useful if you need to copy a large number
+ * of strings but do not want to waste space storing duplicates.
+ * But you must remember that there may be several pointers to
+ * the same string, and so any changes made to the strings
+ * should be done very carefully.
+ *
+ * Note that g_string_chunk_insert_const() will not return a
+ * pointer to a string added with g_string_chunk_insert(), even
+ * if they do match.
+ *
+ * Returns: a pointer to the new or existing copy of @string
+ * within the #GStringChunk
+ */
+gchar*
+g_string_chunk_insert_const (GStringChunk *chunk,
+ const gchar *string)
+{
+ char* lookup;
+
+ g_return_val_if_fail (chunk != NULL, NULL);
+
+ if (!chunk->const_table)
+ chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+ lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
+
+ if (!lookup)
+ {
+ lookup = g_string_chunk_insert (chunk, string);
+ g_hash_table_insert (chunk->const_table, lookup, lookup);
+ }
+
+ return lookup;
+}
+
+/**
+ * g_string_chunk_insert_len:
+ * @chunk: a #GStringChunk
+ * @string: bytes to insert
+ * @len: number of bytes of @string to insert, or -1 to insert a
+ * nul-terminated string
+ *
+ * Adds a copy of the first @len bytes of @string to the #GStringChunk.
+ * The copy is nul-terminated.
+ *
+ * Since this function does not stop at nul bytes, it is the caller's
+ * responsibility to ensure that @string has at least @len addressable
+ * bytes.
+ *
+ * The characters in the returned string can be changed, if necessary,
+ * though you should not change anything after the end of the string.
+ *
+ * Return value: a pointer to the copy of @string within the #GStringChunk
+ *
+ * Since: 2.4
+ **/
+gchar*
+g_string_chunk_insert_len (GStringChunk *chunk,
+ const gchar *string,
+ gssize len)
+{
+ gssize size;
+ gchar* pos;
+
+ g_return_val_if_fail (chunk != NULL, NULL);
+
+ if (len < 0)
+ size = strlen (string);
+ else
+ size = len;
+
+ if ((chunk->storage_next + size + 1) > chunk->this_size)
+ {
+ gsize new_size = nearest_power (chunk->default_size, size + 1);
+
+ chunk->storage_list = g_slist_prepend (chunk->storage_list,
+ g_new (gchar, new_size));
+
+ chunk->this_size = new_size;
+ chunk->storage_next = 0;
+ }
+
+ pos = ((gchar *) chunk->storage_list->data) + chunk->storage_next;
+
+ *(pos + size) = '\0';
+
+ strncpy (pos, string, size);
+ if (len > 0)
+ size = strlen (pos);
+
+ chunk->storage_next += size + 1;
+
+ return pos;
+}
+
+/* Strings.
+ */
+static void
+g_string_maybe_expand (GString* string,
+ gsize len)
+{
+ if (string->len + len >= string->allocated_len)
+ {
+ string->allocated_len = nearest_power (1, string->len + len + 1);
+ string->str = g_realloc (string->str, string->allocated_len);
+ }
+}
+
+/**
+ * g_string_sized_new:
+ * @dfl_size: the default size of the space allocated to
+ * hold the string
+ *
+ * Creates a new #GString, with enough space for @dfl_size
+ * bytes. This is useful if you are going to add a lot of
+ * text to the string and don't want it to be reallocated
+ * too often.
+ *
+ * Returns: the new #GString
+ */
+GString*
+g_string_sized_new (gsize dfl_size)
+{
+ GString *string = g_slice_new (GString);
+
+ string->allocated_len = 0;
+ string->len = 0;
+ string->str = NULL;
+
+ g_string_maybe_expand (string, MAX (dfl_size, 2));
+ string->str[0] = 0;
+
+ return string;
+}
+
+/**
+ * g_string_new:
+ * @init: the initial text to copy into the string
+ *
+ * Creates a new #GString, initialized with the given string.
+ *
+ * Returns: the new #GString
+ */
+GString*
+g_string_new (const gchar *init)
+{
+ GString *string;
+
+ if (init == NULL || *init == '\0')
+ string = g_string_sized_new (2);
+ else
+ {
+ gint len;
+
+ len = strlen (init);
+ string = g_string_sized_new (len + 2);
+
+ g_string_append_len (string, init, len);
+ }
+
+ return string;
+}
+
+/**
+ * g_string_new_len:
+ * @init: initial contents of the string
+ * @len: length of @init to use
+ *
+ * Creates a new #GString with @len bytes of the @init buffer.
+ * Because a length is provided, @init need not be nul-terminated,
+ * and can contain embedded nul bytes.
+ *
+ * Since this function does not stop at nul bytes, it is the caller's
+ * responsibility to ensure that @init has at least @len addressable
+ * bytes.
+ *
+ * Returns: a new #GString
+ */
+GString*
+g_string_new_len (const gchar *init,
+ gssize len)
+{
+ GString *string;
+
+ if (len < 0)
+ return g_string_new (init);
+ else
+ {
+ string = g_string_sized_new (len);
+
+ if (init)
+ g_string_append_len (string, init, len);
+
+ return string;
+ }
+}
+
+/**
+ * g_string_free:
+ * @string: a #GString
+ * @free_segment: if %TRUE the actual character data is freed as well
+ *
+ * Frees the memory allocated for the #GString.
+ * If @free_segment is %TRUE it also frees the character data.
+ *
+ * Returns: the character data of @string
+ * (i.e. %NULL if @free_segment is %TRUE)
+ */
+gchar*
+g_string_free (GString *string,
+ gboolean free_segment)
+{
+ gchar *segment;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ if (free_segment)
+ {
+ g_free (string->str);
+ segment = NULL;
+ }
+ else
+ segment = string->str;
+
+ g_slice_free (GString, string);
+
+ return segment;
+}
+
+/**
+ * g_string_equal:
+ * @v: a #GString
+ * @v2: another #GString
+ *
+ * Compares two strings for equality, returning %TRUE if they are equal.
+ * For use with #GHashTable.
+ *
+ * Returns: %TRUE if they strings are the same length and contain the
+ * same bytes
+ */
+gboolean
+g_string_equal (const GString *v,
+ const GString *v2)
+{
+ gchar *p, *q;
+ GString *string1 = (GString *) v;
+ GString *string2 = (GString *) v2;
+ gsize i = string1->len;
+
+ if (i != string2->len)
+ return FALSE;
+
+ p = string1->str;
+ q = string2->str;
+ while (i)
+ {
+ if (*p != *q)
+ return FALSE;
+ p++;
+ q++;
+ i--;
+ }
+ return TRUE;
+}
+
+/**
+ * g_string_hash:
+ * @str: a string to hash
+ *
+ * Creates a hash code for @str; for use with #GHashTable.
+ *
+ * Returns: hash code for @str
+ */
+/* 31 bit hash function */
+guint
+g_string_hash (const GString *str)
+{
+ const gchar *p = str->str;
+ gsize n = str->len;
+ guint h = 0;
+
+ while (n--)
+ {
+ h = (h << 5) - h + *p;
+ p++;
+ }
+
+ return h;
+}
+
+/**
+ * g_string_assign:
+ * @string: the destination #GString. Its current contents
+ * are destroyed.
+ * @rval: the string to copy into @string
+ *
+ * Copies the bytes from a string into a #GString,
+ * destroying any previous contents. It is rather like
+ * the standard strcpy() function, except that you do not
+ * have to worry about having enough space to copy the string.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_assign (GString *string,
+ const gchar *rval)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (rval != NULL, string);
+
+ /* Make sure assigning to itself doesn't corrupt the string. */
+ if (string->str != rval)
+ {
+ /* Assigning from substring should be ok since g_string_truncate
+ does not realloc. */
+ g_string_truncate (string, 0);
+ g_string_append (string, rval);
+ }
+
+ return string;
+}
+
+/**
+ * g_string_truncate:
+ * @string: a #GString
+ * @len: the new size of @string
+ *
+ * Cuts off the end of the GString, leaving the first @len bytes.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_truncate (GString *string,
+ gsize len)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+
+ string->len = MIN (len, string->len);
+ string->str[string->len] = 0;
+
+ return string;
+}
+
+/**
+ * g_string_set_size:
+ * @string: a #GString
+ * @len: the new length
+ *
+ * Sets the length of a #GString. If the length is less than
+ * the current length, the string will be truncated. If the
+ * length is greater than the current length, the contents
+ * of the newly added area are undefined. (However, as
+ * always, string->str[string->len] will be a nul byte.)
+ *
+ * Return value: @string
+ **/
+GString*
+g_string_set_size (GString *string,
+ gsize len)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+
+ if (len >= string->allocated_len)
+ g_string_maybe_expand (string, len - string->len);
+
+ string->len = len;
+ string->str[len] = 0;
+
+ return string;
+}
+
+/**
+ * g_string_insert_len:
+ * @string: a #GString
+ * @pos: position in @string where insertion should
+ * happen, or -1 for at the end
+ * @val: bytes to insert
+ * @len: number of bytes of @val to insert
+ *
+ * Inserts @len bytes of @val into @string at @pos.
+ * Because @len is provided, @val may contain embedded
+ * nuls and need not be nul-terminated. If @pos is -1,
+ * bytes are inserted at the end of the string.
+ *
+ * Since this function does not stop at nul bytes, it is
+ * the caller's responsibility to ensure that @val has at
+ * least @len addressable bytes.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_insert_len (GString *string,
+ gssize pos,
+ const gchar *val,
+ gssize len)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (val != NULL, string);
+
+ if (len < 0)
+ len = strlen (val);
+
+ if (pos < 0)
+ pos = string->len;
+ else
+ g_return_val_if_fail (pos <= string->len, string);
+
+ /* Check whether val represents a substring of string. This test
+ probably violates chapter and verse of the C standards, since
+ ">=" and "<=" are only valid when val really is a substring.
+ In practice, it will work on modern archs. */
+ if (val >= string->str && val <= string->str + string->len)
+ {
+ gsize offset = val - string->str;
+ gsize precount = 0;
+
+ g_string_maybe_expand (string, len);
+ val = string->str + offset;
+ /* At this point, val is valid again. */
+
+ /* Open up space where we are going to insert. */
+ if (pos < string->len)
+ g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
+
+ /* Move the source part before the gap, if any. */
+ if (offset < pos)
+ {
+ precount = MIN (len, pos - offset);
+ memcpy (string->str + pos, val, precount);
+ }
+
+ /* Move the source part after the gap, if any. */
+ if (len > precount)
+ memcpy (string->str + pos + precount,
+ val + /* Already moved: */ precount + /* Space opened up: */ len,
+ len - precount);
+ }
+ else
+ {
+ g_string_maybe_expand (string, len);
+
+ /* If we aren't appending at the end, move a hunk
+ * of the old string to the end, opening up space
+ */
+ if (pos < string->len)
+ g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
+
+ /* insert the new string */
+ if (len == 1)
+ string->str[pos] = *val;
+ else
+ memcpy (string->str + pos, val, len);
+ }
+
+ string->len += len;
+
+ string->str[string->len] = 0;
+
+ return string;
+}
+
+#define SUB_DELIM_CHARS "!$&'()*+,;="
+
+static gboolean
+is_valid (char c, const char *reserved_chars_allowed)
+{
+ if (g_ascii_isalnum (c) ||
+ c == '-' ||
+ c == '.' ||
+ c == '_' ||
+ c == '~')
+ return TRUE;
+
+ if (reserved_chars_allowed &&
+ strchr (reserved_chars_allowed, c) != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+gunichar_ok (gunichar c)
+{
+ return
+ (c != (gunichar) -2) &&
+ (c != (gunichar) -1);
+}
+
+/**
+ * g_string_append_uri_escaped:
+ * @string: a #GString
+ * @unescaped: a string
+ * @reserved_chars_allowed: a string of reserved characters allowed to be used
+ * @allow_utf8: set %TRUE if the escaped string may include UTF8 characters
+ *
+ * Appends @unescaped to @string, escaped any characters that
+ * are reserved in URIs using URI-style escape sequences.
+ *
+ * Returns: @string
+ *
+ * Since: 2.16
+ **/
+GString *
+g_string_append_uri_escaped (GString *string,
+ const char *unescaped,
+ const char *reserved_chars_allowed,
+ gboolean allow_utf8)
+{
+ unsigned char c;
+ const char *end;
+ static const gchar hex[16] = "0123456789ABCDEF";
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (unescaped != NULL, NULL);
+
+ end = unescaped + strlen (unescaped);
+
+ while ((c = *unescaped) != 0)
+ {
+ if (c >= 0x80 && allow_utf8 &&
+ gunichar_ok (g_utf8_get_char_validated (unescaped, end - unescaped)))
+ {
+ int len = g_utf8_skip [c];
+ g_string_append_len (string, unescaped, len);
+ unescaped += len;
+ }
+ else if (is_valid (c, reserved_chars_allowed))
+ {
+ g_string_append_c (string, c);
+ unescaped++;
+ }
+ else
+ {
+ g_string_append_c (string, '%');
+ g_string_append_c (string, hex[((guchar)c) >> 4]);
+ g_string_append_c (string, hex[((guchar)c) & 0xf]);
+ unescaped++;
+ }
+ }
+
+ return string;
+}
+
+/**
+ * g_string_append:
+ * @string: a #GString
+ * @val: the string to append onto the end of @string
+ *
+ * Adds a string onto the end of a #GString, expanding
+ * it if necessary.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_append (GString *string,
+ const gchar *val)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (val != NULL, string);
+
+ return g_string_insert_len (string, -1, val, -1);
+}
+
+/**
+ * g_string_append_len:
+ * @string: a #GString
+ * @val: bytes to append
+ * @len: number of bytes of @val to use
+ *
+ * Appends @len bytes of @val to @string. Because @len is
+ * provided, @val may contain embedded nuls and need not
+ * be nul-terminated.
+ *
+ * Since this function does not stop at nul bytes, it is
+ * the caller's responsibility to ensure that @val has at
+ * least @len addressable bytes.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_append_len (GString *string,
+ const gchar *val,
+ gssize len)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (val != NULL, string);
+
+ return g_string_insert_len (string, -1, val, len);
+}
+
+/**
+ * g_string_append_c:
+ * @string: a #GString
+ * @c: the byte to append onto the end of @string
+ *
+ * Adds a byte onto the end of a #GString, expanding
+ * it if necessary.
+ *
+ * Returns: @string
+ */
+#undef g_string_append_c
+GString*
+g_string_append_c (GString *string,
+ gchar c)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+
+ return g_string_insert_c (string, -1, c);
+}
+
+/**
+ * g_string_append_unichar:
+ * @string: a #GString
+ * @wc: a Unicode character
+ *
+ * Converts a Unicode character into UTF-8, and appends it
+ * to the string.
+ *
+ * Return value: @string
+ **/
+GString*
+g_string_append_unichar (GString *string,
+ gunichar wc)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+
+ return g_string_insert_unichar (string, -1, wc);
+}
+
+/**
+ * g_string_prepend:
+ * @string: a #GString
+ * @val: the string to prepend on the start of @string
+ *
+ * Adds a string on to the start of a #GString,
+ * expanding it if necessary.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_prepend (GString *string,
+ const gchar *val)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (val != NULL, string);
+
+ return g_string_insert_len (string, 0, val, -1);
+}
+
+/**
+ * g_string_prepend_len:
+ * @string: a #GString
+ * @val: bytes to prepend
+ * @len: number of bytes in @val to prepend
+ *
+ * Prepends @len bytes of @val to @string.
+ * Because @len is provided, @val may contain
+ * embedded nuls and need not be nul-terminated.
+ *
+ * Since this function does not stop at nul bytes,
+ * it is the caller's responsibility to ensure that
+ * @val has at least @len addressable bytes.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_prepend_len (GString *string,
+ const gchar *val,
+ gssize len)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (val != NULL, string);
+
+ return g_string_insert_len (string, 0, val, len);
+}
+
+/**
+ * g_string_prepend_c:
+ * @string: a #GString
+ * @c: the byte to prepend on the start of the #GString
+ *
+ * Adds a byte onto the start of a #GString,
+ * expanding it if necessary.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_prepend_c (GString *string,
+ gchar c)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+
+ return g_string_insert_c (string, 0, c);
+}
+
+/**
+ * g_string_prepend_unichar:
+ * @string: a #GString
+ * @wc: a Unicode character
+ *
+ * Converts a Unicode character into UTF-8, and prepends it
+ * to the string.
+ *
+ * Return value: @string
+ **/
+GString*
+g_string_prepend_unichar (GString *string,
+ gunichar wc)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+
+ return g_string_insert_unichar (string, 0, wc);
+}
+
+/**
+ * g_string_insert:
+ * @string: a #GString
+ * @pos: the position to insert the copy of the string
+ * @val: the string to insert
+ *
+ * Inserts a copy of a string into a #GString,
+ * expanding it if necessary.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_insert (GString *string,
+ gssize pos,
+ const gchar *val)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (val != NULL, string);
+ if (pos >= 0)
+ g_return_val_if_fail (pos <= string->len, string);
+
+ return g_string_insert_len (string, pos, val, -1);
+}
+
+/**
+ * g_string_insert_c:
+ * @string: a #GString
+ * @pos: the position to insert the byte
+ * @c: the byte to insert
+ *
+ * Inserts a byte into a #GString, expanding it if necessary.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_insert_c (GString *string,
+ gssize pos,
+ gchar c)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+
+ g_string_maybe_expand (string, 1);
+
+ if (pos < 0)
+ pos = string->len;
+ else
+ g_return_val_if_fail (pos <= string->len, string);
+
+ /* If not just an append, move the old stuff */
+ if (pos < string->len)
+ g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
+
+ string->str[pos] = c;
+
+ string->len += 1;
+
+ string->str[string->len] = 0;
+
+ return string;
+}
+
+/**
+ * g_string_insert_unichar:
+ * @string: a #GString
+ * @pos: the position at which to insert character, or -1 to
+ * append at the end of the string
+ * @wc: a Unicode character
+ *
+ * Converts a Unicode character into UTF-8, and insert it
+ * into the string at the given position.
+ *
+ * Return value: @string
+ **/
+GString*
+g_string_insert_unichar (GString *string,
+ gssize pos,
+ gunichar wc)
+{
+ gint charlen, first, i;
+ gchar *dest;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ /* Code copied from g_unichar_to_utf() */
+ if (wc < 0x80)
+ {
+ first = 0;
+ charlen = 1;
+ }
+ else if (wc < 0x800)
+ {
+ first = 0xc0;
+ charlen = 2;
+ }
+ else if (wc < 0x10000)
+ {
+ first = 0xe0;
+ charlen = 3;
+ }
+ else if (wc < 0x200000)
+ {
+ first = 0xf0;
+ charlen = 4;
+ }
+ else if (wc < 0x4000000)
+ {
+ first = 0xf8;
+ charlen = 5;
+ }
+ else
+ {
+ first = 0xfc;
+ charlen = 6;
+ }
+ /* End of copied code */
+
+ g_string_maybe_expand (string, charlen);
+
+ if (pos < 0)
+ pos = string->len;
+ else
+ g_return_val_if_fail (pos <= string->len, string);
+
+ /* If not just an append, move the old stuff */
+ if (pos < string->len)
+ g_memmove (string->str + pos + charlen, string->str + pos, string->len - pos);
+
+ dest = string->str + pos;
+ /* Code copied from g_unichar_to_utf() */
+ for (i = charlen - 1; i > 0; --i)
+ {
+ dest[i] = (wc & 0x3f) | 0x80;
+ wc >>= 6;
+ }
+ dest[0] = wc | first;
+ /* End of copied code */
+
+ string->len += charlen;
+
+ string->str[string->len] = 0;
+
+ return string;
+}
+
+/**
+ * g_string_overwrite:
+ * @string: a #GString
+ * @pos: the position at which to start overwriting
+ * @val: the string that will overwrite the @string starting at @pos
+ *
+ * Overwrites part of a string, lengthening it if necessary.
+ *
+ * Return value: @string
+ *
+ * Since: 2.14
+ **/
+GString *
+g_string_overwrite (GString *string,
+ gsize pos,
+ const gchar *val)
+{
+ g_return_val_if_fail (val != NULL, string);
+ return g_string_overwrite_len (string, pos, val, strlen (val));
+}
+
+/**
+ * g_string_overwrite_len:
+ * @string: a #GString
+ * @pos: the position at which to start overwriting
+ * @val: the string that will overwrite the @string starting at @pos
+ * @len: the number of bytes to write from @val
+ *
+ * Overwrites part of a string, lengthening it if necessary.
+ * This function will work with embedded nuls.
+ *
+ * Return value: @string
+ *
+ * Since: 2.14
+ **/
+GString *
+g_string_overwrite_len (GString *string,
+ gsize pos,
+ const gchar *val,
+ gssize len)
+{
+ gsize end;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ if (!len)
+ return string;
+
+ g_return_val_if_fail (val != NULL, string);
+ g_return_val_if_fail (pos <= string->len, string);
+
+ if (len < 0)
+ len = strlen (val);
+
+ end = pos + len;
+
+ if (end > string->len)
+ g_string_maybe_expand (string, end - string->len);
+
+ memcpy (string->str + pos, val, len);
+
+ if (end > string->len)
+ {
+ string->str[end] = '\0';
+ string->len = end;
+ }
+
+ return string;
+}
+
+/**
+ * g_string_erase:
+ * @string: a #GString
+ * @pos: the position of the content to remove
+ * @len: the number of bytes to remove, or -1 to remove all
+ * following bytes
+ *
+ * Removes @len bytes from a #GString, starting at position @pos.
+ * The rest of the #GString is shifted down to fill the gap.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_erase (GString *string,
+ gssize pos,
+ gssize len)
+{
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (pos >= 0, string);
+ g_return_val_if_fail (pos <= string->len, string);
+
+ if (len < 0)
+ len = string->len - pos;
+ else
+ {
+ g_return_val_if_fail (pos + len <= string->len, string);
+
+ if (pos + len < string->len)
+ g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
+ }
+
+ string->len -= len;
+
+ string->str[string->len] = 0;
+
+ return string;
+}
+
+/**
+ * g_string_ascii_down:
+ * @string: a GString
+ *
+ * Converts all upper case ASCII letters to lower case ASCII letters.
+ *
+ * Return value: passed-in @string pointer, with all the upper case
+ * characters converted to lower case in place, with
+ * semantics that exactly match g_ascii_tolower().
+ **/
+GString*
+g_string_ascii_down (GString *string)
+{
+ gchar *s;
+ gint n;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ n = string->len;
+ s = string->str;
+
+ while (n)
+ {
+ *s = g_ascii_tolower (*s);
+ s++;
+ n--;
+ }
+
+ return string;
+}
+
+/**
+ * g_string_ascii_up:
+ * @string: a GString
+ *
+ * Converts all lower case ASCII letters to upper case ASCII letters.
+ *
+ * Return value: passed-in @string pointer, with all the lower case
+ * characters converted to upper case in place, with
+ * semantics that exactly match g_ascii_toupper().
+ **/
+GString*
+g_string_ascii_up (GString *string)
+{
+ gchar *s;
+ gint n;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ n = string->len;
+ s = string->str;
+
+ while (n)
+ {
+ *s = g_ascii_toupper (*s);
+ s++;
+ n--;
+ }
+
+ return string;
+}
+
+/**
+ * g_string_down:
+ * @string: a #GString
+ *
+ * Converts a #GString to lowercase.
+ *
+ * Returns: the #GString.
+ *
+ * Deprecated:2.2: This function uses the locale-specific
+ * tolower() function, which is almost never the right thing.
+ * Use g_string_ascii_down() or g_utf8_strdown() instead.
+ */
+GString*
+g_string_down (GString *string)
+{
+ guchar *s;
+ glong n;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ n = string->len;
+ s = (guchar *) string->str;
+
+ while (n)
+ {
+ if (isupper (*s))
+ *s = tolower (*s);
+ s++;
+ n--;
+ }
+
+ return string;
+}
+
+/**
+ * g_string_up:
+ * @string: a #GString
+ *
+ * Converts a #GString to uppercase.
+ *
+ * Return value: @string
+ *
+ * Deprecated:2.2: This function uses the locale-specific
+ * toupper() function, which is almost never the right thing.
+ * Use g_string_ascii_up() or g_utf8_strup() instead.
+ **/
+GString*
+g_string_up (GString *string)
+{
+ guchar *s;
+ glong n;
+
+ g_return_val_if_fail (string != NULL, NULL);
+
+ n = string->len;
+ s = (guchar *) string->str;
+
+ while (n)
+ {
+ if (islower (*s))
+ *s = toupper (*s);
+ s++;
+ n--;
+ }
+
+ return string;
+}
+
+/**
+ * g_string_append_vprintf:
+ * @string: a #GString
+ * @format: the string format. See the printf() documentation
+ * @args: the list of arguments to insert in the output
+ *
+ * Appends a formatted string onto the end of a #GString.
+ * This function is similar to g_string_append_printf()
+ * except that the arguments to the format string are passed
+ * as a va_list.
+ *
+ * Since: 2.14
+ */
+void
+g_string_append_vprintf (GString *string,
+ const gchar *format,
+ va_list args)
+{
+ gchar *buf;
+ gint len;
+
+ g_return_if_fail (string != NULL);
+ g_return_if_fail (format != NULL);
+
+ len = g_vasprintf (&buf, format, args);
+
+ if (len >= 0)
+ {
+ g_string_maybe_expand (string, len);
+ memcpy (string->str + string->len, buf, len + 1);
+ string->len += len;
+ g_free (buf);
+ }
+}
+
+/**
+ * g_string_vprintf:
+ * @string: a #GString
+ * @format: the string format. See the printf() documentation
+ * @args: the parameters to insert into the format string
+ *
+ * Writes a formatted string into a #GString.
+ * This function is similar to g_string_printf() except that
+ * the arguments to the format string are passed as a va_list.
+ *
+ * Since: 2.14
+ */
+void
+g_string_vprintf (GString *string,
+ const gchar *format,
+ va_list args)
+{
+ g_string_truncate (string, 0);
+ g_string_append_vprintf (string, format, args);
+}
+
+/**
+ * g_string_sprintf:
+ * @string: a #GString
+ * @format: the string format. See the sprintf() documentation
+ * @Varargs: the parameters to insert into the format string
+ *
+ * Writes a formatted string into a #GString.
+ * This is similar to the standard sprintf() function,
+ * except that the #GString buffer automatically expands
+ * to contain the results. The previous contents of the
+ * #GString are destroyed.
+ *
+ * Deprecated: This function has been renamed to g_string_printf().
+ */
+
+/**
+ * g_string_printf:
+ * @string: a #GString
+ * @format: the string format. See the printf() documentation
+ * @Varargs: the parameters to insert into the format string
+ *
+ * Writes a formatted string into a #GString.
+ * This is similar to the standard sprintf() function,
+ * except that the #GString buffer automatically expands
+ * to contain the results. The previous contents of the
+ * #GString are destroyed.
+ */
+void
+g_string_printf (GString *string,
+ const gchar *format,
+ ...)
+{
+ va_list args;
+
+ g_string_truncate (string, 0);
+
+ va_start (args, format);
+ g_string_append_vprintf (string, format, args);
+ va_end (args);
+}
+
+/**
+ * g_string_sprintfa:
+ * @string: a #GString
+ * @format: the string format. See the sprintf() documentation
+ * @Varargs: the parameters to insert into the format string
+ *
+ * Appends a formatted string onto the end of a #GString.
+ * This function is similar to g_string_sprintf() except that
+ * the text is appended to the #GString.
+ *
+ * Deprecated: This function has been renamed to g_string_append_printf()
+ */
+
+/**
+ * g_string_append_printf:
+ * @string: a #GString
+ * @format: the string format. See the printf() documentation
+ * @Varargs: the parameters to insert into the format string
+ *
+ * Appends a formatted string onto the end of a #GString.
+ * This function is similar to g_string_printf() except
+ * that the text is appended to the #GString.
+ */
+void
+g_string_append_printf (GString *string,
+ const gchar *format,
+ ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ g_string_append_vprintf (string, format, args);
+ va_end (args);
+}
+
+#endif /* NOT_NEEDED_FOR_NAVIT */
+#define __G_STRING_C__
+#include "galiasdef.c"
diff --git a/support/glib/gthreadprivate.h b/support/glib/gthreadprivate.h
new file mode 100644
index 00000000..c9b5fa50
--- /dev/null
+++ b/support/glib/gthreadprivate.h
@@ -0,0 +1,68 @@
+/* GLIB - Library of useful routines for C programming
+ *
+ * gthreadprivate.h - GLib internal thread system related declarations.
+ *
+ * Copyright (C) 2003 Sebastian Wilhelmi
+ *
+ * The Gnome Library 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.
+ *
+ * The Gnome Library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_THREADPRIVATE_H__
+#define __G_THREADPRIVATE_H__
+
+G_BEGIN_DECLS
+
+/* System thread identifier comparision and assignment */
+#if GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P
+# define g_system_thread_equal_simple(thread1, thread2) \
+ ((thread1).dummy_pointer == (thread2).dummy_pointer)
+# define g_system_thread_assign(dest, src) \
+ ((dest).dummy_pointer = (src).dummy_pointer)
+#else /* GLIB_SIZEOF_SYSTEM_THREAD != SIZEOF_VOID_P */
+# define g_system_thread_equal_simple(thread1, thread2) \
+ (memcmp (&(thread1), &(thread2), GLIB_SIZEOF_SYSTEM_THREAD) == 0)
+# define g_system_thread_assign(dest, src) \
+ (memcpy (&(dest), &(src), GLIB_SIZEOF_SYSTEM_THREAD))
+#endif /* GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P */
+
+#define g_system_thread_equal(thread1, thread2) \
+ (g_thread_functions_for_glib_use.thread_equal ? \
+ g_thread_functions_for_glib_use.thread_equal (&(thread1), &(thread2)) :\
+ g_system_thread_equal_simple((thread1), (thread2)))
+
+/* Is called from gthread/gthread-impl.c */
+void g_thread_init_glib (void);
+
+/* base initializers, may only use g_mutex_new(), g_cond_new() */
+G_GNUC_INTERNAL void _g_mem_thread_init_noprivate_nomessage (void);
+/* initializers that may also use g_private_new() */
+G_GNUC_INTERNAL void _g_slice_thread_init_nomessage (void);
+G_GNUC_INTERNAL void _g_messages_thread_init_nomessage (void);
+
+/* full fledged initializers */
+G_GNUC_INTERNAL void _g_convert_thread_init (void);
+G_GNUC_INTERNAL void _g_rand_thread_init (void);
+G_GNUC_INTERNAL void _g_main_thread_init (void);
+G_GNUC_INTERNAL void _g_atomic_thread_init (void);
+G_GNUC_INTERNAL void _g_utils_thread_init (void);
+
+#ifdef G_OS_WIN32
+G_GNUC_INTERNAL void _g_win32_thread_init (void);
+#endif /* G_OS_WIN32 */
+
+G_END_DECLS
+
+#endif /* __G_THREADPRIVATE_H__ */
diff --git a/support/glib/gtypes.h b/support/glib/gtypes.h
new file mode 100644
index 00000000..3ac98fd4
--- /dev/null
+++ b/support/glib/gtypes.h
@@ -0,0 +1,432 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_TYPES_H__
+#define __G_TYPES_H__
+
+#include <glibconfig.h>
+
+G_BEGIN_DECLS
+
+/* Provide type definitions for commonly used types.
+ * These are useful because a "gint8" can be adjusted
+ * to be 1 byte (8 bits) on all platforms. Similarly and
+ * more importantly, "gint32" can be adjusted to be
+ * 4 bytes (32 bits) on all platforms.
+ */
+
+typedef char gchar;
+typedef short gshort;
+typedef long glong;
+typedef int gint;
+typedef gint gboolean;
+
+typedef unsigned char guchar;
+typedef unsigned short gushort;
+typedef unsigned long gulong;
+typedef unsigned int guint;
+
+typedef float gfloat;
+typedef double gdouble;
+
+/* Define min and max constants for the fixed size numerical types */
+#define G_MININT8 ((gint8) 0x80)
+#define G_MAXINT8 ((gint8) 0x7f)
+#define G_MAXUINT8 ((guint8) 0xff)
+
+#define G_MININT16 ((gint16) 0x8000)
+#define G_MAXINT16 ((gint16) 0x7fff)
+#define G_MAXUINT16 ((guint16) 0xffff)
+
+#define G_MININT32 ((gint32) 0x80000000)
+#define G_MAXINT32 ((gint32) 0x7fffffff)
+#define G_MAXUINT32 ((guint32) 0xffffffff)
+
+#define G_MININT64 ((gint64) G_GINT64_CONSTANT(0x8000000000000000))
+#define G_MAXINT64 G_GINT64_CONSTANT(0x7fffffffffffffff)
+#define G_MAXUINT64 G_GINT64_CONSTANT(0xffffffffffffffffU)
+
+typedef void* gpointer;
+typedef const void *gconstpointer;
+
+typedef gint (*GCompareFunc) (gconstpointer a,
+ gconstpointer b);
+typedef gint (*GCompareDataFunc) (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data);
+typedef gboolean (*GEqualFunc) (gconstpointer a,
+ gconstpointer b);
+typedef void (*GDestroyNotify) (gpointer data);
+typedef void (*GFunc) (gpointer data,
+ gpointer user_data);
+typedef guint (*GHashFunc) (gconstpointer key);
+typedef void (*GHFunc) (gpointer key,
+ gpointer value,
+ gpointer user_data);
+typedef void (*GFreeFunc) (gpointer data);
+typedef const gchar * (*GTranslateFunc) (const gchar *str,
+ gpointer data);
+
+
+/* Define some mathematical constants that aren't available
+ * symbolically in some strict ISO C implementations.
+ *
+ * Note that the large number of digits used in these definitions
+ * doesn't imply that GLib or current computers in general would be
+ * able to handle floating point numbers with an accuracy like this.
+ * It's mostly an exercise in futility and future proofing. For
+ * extended precision floating point support, look somewhere else
+ * than GLib.
+ */
+#define G_E 2.7182818284590452353602874713526624977572470937000
+#define G_LN2 0.69314718055994530941723212145817656807550013436026
+#define G_LN10 2.3025850929940456840179914546843642076011014886288
+#define G_PI 3.1415926535897932384626433832795028841971693993751
+#define G_PI_2 1.5707963267948966192313216916397514420985846996876
+#define G_PI_4 0.78539816339744830961566084581987572104929234984378
+#define G_SQRT2 1.4142135623730950488016887242096980785696718753769
+
+/* Portable endian checks and conversions
+ *
+ * glibconfig.h defines G_BYTE_ORDER which expands to one of
+ * the below macros.
+ */
+#define G_LITTLE_ENDIAN 1234
+#define G_BIG_ENDIAN 4321
+#define G_PDP_ENDIAN 3412 /* unused, need specific PDP check */
+
+
+/* Basic bit swapping functions
+ */
+#define GUINT16_SWAP_LE_BE_CONSTANT(val) ((guint16) ( \
+ (guint16) ((guint16) (val) >> 8) | \
+ (guint16) ((guint16) (val) << 8)))
+
+#define GUINT32_SWAP_LE_BE_CONSTANT(val) ((guint32) ( \
+ (((guint32) (val) & (guint32) 0x000000ffU) << 24) | \
+ (((guint32) (val) & (guint32) 0x0000ff00U) << 8) | \
+ (((guint32) (val) & (guint32) 0x00ff0000U) >> 8) | \
+ (((guint32) (val) & (guint32) 0xff000000U) >> 24)))
+
+#define GUINT64_SWAP_LE_BE_CONSTANT(val) ((guint64) ( \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x00000000000000ffU)) << 56) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x000000000000ff00U)) << 40) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x0000000000ff0000U)) << 24) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x00000000ff000000U)) << 8) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x000000ff00000000U)) >> 8) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x0000ff0000000000U)) >> 24) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0x00ff000000000000U)) >> 40) | \
+ (((guint64) (val) & \
+ (guint64) G_GINT64_CONSTANT (0xff00000000000000U)) >> 56)))
+
+/* Arch specific stuff for speed
+ */
+#if defined (__GNUC__) && (__GNUC__ >= 2) && defined (__OPTIMIZE__)
+# if defined (__i386__)
+# define GUINT16_SWAP_LE_BE_IA32(val) \
+ (__extension__ \
+ ({ register guint16 __v, __x = ((guint16) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT16_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ ("rorw $8, %w0" \
+ : "=r" (__v) \
+ : "0" (__x) \
+ : "cc"); \
+ __v; }))
+# if !defined (__i486__) && !defined (__i586__) \
+ && !defined (__pentium__) && !defined (__i686__) \
+ && !defined (__pentiumpro__) && !defined (__pentium4__)
+# define GUINT32_SWAP_LE_BE_IA32(val) \
+ (__extension__ \
+ ({ register guint32 __v, __x = ((guint32) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT32_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ ("rorw $8, %w0\n\t" \
+ "rorl $16, %0\n\t" \
+ "rorw $8, %w0" \
+ : "=r" (__v) \
+ : "0" (__x) \
+ : "cc"); \
+ __v; }))
+# else /* 486 and higher has bswap */
+# define GUINT32_SWAP_LE_BE_IA32(val) \
+ (__extension__ \
+ ({ register guint32 __v, __x = ((guint32) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT32_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ ("bswap %0" \
+ : "=r" (__v) \
+ : "0" (__x)); \
+ __v; }))
+# endif /* processor specific 32-bit stuff */
+# define GUINT64_SWAP_LE_BE_IA32(val) \
+ (__extension__ \
+ ({ union { guint64 __ll; \
+ guint32 __l[2]; } __w, __r; \
+ __w.__ll = ((guint64) (val)); \
+ if (__builtin_constant_p (__w.__ll)) \
+ __r.__ll = GUINT64_SWAP_LE_BE_CONSTANT (__w.__ll); \
+ else \
+ { \
+ __r.__l[0] = GUINT32_SWAP_LE_BE (__w.__l[1]); \
+ __r.__l[1] = GUINT32_SWAP_LE_BE (__w.__l[0]); \
+ } \
+ __r.__ll; }))
+ /* Possibly just use the constant version and let gcc figure it out? */
+# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_IA32 (val))
+# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_IA32 (val))
+# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_IA32 (val))
+# elif defined (__ia64__)
+# define GUINT16_SWAP_LE_BE_IA64(val) \
+ (__extension__ \
+ ({ register guint16 __v, __x = ((guint16) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT16_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ __volatile__ ("shl %0 = %1, 48 ;;" \
+ "mux1 %0 = %0, @rev ;;" \
+ : "=r" (__v) \
+ : "r" (__x)); \
+ __v; }))
+# define GUINT32_SWAP_LE_BE_IA64(val) \
+ (__extension__ \
+ ({ register guint32 __v, __x = ((guint32) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT32_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ __volatile__ ("shl %0 = %1, 32 ;;" \
+ "mux1 %0 = %0, @rev ;;" \
+ : "=r" (__v) \
+ : "r" (__x)); \
+ __v; }))
+# define GUINT64_SWAP_LE_BE_IA64(val) \
+ (__extension__ \
+ ({ register guint64 __v, __x = ((guint64) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT64_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ __volatile__ ("mux1 %0 = %1, @rev ;;" \
+ : "=r" (__v) \
+ : "r" (__x)); \
+ __v; }))
+# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_IA64 (val))
+# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_IA64 (val))
+# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_IA64 (val))
+# elif defined (__x86_64__)
+# define GUINT32_SWAP_LE_BE_X86_64(val) \
+ (__extension__ \
+ ({ register guint32 __v, __x = ((guint32) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT32_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ ("bswapl %0" \
+ : "=r" (__v) \
+ : "0" (__x)); \
+ __v; }))
+# define GUINT64_SWAP_LE_BE_X86_64(val) \
+ (__extension__ \
+ ({ register guint64 __v, __x = ((guint64) (val)); \
+ if (__builtin_constant_p (__x)) \
+ __v = GUINT64_SWAP_LE_BE_CONSTANT (__x); \
+ else \
+ __asm__ ("bswapq %0" \
+ : "=r" (__v) \
+ : "0" (__x)); \
+ __v; }))
+ /* gcc seems to figure out optimal code for this on its own */
+# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
+# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_X86_64 (val))
+# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_X86_64 (val))
+# else /* generic gcc */
+# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
+# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
+# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT (val))
+# endif
+#else /* generic */
+# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
+# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
+# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT (val))
+#endif /* generic */
+
+#define GUINT16_SWAP_LE_PDP(val) ((guint16) (val))
+#define GUINT16_SWAP_BE_PDP(val) (GUINT16_SWAP_LE_BE (val))
+#define GUINT32_SWAP_LE_PDP(val) ((guint32) ( \
+ (((guint32) (val) & (guint32) 0x0000ffffU) << 16) | \
+ (((guint32) (val) & (guint32) 0xffff0000U) >> 16)))
+#define GUINT32_SWAP_BE_PDP(val) ((guint32) ( \
+ (((guint32) (val) & (guint32) 0x00ff00ffU) << 8) | \
+ (((guint32) (val) & (guint32) 0xff00ff00U) >> 8)))
+
+/* The G*_TO_?E() macros are defined in glibconfig.h.
+ * The transformation is symmetric, so the FROM just maps to the TO.
+ */
+#define GINT16_FROM_LE(val) (GINT16_TO_LE (val))
+#define GUINT16_FROM_LE(val) (GUINT16_TO_LE (val))
+#define GINT16_FROM_BE(val) (GINT16_TO_BE (val))
+#define GUINT16_FROM_BE(val) (GUINT16_TO_BE (val))
+#define GINT32_FROM_LE(val) (GINT32_TO_LE (val))
+#define GUINT32_FROM_LE(val) (GUINT32_TO_LE (val))
+#define GINT32_FROM_BE(val) (GINT32_TO_BE (val))
+#define GUINT32_FROM_BE(val) (GUINT32_TO_BE (val))
+
+#define GINT64_FROM_LE(val) (GINT64_TO_LE (val))
+#define GUINT64_FROM_LE(val) (GUINT64_TO_LE (val))
+#define GINT64_FROM_BE(val) (GINT64_TO_BE (val))
+#define GUINT64_FROM_BE(val) (GUINT64_TO_BE (val))
+
+#define GLONG_FROM_LE(val) (GLONG_TO_LE (val))
+#define GULONG_FROM_LE(val) (GULONG_TO_LE (val))
+#define GLONG_FROM_BE(val) (GLONG_TO_BE (val))
+#define GULONG_FROM_BE(val) (GULONG_TO_BE (val))
+
+#define GINT_FROM_LE(val) (GINT_TO_LE (val))
+#define GUINT_FROM_LE(val) (GUINT_TO_LE (val))
+#define GINT_FROM_BE(val) (GINT_TO_BE (val))
+#define GUINT_FROM_BE(val) (GUINT_TO_BE (val))
+
+
+/* Portable versions of host-network order stuff
+ */
+#define g_ntohl(val) (GUINT32_FROM_BE (val))
+#define g_ntohs(val) (GUINT16_FROM_BE (val))
+#define g_htonl(val) (GUINT32_TO_BE (val))
+#define g_htons(val) (GUINT16_TO_BE (val))
+
+/* IEEE Standard 754 Single Precision Storage Format (gfloat):
+ *
+ * 31 30 23 22 0
+ * +--------+---------------+---------------+
+ * | s 1bit | e[30:23] 8bit | f[22:0] 23bit |
+ * +--------+---------------+---------------+
+ * B0------------------->B1------->B2-->B3-->
+ *
+ * IEEE Standard 754 Double Precision Storage Format (gdouble):
+ *
+ * 63 62 52 51 32 31 0
+ * +--------+----------------+----------------+ +---------------+
+ * | s 1bit | e[62:52] 11bit | f[51:32] 20bit | | f[31:0] 32bit |
+ * +--------+----------------+----------------+ +---------------+
+ * B0--------------->B1---------->B2--->B3----> B4->B5->B6->B7->
+ */
+/* subtract from biased_exponent to form base2 exponent (normal numbers) */
+typedef union _GDoubleIEEE754 GDoubleIEEE754;
+typedef union _GFloatIEEE754 GFloatIEEE754;
+#define G_IEEE754_FLOAT_BIAS (127)
+#define G_IEEE754_DOUBLE_BIAS (1023)
+/* multiply with base2 exponent to get base10 exponent (normal numbers) */
+#define G_LOG_2_BASE_10 (0.30102999566398119521)
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+union _GFloatIEEE754
+{
+ gfloat v_float;
+ struct {
+ guint mantissa : 23;
+ guint biased_exponent : 8;
+ guint sign : 1;
+ } mpn;
+};
+union _GDoubleIEEE754
+{
+ gdouble v_double;
+ struct {
+ guint mantissa_low : 32;
+ guint mantissa_high : 20;
+ guint biased_exponent : 11;
+ guint sign : 1;
+ } mpn;
+};
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+union _GFloatIEEE754
+{
+ gfloat v_float;
+ struct {
+ guint sign : 1;
+ guint biased_exponent : 8;
+ guint mantissa : 23;
+ } mpn;
+};
+union _GDoubleIEEE754
+{
+ gdouble v_double;
+ struct {
+ guint sign : 1;
+ guint biased_exponent : 11;
+ guint mantissa_high : 20;
+ guint mantissa_low : 32;
+ } mpn;
+};
+#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+#error unknown ENDIAN type
+#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+
+typedef struct _GTimeVal GTimeVal;
+
+struct _GTimeVal
+{
+ glong tv_sec;
+ glong tv_usec;
+};
+
+G_END_DECLS
+
+/* We prefix variable declarations so they can
+ * properly get exported in Windows DLLs.
+ */
+#ifndef GLIB_VAR
+# ifdef G_PLATFORM_WIN32
+# ifdef GLIB_STATIC_COMPILATION
+# define GLIB_VAR extern
+# else /* !GLIB_STATIC_COMPILATION */
+# ifdef GLIB_COMPILATION
+# ifdef DLL_EXPORT
+# define GLIB_VAR __declspec(dllexport)
+# else /* !DLL_EXPORT */
+# define GLIB_VAR extern
+# endif /* !DLL_EXPORT */
+# else /* !GLIB_COMPILATION */
+# define GLIB_VAR extern __declspec(dllimport)
+# endif /* !GLIB_COMPILATION */
+# endif /* !GLIB_STATIC_COMPILATION */
+# else /* !G_PLATFORM_WIN32 */
+# define GLIB_VAR extern
+# endif /* !G_PLATFORM_WIN32 */
+#endif /* GLIB_VAR */
+
+#endif /* __G_TYPES_H__ */
diff --git a/support/glib/gunicode.h b/support/glib/gunicode.h
new file mode 100644
index 00000000..78b259e4
--- /dev/null
+++ b/support/glib/gunicode.h
@@ -0,0 +1,404 @@
+/* gunicode.h - Unicode manipulation functions
+ *
+ * Copyright (C) 1999, 2000 Tom Tromey
+ * Copyright 2000, 2005 Red Hat, Inc.
+ *
+ * The Gnome Library 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.
+ *
+ * The Gnome Library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_UNICODE_H__
+#define __G_UNICODE_H__
+
+#include <glib/gerror.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef guint32 gunichar;
+typedef guint16 gunichar2;
+
+/* These are the possible character classifications.
+ * See http://www.unicode.org/Public/UNIDATA/UCD.html#General_Category_Values
+ */
+typedef enum
+{
+ G_UNICODE_CONTROL,
+ G_UNICODE_FORMAT,
+ G_UNICODE_UNASSIGNED,
+ G_UNICODE_PRIVATE_USE,
+ G_UNICODE_SURROGATE,
+ G_UNICODE_LOWERCASE_LETTER,
+ G_UNICODE_MODIFIER_LETTER,
+ G_UNICODE_OTHER_LETTER,
+ G_UNICODE_TITLECASE_LETTER,
+ G_UNICODE_UPPERCASE_LETTER,
+ G_UNICODE_COMBINING_MARK,
+ G_UNICODE_ENCLOSING_MARK,
+ G_UNICODE_NON_SPACING_MARK,
+ G_UNICODE_DECIMAL_NUMBER,
+ G_UNICODE_LETTER_NUMBER,
+ G_UNICODE_OTHER_NUMBER,
+ G_UNICODE_CONNECT_PUNCTUATION,
+ G_UNICODE_DASH_PUNCTUATION,
+ G_UNICODE_CLOSE_PUNCTUATION,
+ G_UNICODE_FINAL_PUNCTUATION,
+ G_UNICODE_INITIAL_PUNCTUATION,
+ G_UNICODE_OTHER_PUNCTUATION,
+ G_UNICODE_OPEN_PUNCTUATION,
+ G_UNICODE_CURRENCY_SYMBOL,
+ G_UNICODE_MODIFIER_SYMBOL,
+ G_UNICODE_MATH_SYMBOL,
+ G_UNICODE_OTHER_SYMBOL,
+ G_UNICODE_LINE_SEPARATOR,
+ G_UNICODE_PARAGRAPH_SEPARATOR,
+ G_UNICODE_SPACE_SEPARATOR
+} GUnicodeType;
+
+/* These are the possible line break classifications.
+ * Note that new types may be added in the future.
+ * Implementations may regard unknown values like G_UNICODE_BREAK_UNKNOWN
+ * See http://www.unicode.org/unicode/reports/tr14/
+ */
+typedef enum
+{
+ G_UNICODE_BREAK_MANDATORY,
+ G_UNICODE_BREAK_CARRIAGE_RETURN,
+ G_UNICODE_BREAK_LINE_FEED,
+ G_UNICODE_BREAK_COMBINING_MARK,
+ G_UNICODE_BREAK_SURROGATE,
+ G_UNICODE_BREAK_ZERO_WIDTH_SPACE,
+ G_UNICODE_BREAK_INSEPARABLE,
+ G_UNICODE_BREAK_NON_BREAKING_GLUE,
+ G_UNICODE_BREAK_CONTINGENT,
+ G_UNICODE_BREAK_SPACE,
+ G_UNICODE_BREAK_AFTER,
+ G_UNICODE_BREAK_BEFORE,
+ G_UNICODE_BREAK_BEFORE_AND_AFTER,
+ G_UNICODE_BREAK_HYPHEN,
+ G_UNICODE_BREAK_NON_STARTER,
+ G_UNICODE_BREAK_OPEN_PUNCTUATION,
+ G_UNICODE_BREAK_CLOSE_PUNCTUATION,
+ G_UNICODE_BREAK_QUOTATION,
+ G_UNICODE_BREAK_EXCLAMATION,
+ G_UNICODE_BREAK_IDEOGRAPHIC,
+ G_UNICODE_BREAK_NUMERIC,
+ G_UNICODE_BREAK_INFIX_SEPARATOR,
+ G_UNICODE_BREAK_SYMBOL,
+ G_UNICODE_BREAK_ALPHABETIC,
+ G_UNICODE_BREAK_PREFIX,
+ G_UNICODE_BREAK_POSTFIX,
+ G_UNICODE_BREAK_COMPLEX_CONTEXT,
+ G_UNICODE_BREAK_AMBIGUOUS,
+ G_UNICODE_BREAK_UNKNOWN,
+ G_UNICODE_BREAK_NEXT_LINE,
+ G_UNICODE_BREAK_WORD_JOINER,
+ G_UNICODE_BREAK_HANGUL_L_JAMO,
+ G_UNICODE_BREAK_HANGUL_V_JAMO,
+ G_UNICODE_BREAK_HANGUL_T_JAMO,
+ G_UNICODE_BREAK_HANGUL_LV_SYLLABLE,
+ G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE
+} GUnicodeBreakType;
+
+typedef enum
+{ /* ISO 15924 code */
+ G_UNICODE_SCRIPT_INVALID_CODE = -1,
+ G_UNICODE_SCRIPT_COMMON = 0, /* Zyyy */
+ G_UNICODE_SCRIPT_INHERITED, /* Qaai */
+ G_UNICODE_SCRIPT_ARABIC, /* Arab */
+ G_UNICODE_SCRIPT_ARMENIAN, /* Armn */
+ G_UNICODE_SCRIPT_BENGALI, /* Beng */
+ G_UNICODE_SCRIPT_BOPOMOFO, /* Bopo */
+ G_UNICODE_SCRIPT_CHEROKEE, /* Cher */
+ G_UNICODE_SCRIPT_COPTIC, /* Qaac */
+ G_UNICODE_SCRIPT_CYRILLIC, /* Cyrl (Cyrs) */
+ G_UNICODE_SCRIPT_DESERET, /* Dsrt */
+ G_UNICODE_SCRIPT_DEVANAGARI, /* Deva */
+ G_UNICODE_SCRIPT_ETHIOPIC, /* Ethi */
+ G_UNICODE_SCRIPT_GEORGIAN, /* Geor (Geon, Geoa) */
+ G_UNICODE_SCRIPT_GOTHIC, /* Goth */
+ G_UNICODE_SCRIPT_GREEK, /* Grek */
+ G_UNICODE_SCRIPT_GUJARATI, /* Gujr */
+ G_UNICODE_SCRIPT_GURMUKHI, /* Guru */
+ G_UNICODE_SCRIPT_HAN, /* Hani */
+ G_UNICODE_SCRIPT_HANGUL, /* Hang */
+ G_UNICODE_SCRIPT_HEBREW, /* Hebr */
+ G_UNICODE_SCRIPT_HIRAGANA, /* Hira */
+ G_UNICODE_SCRIPT_KANNADA, /* Knda */
+ G_UNICODE_SCRIPT_KATAKANA, /* Kana */
+ G_UNICODE_SCRIPT_KHMER, /* Khmr */
+ G_UNICODE_SCRIPT_LAO, /* Laoo */
+ G_UNICODE_SCRIPT_LATIN, /* Latn (Latf, Latg) */
+ G_UNICODE_SCRIPT_MALAYALAM, /* Mlym */
+ G_UNICODE_SCRIPT_MONGOLIAN, /* Mong */
+ G_UNICODE_SCRIPT_MYANMAR, /* Mymr */
+ G_UNICODE_SCRIPT_OGHAM, /* Ogam */
+ G_UNICODE_SCRIPT_OLD_ITALIC, /* Ital */
+ G_UNICODE_SCRIPT_ORIYA, /* Orya */
+ G_UNICODE_SCRIPT_RUNIC, /* Runr */
+ G_UNICODE_SCRIPT_SINHALA, /* Sinh */
+ G_UNICODE_SCRIPT_SYRIAC, /* Syrc (Syrj, Syrn, Syre) */
+ G_UNICODE_SCRIPT_TAMIL, /* Taml */
+ G_UNICODE_SCRIPT_TELUGU, /* Telu */
+ G_UNICODE_SCRIPT_THAANA, /* Thaa */
+ G_UNICODE_SCRIPT_THAI, /* Thai */
+ G_UNICODE_SCRIPT_TIBETAN, /* Tibt */
+ G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL, /* Cans */
+ G_UNICODE_SCRIPT_YI, /* Yiii */
+ G_UNICODE_SCRIPT_TAGALOG, /* Tglg */
+ G_UNICODE_SCRIPT_HANUNOO, /* Hano */
+ G_UNICODE_SCRIPT_BUHID, /* Buhd */
+ G_UNICODE_SCRIPT_TAGBANWA, /* Tagb */
+
+ /* Unicode-4.0 additions */
+ G_UNICODE_SCRIPT_BRAILLE, /* Brai */
+ G_UNICODE_SCRIPT_CYPRIOT, /* Cprt */
+ G_UNICODE_SCRIPT_LIMBU, /* Limb */
+ G_UNICODE_SCRIPT_OSMANYA, /* Osma */
+ G_UNICODE_SCRIPT_SHAVIAN, /* Shaw */
+ G_UNICODE_SCRIPT_LINEAR_B, /* Linb */
+ G_UNICODE_SCRIPT_TAI_LE, /* Tale */
+ G_UNICODE_SCRIPT_UGARITIC, /* Ugar */
+
+ /* Unicode-4.1 additions */
+ G_UNICODE_SCRIPT_NEW_TAI_LUE, /* Talu */
+ G_UNICODE_SCRIPT_BUGINESE, /* Bugi */
+ G_UNICODE_SCRIPT_GLAGOLITIC, /* Glag */
+ G_UNICODE_SCRIPT_TIFINAGH, /* Tfng */
+ G_UNICODE_SCRIPT_SYLOTI_NAGRI, /* Sylo */
+ G_UNICODE_SCRIPT_OLD_PERSIAN, /* Xpeo */
+ G_UNICODE_SCRIPT_KHAROSHTHI, /* Khar */
+
+ /* Unicode-5.0 additions */
+ G_UNICODE_SCRIPT_UNKNOWN, /* Zzzz */
+ G_UNICODE_SCRIPT_BALINESE, /* Bali */
+ G_UNICODE_SCRIPT_CUNEIFORM, /* Xsux */
+ G_UNICODE_SCRIPT_PHOENICIAN, /* Phnx */
+ G_UNICODE_SCRIPT_PHAGS_PA, /* Phag */
+ G_UNICODE_SCRIPT_NKO, /* Nkoo */
+
+ /* Unicode-5.1 additions */
+ G_UNICODE_SCRIPT_KAYAH_LI, /* Kali */
+ G_UNICODE_SCRIPT_LEPCHA, /* Lepc */
+ G_UNICODE_SCRIPT_REJANG, /* Rjng */
+ G_UNICODE_SCRIPT_SUNDANESE, /* Sund */
+ G_UNICODE_SCRIPT_SAURASHTRA, /* Saur */
+ G_UNICODE_SCRIPT_CHAM, /* Cham */
+ G_UNICODE_SCRIPT_OL_CHIKI, /* Olck */
+ G_UNICODE_SCRIPT_VAI, /* Vaii */
+ G_UNICODE_SCRIPT_CARIAN, /* Cari */
+ G_UNICODE_SCRIPT_LYCIAN, /* Lyci */
+ G_UNICODE_SCRIPT_LYDIAN /* Lydi */
+} GUnicodeScript;
+
+/* Returns TRUE if current locale uses UTF-8 charset. If CHARSET is
+ * not null, sets *CHARSET to the name of the current locale's
+ * charset. This value is statically allocated, and should be copied
+ * in case the locale's charset will be changed later using setlocale()
+ * or in some other way.
+ */
+gboolean g_get_charset (G_CONST_RETURN char **charset);
+
+/* These are all analogs of the <ctype.h> functions.
+ */
+gboolean g_unichar_isalnum (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isalpha (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iscntrl (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isdigit (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isgraph (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_islower (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isprint (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_ispunct (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isspace (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isupper (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isxdigit (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_istitle (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isdefined (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iswide (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iswide_cjk(gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iszerowidth(gunichar c) G_GNUC_CONST;
+gboolean g_unichar_ismark (gunichar c) G_GNUC_CONST;
+
+/* More <ctype.h> functions. These convert between the three cases.
+ * See the Unicode book to understand title case. */
+gunichar g_unichar_toupper (gunichar c) G_GNUC_CONST;
+gunichar g_unichar_tolower (gunichar c) G_GNUC_CONST;
+gunichar g_unichar_totitle (gunichar c) G_GNUC_CONST;
+
+/* If C is a digit (according to `g_unichar_isdigit'), then return its
+ numeric value. Otherwise return -1. */
+gint g_unichar_digit_value (gunichar c) G_GNUC_CONST;
+
+gint g_unichar_xdigit_value (gunichar c) G_GNUC_CONST;
+
+/* Return the Unicode character type of a given character. */
+GUnicodeType g_unichar_type (gunichar c) G_GNUC_CONST;
+
+/* Return the line break property for a given character */
+GUnicodeBreakType g_unichar_break_type (gunichar c) G_GNUC_CONST;
+
+/* Returns the combining class for a given character */
+gint g_unichar_combining_class (gunichar uc) G_GNUC_CONST;
+
+
+/* Compute canonical ordering of a string in-place. This rearranges
+ decomposed characters in the string according to their combining
+ classes. See the Unicode manual for more information. */
+void g_unicode_canonical_ordering (gunichar *string,
+ gsize len);
+
+/* Compute canonical decomposition of a character. Returns g_malloc()d
+ string of Unicode characters. RESULT_LEN is set to the resulting
+ length of the string. */
+gunichar *g_unicode_canonical_decomposition (gunichar ch,
+ gsize *result_len) G_GNUC_MALLOC;
+
+/* Array of skip-bytes-per-initial character.
+ */
+GLIB_VAR const gchar * const g_utf8_skip;
+
+#define g_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(const guchar *)(p)])
+
+gunichar g_utf8_get_char (const gchar *p) G_GNUC_PURE;
+gunichar g_utf8_get_char_validated (const gchar *p,
+ gssize max_len) G_GNUC_PURE;
+
+gchar* g_utf8_offset_to_pointer (const gchar *str,
+ glong offset) G_GNUC_PURE;
+glong g_utf8_pointer_to_offset (const gchar *str,
+ const gchar *pos) G_GNUC_PURE;
+gchar* g_utf8_prev_char (const gchar *p) G_GNUC_PURE;
+gchar* g_utf8_find_next_char (const gchar *p,
+ const gchar *end) G_GNUC_PURE;
+gchar* g_utf8_find_prev_char (const gchar *str,
+ const gchar *p) G_GNUC_PURE;
+
+glong g_utf8_strlen (const gchar *p,
+ gssize max) G_GNUC_PURE;
+
+/* Copies n characters from src to dest */
+gchar* g_utf8_strncpy (gchar *dest,
+ const gchar *src,
+ gsize n);
+
+/* Find the UTF-8 character corresponding to ch, in string p. These
+ functions are equivalants to strchr and strrchr */
+gchar* g_utf8_strchr (const gchar *p,
+ gssize len,
+ gunichar c);
+gchar* g_utf8_strrchr (const gchar *p,
+ gssize len,
+ gunichar c);
+gchar* g_utf8_strreverse (const gchar *str,
+ gssize len);
+
+gunichar2 *g_utf8_to_utf16 (const gchar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+gunichar * g_utf8_to_ucs4 (const gchar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+gunichar * g_utf8_to_ucs4_fast (const gchar *str,
+ glong len,
+ glong *items_written) G_GNUC_MALLOC;
+gunichar * g_utf16_to_ucs4 (const gunichar2 *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+gchar* g_utf16_to_utf8 (const gunichar2 *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+gunichar2 *g_ucs4_to_utf16 (const gunichar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+gchar* g_ucs4_to_utf8 (const gunichar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error) G_GNUC_MALLOC;
+
+/* Convert a single character into UTF-8. outbuf must have at
+ * least 6 bytes of space. Returns the number of bytes in the
+ * result.
+ */
+gint g_unichar_to_utf8 (gunichar c,
+ gchar *outbuf);
+
+/* Validate a UTF8 string, return TRUE if valid, put pointer to
+ * first invalid char in **end
+ */
+
+gboolean g_utf8_validate (const gchar *str,
+ gssize max_len,
+ const gchar **end);
+
+/* Validate a Unicode character */
+gboolean g_unichar_validate (gunichar ch) G_GNUC_CONST;
+
+gchar *g_utf8_strup (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+gchar *g_utf8_strdown (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+gchar *g_utf8_casefold (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+
+typedef enum {
+ G_NORMALIZE_DEFAULT,
+ G_NORMALIZE_NFD = G_NORMALIZE_DEFAULT,
+ G_NORMALIZE_DEFAULT_COMPOSE,
+ G_NORMALIZE_NFC = G_NORMALIZE_DEFAULT_COMPOSE,
+ G_NORMALIZE_ALL,
+ G_NORMALIZE_NFKD = G_NORMALIZE_ALL,
+ G_NORMALIZE_ALL_COMPOSE,
+ G_NORMALIZE_NFKC = G_NORMALIZE_ALL_COMPOSE
+} GNormalizeMode;
+
+gchar *g_utf8_normalize (const gchar *str,
+ gssize len,
+ GNormalizeMode mode) G_GNUC_MALLOC;
+
+gint g_utf8_collate (const gchar *str1,
+ const gchar *str2) G_GNUC_PURE;
+gchar *g_utf8_collate_key (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+gchar *g_utf8_collate_key_for_filename (const gchar *str,
+ gssize len) G_GNUC_MALLOC;
+
+gboolean g_unichar_get_mirror_char (gunichar ch,
+ gunichar *mirrored_ch);
+
+GUnicodeScript g_unichar_get_script (gunichar ch) G_GNUC_CONST;
+
+
+/* private */
+
+gchar *_g_utf8_make_valid (const gchar *name);
+
+G_END_DECLS
+
+#endif /* __G_UNICODE_H__ */
diff --git a/support/glib/gutf8.c b/support/glib/gutf8.c
new file mode 100644
index 00000000..56163f80
--- /dev/null
+++ b/support/glib/gutf8.c
@@ -0,0 +1,1866 @@
+/* gutf8.c - Operations on UTF-8 strings.
+ *
+ * Copyright (C) 1999 Tom Tromey
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#ifdef HAVE_CODESET
+#include <langinfo.h>
+#endif
+#include <string.h>
+
+#include "glib.h"
+
+#ifdef G_PLATFORM_WIN32
+#include <stdio.h>
+#define STRICT
+#include <windows.h>
+#undef STRICT
+#endif
+
+#ifdef NOT_NEEDED_FOR_NAVIT
+#include "libcharset/libcharset.h"
+
+#include "glibintl.h"
+#include "galias.h"
+#endif
+
+#define UTF8_COMPUTE(Char, Mask, Len) \
+ if (Char < 128) \
+ { \
+ Len = 1; \
+ Mask = 0x7f; \
+ } \
+ else if ((Char & 0xe0) == 0xc0) \
+ { \
+ Len = 2; \
+ Mask = 0x1f; \
+ } \
+ else if ((Char & 0xf0) == 0xe0) \
+ { \
+ Len = 3; \
+ Mask = 0x0f; \
+ } \
+ else if ((Char & 0xf8) == 0xf0) \
+ { \
+ Len = 4; \
+ Mask = 0x07; \
+ } \
+ else if ((Char & 0xfc) == 0xf8) \
+ { \
+ Len = 5; \
+ Mask = 0x03; \
+ } \
+ else if ((Char & 0xfe) == 0xfc) \
+ { \
+ Len = 6; \
+ Mask = 0x01; \
+ } \
+ else \
+ Len = -1;
+
+#define UTF8_LENGTH(Char) \
+ ((Char) < 0x80 ? 1 : \
+ ((Char) < 0x800 ? 2 : \
+ ((Char) < 0x10000 ? 3 : \
+ ((Char) < 0x200000 ? 4 : \
+ ((Char) < 0x4000000 ? 5 : 6)))))
+
+
+#define UTF8_GET(Result, Chars, Count, Mask, Len) \
+ (Result) = (Chars)[0] & (Mask); \
+ for ((Count) = 1; (Count) < (Len); ++(Count)) \
+ { \
+ if (((Chars)[(Count)] & 0xc0) != 0x80) \
+ { \
+ (Result) = -1; \
+ break; \
+ } \
+ (Result) <<= 6; \
+ (Result) |= ((Chars)[(Count)] & 0x3f); \
+ }
+
+#define UNICODE_VALID(Char) \
+ ((Char) < 0x110000 && \
+ (((Char) & 0xFFFFF800) != 0xD800) && \
+ ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
+ ((Char) & 0xFFFE) != 0xFFFE)
+
+
+static const gchar utf8_skip_data[256] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
+};
+
+const gchar * const g_utf8_skip = utf8_skip_data;
+
+/**
+ * g_utf8_find_prev_char:
+ * @str: pointer to the beginning of a UTF-8 encoded string
+ * @p: pointer to some position within @str
+ *
+ * Given a position @p with a UTF-8 encoded string @str, find the start
+ * of the previous UTF-8 character starting before @p. Returns %NULL if no
+ * UTF-8 characters are present in @str before @p.
+ *
+ * @p does not have to be at the beginning of a UTF-8 character. No check
+ * is made to see if the character found is actually valid other than
+ * it starts with an appropriate byte.
+ *
+ * Return value: a pointer to the found character or %NULL.
+ **/
+gchar *
+g_utf8_find_prev_char (const char *str,
+ const char *p)
+{
+ for (--p; p >= str; --p)
+ {
+ if ((*p & 0xc0) != 0x80)
+ return (gchar *)p;
+ }
+ return NULL;
+}
+
+/**
+ * g_utf8_find_next_char:
+ * @p: a pointer to a position within a UTF-8 encoded string
+ * @end: a pointer to the byte following the end of the string,
+ * or %NULL to indicate that the string is nul-terminated.
+ *
+ * Finds the start of the next UTF-8 character in the string after @p.
+ *
+ * @p does not have to be at the beginning of a UTF-8 character. No check
+ * is made to see if the character found is actually valid other than
+ * it starts with an appropriate byte.
+ *
+ * Return value: a pointer to the found character or %NULL
+ **/
+gchar *
+g_utf8_find_next_char (const gchar *p,
+ const gchar *end)
+{
+ if (*p)
+ {
+ if (end)
+ for (++p; p < end && (*p & 0xc0) == 0x80; ++p)
+ ;
+ else
+ for (++p; (*p & 0xc0) == 0x80; ++p)
+ ;
+ }
+ return (p == end) ? NULL : (gchar *)p;
+}
+
+/**
+ * g_utf8_prev_char:
+ * @p: a pointer to a position within a UTF-8 encoded string
+ *
+ * Finds the previous UTF-8 character in the string before @p.
+ *
+ * @p does not have to be at the beginning of a UTF-8 character. No check
+ * is made to see if the character found is actually valid other than
+ * it starts with an appropriate byte. If @p might be the first
+ * character of the string, you must use g_utf8_find_prev_char() instead.
+ *
+ * Return value: a pointer to the found character.
+ **/
+gchar *
+g_utf8_prev_char (const gchar *p)
+{
+ while (TRUE)
+ {
+ p--;
+ if ((*p & 0xc0) != 0x80)
+ return (gchar *)p;
+ }
+}
+
+/**
+ * g_utf8_strlen:
+ * @p: pointer to the start of a UTF-8 encoded string.
+ * @max: the maximum number of bytes to examine. If @max
+ * is less than 0, then the string is assumed to be
+ * nul-terminated. If @max is 0, @p will not be examined and
+ * may be %NULL.
+ *
+ * Returns the length of the string in characters.
+ *
+ * Return value: the length of the string in characters
+ **/
+glong
+g_utf8_strlen (const gchar *p,
+ gssize max)
+{
+ glong len = 0;
+ const gchar *start = p;
+ g_return_val_if_fail (p != NULL || max == 0, 0);
+
+ if (max < 0)
+ {
+ while (*p)
+ {
+ p = g_utf8_next_char (p);
+ ++len;
+ }
+ }
+ else
+ {
+ if (max == 0 || !*p)
+ return 0;
+
+ p = g_utf8_next_char (p);
+
+ while (p - start < max && *p)
+ {
+ ++len;
+ p = g_utf8_next_char (p);
+ }
+
+ /* only do the last len increment if we got a complete
+ * char (don't count partial chars)
+ */
+ if (p - start <= max)
+ ++len;
+ }
+
+ return len;
+}
+
+/**
+ * g_utf8_get_char:
+ * @p: a pointer to Unicode character encoded as UTF-8
+ *
+ * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
+ * If @p does not point to a valid UTF-8 encoded character, results are
+ * undefined. If you are not sure that the bytes are complete
+ * valid Unicode characters, you should use g_utf8_get_char_validated()
+ * instead.
+ *
+ * Return value: the resulting character
+ **/
+gunichar
+g_utf8_get_char (const gchar *p)
+{
+ int i, mask = 0, len;
+ gunichar result;
+ unsigned char c = (unsigned char) *p;
+
+ UTF8_COMPUTE (c, mask, len);
+ if (len == -1)
+ return (gunichar)-1;
+ UTF8_GET (result, p, i, mask, len);
+
+ return result;
+}
+
+#ifdef NOT_NEEDED_FOR_NAVIT
+
+/**
+ * g_utf8_offset_to_pointer:
+ * @str: a UTF-8 encoded string
+ * @offset: a character offset within @str
+ *
+ * Converts from an integer character offset to a pointer to a position
+ * within the string.
+ *
+ * Since 2.10, this function allows to pass a negative @offset to
+ * step backwards. It is usually worth stepping backwards from the end
+ * instead of forwards if @offset is in the last fourth of the string,
+ * since moving forward is about 3 times faster than moving backward.
+ *
+ * Return value: the resulting pointer
+ **/
+gchar *
+g_utf8_offset_to_pointer (const gchar *str,
+ glong offset)
+{
+ const gchar *s = str;
+
+ if (offset > 0)
+ while (offset--)
+ s = g_utf8_next_char (s);
+ else
+ {
+ const char *s1;
+
+ /* This nice technique for fast backwards stepping
+ * through a UTF-8 string was dubbed "stutter stepping"
+ * by its inventor, Larry Ewing.
+ */
+ while (offset)
+ {
+ s1 = s;
+ s += offset;
+ while ((*s & 0xc0) == 0x80)
+ s--;
+
+ offset += g_utf8_pointer_to_offset (s, s1);
+ }
+ }
+
+ return (gchar *)s;
+}
+
+/**
+ * g_utf8_pointer_to_offset:
+ * @str: a UTF-8 encoded string
+ * @pos: a pointer to a position within @str
+ *
+ * Converts from a pointer to position within a string to a integer
+ * character offset.
+ *
+ * Since 2.10, this function allows @pos to be before @str, and returns
+ * a negative offset in this case.
+ *
+ * Return value: the resulting character offset
+ **/
+glong
+g_utf8_pointer_to_offset (const gchar *str,
+ const gchar *pos)
+{
+ const gchar *s = str;
+ glong offset = 0;
+
+ if (pos < str)
+ offset = - g_utf8_pointer_to_offset (pos, str);
+ else
+ while (s < pos)
+ {
+ s = g_utf8_next_char (s);
+ offset++;
+ }
+
+ return offset;
+}
+
+
+/**
+ * g_utf8_strncpy:
+ * @dest: buffer to fill with characters from @src
+ * @src: UTF-8 encoded string
+ * @n: character count
+ *
+ * Like the standard C strncpy() function, but
+ * copies a given number of characters instead of a given number of
+ * bytes. The @src string must be valid UTF-8 encoded text.
+ * (Use g_utf8_validate() on all text before trying to use UTF-8
+ * utility functions with it.)
+ *
+ * Return value: @dest
+ **/
+gchar *
+g_utf8_strncpy (gchar *dest,
+ const gchar *src,
+ gsize n)
+{
+ const gchar *s = src;
+ while (n && *s)
+ {
+ s = g_utf8_next_char(s);
+ n--;
+ }
+ strncpy(dest, src, s - src);
+ dest[s - src] = 0;
+ return dest;
+}
+
+G_LOCK_DEFINE_STATIC (aliases);
+
+static GHashTable *
+get_alias_hash (void)
+{
+ static GHashTable *alias_hash = NULL;
+ const char *aliases;
+
+ G_LOCK (aliases);
+
+ if (!alias_hash)
+ {
+ alias_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ aliases = _g_locale_get_charset_aliases ();
+ while (*aliases != '\0')
+ {
+ const char *canonical;
+ const char *alias;
+ const char **alias_array;
+ int count = 0;
+
+ alias = aliases;
+ aliases += strlen (aliases) + 1;
+ canonical = aliases;
+ aliases += strlen (aliases) + 1;
+
+ alias_array = g_hash_table_lookup (alias_hash, canonical);
+ if (alias_array)
+ {
+ while (alias_array[count])
+ count++;
+ }
+
+ alias_array = g_renew (const char *, alias_array, count + 2);
+ alias_array[count] = alias;
+ alias_array[count + 1] = NULL;
+
+ g_hash_table_insert (alias_hash, (char *)canonical, alias_array);
+ }
+ }
+
+ G_UNLOCK (aliases);
+
+ return alias_hash;
+}
+
+/* As an abuse of the alias table, the following routines gets
+ * the charsets that are aliases for the canonical name.
+ */
+G_GNUC_INTERNAL const char **
+_g_charset_get_aliases (const char *canonical_name)
+{
+ GHashTable *alias_hash = get_alias_hash ();
+
+ return g_hash_table_lookup (alias_hash, canonical_name);
+}
+
+static gboolean
+g_utf8_get_charset_internal (const char *raw_data,
+ const char **a)
+{
+ const char *charset = getenv("CHARSET");
+
+ if (charset && *charset)
+ {
+ *a = charset;
+
+ if (charset && strstr (charset, "UTF-8"))
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ /* The libcharset code tries to be thread-safe without
+ * a lock, but has a memory leak and a missing memory
+ * barrier, so we lock for it
+ */
+ G_LOCK (aliases);
+ charset = _g_locale_charset_unalias (raw_data);
+ G_UNLOCK (aliases);
+
+ if (charset && *charset)
+ {
+ *a = charset;
+
+ if (charset && strstr (charset, "UTF-8"))
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ /* Assume this for compatibility at present. */
+ *a = "US-ASCII";
+
+ return FALSE;
+}
+
+typedef struct _GCharsetCache GCharsetCache;
+
+struct _GCharsetCache {
+ gboolean is_utf8;
+ gchar *raw;
+ gchar *charset;
+};
+
+static void
+charset_cache_free (gpointer data)
+{
+ GCharsetCache *cache = data;
+ g_free (cache->raw);
+ g_free (cache->charset);
+ g_free (cache);
+}
+
+/**
+ * g_get_charset:
+ * @charset: return location for character set name
+ *
+ * Obtains the character set for the <link linkend="setlocale">current
+ * locale</link>; you might use this character set as an argument to
+ * g_convert(), to convert from the current locale's encoding to some
+ * other encoding. (Frequently g_locale_to_utf8() and g_locale_from_utf8()
+ * are nice shortcuts, though.)
+ *
+ * On Windows the character set returned by this function is the
+ * so-called system default ANSI code-page. That is the character set
+ * used by the "narrow" versions of C library and Win32 functions that
+ * handle file names. It might be different from the character set
+ * used by the C library's current locale.
+ *
+ * The return value is %TRUE if the locale's encoding is UTF-8, in that
+ * case you can perhaps avoid calling g_convert().
+ *
+ * The string returned in @charset is not allocated, and should not be
+ * freed.
+ *
+ * Return value: %TRUE if the returned charset is UTF-8
+ **/
+gboolean
+g_get_charset (G_CONST_RETURN char **charset)
+{
+ static GStaticPrivate cache_private = G_STATIC_PRIVATE_INIT;
+ GCharsetCache *cache = g_static_private_get (&cache_private);
+ const gchar *raw;
+
+ if (!cache)
+ {
+ cache = g_new0 (GCharsetCache, 1);
+ g_static_private_set (&cache_private, cache, charset_cache_free);
+ }
+
+ raw = _g_locale_charset_raw ();
+
+ if (!(cache->raw && strcmp (cache->raw, raw) == 0))
+ {
+ const gchar *new_charset;
+
+ g_free (cache->raw);
+ g_free (cache->charset);
+ cache->raw = g_strdup (raw);
+ cache->is_utf8 = g_utf8_get_charset_internal (raw, &new_charset);
+ cache->charset = g_strdup (new_charset);
+ }
+
+ if (charset)
+ *charset = cache->charset;
+
+ return cache->is_utf8;
+}
+
+/* unicode_strchr */
+
+/**
+ * g_unichar_to_utf8:
+ * @c: a Unicode character code
+ * @outbuf: output buffer, must have at least 6 bytes of space.
+ * If %NULL, the length will be computed and returned
+ * and nothing will be written to @outbuf.
+ *
+ * Converts a single character to UTF-8.
+ *
+ * Return value: number of bytes written
+ **/
+int
+g_unichar_to_utf8 (gunichar c,
+ gchar *outbuf)
+{
+ /* If this gets modified, also update the copy in g_string_insert_unichar() */
+ guint len = 0;
+ int first;
+ int i;
+
+ if (c < 0x80)
+ {
+ first = 0;
+ len = 1;
+ }
+ else if (c < 0x800)
+ {
+ first = 0xc0;
+ len = 2;
+ }
+ else if (c < 0x10000)
+ {
+ first = 0xe0;
+ len = 3;
+ }
+ else if (c < 0x200000)
+ {
+ first = 0xf0;
+ len = 4;
+ }
+ else if (c < 0x4000000)
+ {
+ first = 0xf8;
+ len = 5;
+ }
+ else
+ {
+ first = 0xfc;
+ len = 6;
+ }
+
+ if (outbuf)
+ {
+ for (i = len - 1; i > 0; --i)
+ {
+ outbuf[i] = (c & 0x3f) | 0x80;
+ c >>= 6;
+ }
+ outbuf[0] = c | first;
+ }
+
+ return len;
+}
+
+/**
+ * g_utf8_strchr:
+ * @p: a nul-terminated UTF-8 encoded string
+ * @len: the maximum length of @p
+ * @c: a Unicode character
+ *
+ * Finds the leftmost occurrence of the given Unicode character
+ * in a UTF-8 encoded string, while limiting the search to @len bytes.
+ * If @len is -1, allow unbounded search.
+ *
+ * Return value: %NULL if the string does not contain the character,
+ * otherwise, a pointer to the start of the leftmost occurrence of
+ * the character in the string.
+ **/
+gchar *
+g_utf8_strchr (const char *p,
+ gssize len,
+ gunichar c)
+{
+ gchar ch[10];
+
+ gint charlen = g_unichar_to_utf8 (c, ch);
+ ch[charlen] = '\0';
+
+ return g_strstr_len (p, len, ch);
+}
+
+
+/**
+ * g_utf8_strrchr:
+ * @p: a nul-terminated UTF-8 encoded string
+ * @len: the maximum length of @p
+ * @c: a Unicode character
+ *
+ * Find the rightmost occurrence of the given Unicode character
+ * in a UTF-8 encoded string, while limiting the search to @len bytes.
+ * If @len is -1, allow unbounded search.
+ *
+ * Return value: %NULL if the string does not contain the character,
+ * otherwise, a pointer to the start of the rightmost occurrence of the
+ * character in the string.
+ **/
+gchar *
+g_utf8_strrchr (const char *p,
+ gssize len,
+ gunichar c)
+{
+ gchar ch[10];
+
+ gint charlen = g_unichar_to_utf8 (c, ch);
+ ch[charlen] = '\0';
+
+ return g_strrstr_len (p, len, ch);
+}
+
+
+/* Like g_utf8_get_char, but take a maximum length
+ * and return (gunichar)-2 on incomplete trailing character
+ */
+static inline gunichar
+g_utf8_get_char_extended (const gchar *p,
+ gssize max_len)
+{
+ guint i, len;
+ gunichar wc = (guchar) *p;
+
+ if (wc < 0x80)
+ {
+ return wc;
+ }
+ else if (wc < 0xc0)
+ {
+ return (gunichar)-1;
+ }
+ else if (wc < 0xe0)
+ {
+ len = 2;
+ wc &= 0x1f;
+ }
+ else if (wc < 0xf0)
+ {
+ len = 3;
+ wc &= 0x0f;
+ }
+ else if (wc < 0xf8)
+ {
+ len = 4;
+ wc &= 0x07;
+ }
+ else if (wc < 0xfc)
+ {
+ len = 5;
+ wc &= 0x03;
+ }
+ else if (wc < 0xfe)
+ {
+ len = 6;
+ wc &= 0x01;
+ }
+ else
+ {
+ return (gunichar)-1;
+ }
+
+ if (max_len >= 0 && len > max_len)
+ {
+ for (i = 1; i < max_len; i++)
+ {
+ if ((((guchar *)p)[i] & 0xc0) != 0x80)
+ return (gunichar)-1;
+ }
+ return (gunichar)-2;
+ }
+
+ for (i = 1; i < len; ++i)
+ {
+ gunichar ch = ((guchar *)p)[i];
+
+ if ((ch & 0xc0) != 0x80)
+ {
+ if (ch)
+ return (gunichar)-1;
+ else
+ return (gunichar)-2;
+ }
+
+ wc <<= 6;
+ wc |= (ch & 0x3f);
+ }
+
+ if (UTF8_LENGTH(wc) != len)
+ return (gunichar)-1;
+
+ return wc;
+}
+
+/**
+ * g_utf8_get_char_validated:
+ * @p: a pointer to Unicode character encoded as UTF-8
+ * @max_len: the maximum number of bytes to read, or -1, for no maximum or
+ * if @p is nul-terminated
+ *
+ * Convert a sequence of bytes encoded as UTF-8 to a Unicode character.
+ * This function checks for incomplete characters, for invalid characters
+ * such as characters that are out of the range of Unicode, and for
+ * overlong encodings of valid characters.
+ *
+ * Return value: the resulting character. If @p points to a partial
+ * sequence at the end of a string that could begin a valid
+ * character (or if @max_len is zero), returns (gunichar)-2;
+ * otherwise, if @p does not point to a valid UTF-8 encoded
+ * Unicode character, returns (gunichar)-1.
+ **/
+gunichar
+g_utf8_get_char_validated (const gchar *p,
+ gssize max_len)
+{
+ gunichar result;
+
+ if (max_len == 0)
+ return (gunichar)-2;
+
+ result = g_utf8_get_char_extended (p, max_len);
+
+ if (result & 0x80000000)
+ return result;
+ else if (!UNICODE_VALID (result))
+ return (gunichar)-1;
+ else
+ return result;
+}
+
+/**
+ * g_utf8_to_ucs4_fast:
+ * @str: a UTF-8 encoded string
+ * @len: the maximum length of @str to use, in bytes. If @len < 0,
+ * then the string is nul-terminated.
+ * @items_written: location to store the number of characters in the
+ * result, or %NULL.
+ *
+ * Convert a string from UTF-8 to a 32-bit fixed width
+ * representation as UCS-4, assuming valid UTF-8 input.
+ * This function is roughly twice as fast as g_utf8_to_ucs4()
+ * but does no error checking on the input.
+ *
+ * Return value: a pointer to a newly allocated UCS-4 string.
+ * This value must be freed with g_free().
+ **/
+gunichar *
+g_utf8_to_ucs4_fast (const gchar *str,
+ glong len,
+ glong *items_written)
+{
+ gint j, charlen;
+ gunichar *result;
+ gint n_chars, i;
+ const gchar *p;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ p = str;
+ n_chars = 0;
+ if (len < 0)
+ {
+ while (*p)
+ {
+ p = g_utf8_next_char (p);
+ ++n_chars;
+ }
+ }
+ else
+ {
+ while (p < str + len && *p)
+ {
+ p = g_utf8_next_char (p);
+ ++n_chars;
+ }
+ }
+
+ result = g_new (gunichar, n_chars + 1);
+
+ p = str;
+ for (i=0; i < n_chars; i++)
+ {
+ gunichar wc = ((unsigned char *)p)[0];
+
+ if (wc < 0x80)
+ {
+ result[i] = wc;
+ p++;
+ }
+ else
+ {
+ if (wc < 0xe0)
+ {
+ charlen = 2;
+ wc &= 0x1f;
+ }
+ else if (wc < 0xf0)
+ {
+ charlen = 3;
+ wc &= 0x0f;
+ }
+ else if (wc < 0xf8)
+ {
+ charlen = 4;
+ wc &= 0x07;
+ }
+ else if (wc < 0xfc)
+ {
+ charlen = 5;
+ wc &= 0x03;
+ }
+ else
+ {
+ charlen = 6;
+ wc &= 0x01;
+ }
+
+ for (j = 1; j < charlen; j++)
+ {
+ wc <<= 6;
+ wc |= ((unsigned char *)p)[j] & 0x3f;
+ }
+
+ result[i] = wc;
+ p += charlen;
+ }
+ }
+ result[i] = 0;
+
+ if (items_written)
+ *items_written = i;
+
+ return result;
+}
+
+/**
+ * g_utf8_to_ucs4:
+ * @str: a UTF-8 encoded string
+ * @len: the maximum length of @str to use, in bytes. If @len < 0,
+ * then the string is nul-terminated.
+ * @items_read: location to store number of bytes read, or %NULL.
+ * If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
+ * returned in case @str contains a trailing partial
+ * character. If an error occurs then the index of the
+ * invalid input is stored here.
+ * @items_written: location to store number of characters written or %NULL.
+ * The value here stored does not include the trailing 0
+ * character.
+ * @error: location to store the error occuring, or %NULL to ignore
+ * errors. Any of the errors in #GConvertError other than
+ * %G_CONVERT_ERROR_NO_CONVERSION may occur.
+ *
+ * Convert a string from UTF-8 to a 32-bit fixed width
+ * representation as UCS-4. A trailing 0 will be added to the
+ * string after the converted text.
+ *
+ * Return value: a pointer to a newly allocated UCS-4 string.
+ * This value must be freed with g_free(). If an
+ * error occurs, %NULL will be returned and
+ * @error set.
+ **/
+gunichar *
+g_utf8_to_ucs4 (const gchar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error)
+{
+ gunichar *result = NULL;
+ gint n_chars, i;
+ const gchar *in;
+
+ in = str;
+ n_chars = 0;
+ while ((len < 0 || str + len - in > 0) && *in)
+ {
+ gunichar wc = g_utf8_get_char_extended (in, len < 0 ? 6 : str + len - in);
+ if (wc & 0x80000000)
+ {
+ if (wc == (gunichar)-2)
+ {
+ if (items_read)
+ break;
+ else
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
+ _("Partial character sequence at end of input"));
+ }
+ else
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Invalid byte sequence in conversion input"));
+
+ goto err_out;
+ }
+
+ n_chars++;
+
+ in = g_utf8_next_char (in);
+ }
+
+ result = g_new (gunichar, n_chars + 1);
+
+ in = str;
+ for (i=0; i < n_chars; i++)
+ {
+ result[i] = g_utf8_get_char (in);
+ in = g_utf8_next_char (in);
+ }
+ result[i] = 0;
+
+ if (items_written)
+ *items_written = n_chars;
+
+ err_out:
+ if (items_read)
+ *items_read = in - str;
+
+ return result;
+}
+
+/**
+ * g_ucs4_to_utf8:
+ * @str: a UCS-4 encoded string
+ * @len: the maximum length (number of characters) of @str to use.
+ * If @len < 0, then the string is nul-terminated.
+ * @items_read: location to store number of characters read, or %NULL.
+ * @items_written: location to store number of bytes written or %NULL.
+ * The value here stored does not include the trailing 0
+ * byte.
+ * @error: location to store the error occuring, or %NULL to ignore
+ * errors. Any of the errors in #GConvertError other than
+ * %G_CONVERT_ERROR_NO_CONVERSION may occur.
+ *
+ * Convert a string from a 32-bit fixed width representation as UCS-4.
+ * to UTF-8. The result will be terminated with a 0 byte.
+ *
+ * Return value: a pointer to a newly allocated UTF-8 string.
+ * This value must be freed with g_free(). If an
+ * error occurs, %NULL will be returned and
+ * @error set. In that case, @items_read will be
+ * set to the position of the first invalid input
+ * character.
+ **/
+gchar *
+g_ucs4_to_utf8 (const gunichar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error)
+{
+ gint result_length;
+ gchar *result = NULL;
+ gchar *p;
+ gint i;
+
+ result_length = 0;
+ for (i = 0; len < 0 || i < len ; i++)
+ {
+ if (!str[i])
+ break;
+
+ if (str[i] >= 0x80000000)
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Character out of range for UTF-8"));
+ goto err_out;
+ }
+
+ result_length += UTF8_LENGTH (str[i]);
+ }
+
+ result = g_malloc (result_length + 1);
+ p = result;
+
+ i = 0;
+ while (p < result + result_length)
+ p += g_unichar_to_utf8 (str[i++], p);
+
+ *p = '\0';
+
+ if (items_written)
+ *items_written = p - result;
+
+ err_out:
+ if (items_read)
+ *items_read = i;
+
+ return result;
+}
+
+#define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000)
+
+/**
+ * g_utf16_to_utf8:
+ * @str: a UTF-16 encoded string
+ * @len: the maximum length (number of <type>gunichar2</type>) of @str to use.
+ * If @len < 0, then the string is nul-terminated.
+ * @items_read: location to store number of words read, or %NULL.
+ * If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
+ * returned in case @str contains a trailing partial
+ * character. If an error occurs then the index of the
+ * invalid input is stored here.
+ * @items_written: location to store number of bytes written, or %NULL.
+ * The value stored here does not include the trailing
+ * 0 byte.
+ * @error: location to store the error occuring, or %NULL to ignore
+ * errors. Any of the errors in #GConvertError other than
+ * %G_CONVERT_ERROR_NO_CONVERSION may occur.
+ *
+ * Convert a string from UTF-16 to UTF-8. The result will be
+ * terminated with a 0 byte.
+ *
+ * Note that the input is expected to be already in native endianness,
+ * an initial byte-order-mark character is not handled specially.
+ * g_convert() can be used to convert a byte buffer of UTF-16 data of
+ * ambiguous endianess.
+ *
+ * Return value: a pointer to a newly allocated UTF-8 string.
+ * This value must be freed with g_free(). If an
+ * error occurs, %NULL will be returned and
+ * @error set.
+ **/
+gchar *
+g_utf16_to_utf8 (const gunichar2 *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error)
+{
+ /* This function and g_utf16_to_ucs4 are almost exactly identical - The lines that differ
+ * are marked.
+ */
+ const gunichar2 *in;
+ gchar *out;
+ gchar *result = NULL;
+ gint n_bytes;
+ gunichar high_surrogate;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ n_bytes = 0;
+ in = str;
+ high_surrogate = 0;
+ while ((len < 0 || in - str < len) && *in)
+ {
+ gunichar2 c = *in;
+ gunichar wc;
+
+ if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
+ {
+ if (high_surrogate)
+ {
+ wc = SURROGATE_VALUE (high_surrogate, c);
+ high_surrogate = 0;
+ }
+ else
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Invalid sequence in conversion input"));
+ goto err_out;
+ }
+ }
+ else
+ {
+ if (high_surrogate)
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Invalid sequence in conversion input"));
+ goto err_out;
+ }
+
+ if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
+ {
+ high_surrogate = c;
+ goto next1;
+ }
+ else
+ wc = c;
+ }
+
+ /********** DIFFERENT for UTF8/UCS4 **********/
+ n_bytes += UTF8_LENGTH (wc);
+
+ next1:
+ in++;
+ }
+
+ if (high_surrogate && !items_read)
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
+ _("Partial character sequence at end of input"));
+ goto err_out;
+ }
+
+ /* At this point, everything is valid, and we just need to convert
+ */
+ /********** DIFFERENT for UTF8/UCS4 **********/
+ result = g_malloc (n_bytes + 1);
+
+ high_surrogate = 0;
+ out = result;
+ in = str;
+ while (out < result + n_bytes)
+ {
+ gunichar2 c = *in;
+ gunichar wc;
+
+ if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
+ {
+ wc = SURROGATE_VALUE (high_surrogate, c);
+ high_surrogate = 0;
+ }
+ else if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
+ {
+ high_surrogate = c;
+ goto next2;
+ }
+ else
+ wc = c;
+
+ /********** DIFFERENT for UTF8/UCS4 **********/
+ out += g_unichar_to_utf8 (wc, out);
+
+ next2:
+ in++;
+ }
+
+ /********** DIFFERENT for UTF8/UCS4 **********/
+ *out = '\0';
+
+ if (items_written)
+ /********** DIFFERENT for UTF8/UCS4 **********/
+ *items_written = out - result;
+
+ err_out:
+ if (items_read)
+ *items_read = in - str;
+
+ return result;
+}
+
+/**
+ * g_utf16_to_ucs4:
+ * @str: a UTF-16 encoded string
+ * @len: the maximum length (number of <type>gunichar2</type>) of @str to use.
+ * If @len < 0, then the string is nul-terminated.
+ * @items_read: location to store number of words read, or %NULL.
+ * If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
+ * returned in case @str contains a trailing partial
+ * character. If an error occurs then the index of the
+ * invalid input is stored here.
+ * @items_written: location to store number of characters written, or %NULL.
+ * The value stored here does not include the trailing
+ * 0 character.
+ * @error: location to store the error occuring, or %NULL to ignore
+ * errors. Any of the errors in #GConvertError other than
+ * %G_CONVERT_ERROR_NO_CONVERSION may occur.
+ *
+ * Convert a string from UTF-16 to UCS-4. The result will be
+ * nul-terminated.
+ *
+ * Return value: a pointer to a newly allocated UCS-4 string.
+ * This value must be freed with g_free(). If an
+ * error occurs, %NULL will be returned and
+ * @error set.
+ **/
+gunichar *
+g_utf16_to_ucs4 (const gunichar2 *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error)
+{
+ const gunichar2 *in;
+ gchar *out;
+ gchar *result = NULL;
+ gint n_bytes;
+ gunichar high_surrogate;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ n_bytes = 0;
+ in = str;
+ high_surrogate = 0;
+ while ((len < 0 || in - str < len) && *in)
+ {
+ gunichar2 c = *in;
+ gunichar wc;
+
+ if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
+ {
+ if (high_surrogate)
+ {
+ wc = SURROGATE_VALUE (high_surrogate, c);
+ high_surrogate = 0;
+ }
+ else
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Invalid sequence in conversion input"));
+ goto err_out;
+ }
+ }
+ else
+ {
+ if (high_surrogate)
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Invalid sequence in conversion input"));
+ goto err_out;
+ }
+
+ if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
+ {
+ high_surrogate = c;
+ goto next1;
+ }
+ else
+ wc = c;
+ }
+
+ /********** DIFFERENT for UTF8/UCS4 **********/
+ n_bytes += sizeof (gunichar);
+
+ next1:
+ in++;
+ }
+
+ if (high_surrogate && !items_read)
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
+ _("Partial character sequence at end of input"));
+ goto err_out;
+ }
+
+ /* At this point, everything is valid, and we just need to convert
+ */
+ /********** DIFFERENT for UTF8/UCS4 **********/
+ result = g_malloc (n_bytes + 4);
+
+ high_surrogate = 0;
+ out = result;
+ in = str;
+ while (out < result + n_bytes)
+ {
+ gunichar2 c = *in;
+ gunichar wc;
+
+ if (c >= 0xdc00 && c < 0xe000) /* low surrogate */
+ {
+ wc = SURROGATE_VALUE (high_surrogate, c);
+ high_surrogate = 0;
+ }
+ else if (c >= 0xd800 && c < 0xdc00) /* high surrogate */
+ {
+ high_surrogate = c;
+ goto next2;
+ }
+ else
+ wc = c;
+
+ /********** DIFFERENT for UTF8/UCS4 **********/
+ *(gunichar *)out = wc;
+ out += sizeof (gunichar);
+
+ next2:
+ in++;
+ }
+
+ /********** DIFFERENT for UTF8/UCS4 **********/
+ *(gunichar *)out = 0;
+
+ if (items_written)
+ /********** DIFFERENT for UTF8/UCS4 **********/
+ *items_written = (out - result) / sizeof (gunichar);
+
+ err_out:
+ if (items_read)
+ *items_read = in - str;
+
+ return (gunichar *)result;
+}
+
+/**
+ * g_utf8_to_utf16:
+ * @str: a UTF-8 encoded string
+ * @len: the maximum length (number of characters) of @str to use.
+ * If @len < 0, then the string is nul-terminated.
+ * @items_read: location to store number of bytes read, or %NULL.
+ * If %NULL, then %G_CONVERT_ERROR_PARTIAL_INPUT will be
+ * returned in case @str contains a trailing partial
+ * character. If an error occurs then the index of the
+ * invalid input is stored here.
+ * @items_written: location to store number of <type>gunichar2</type> written,
+ * or %NULL.
+ * The value stored here does not include the trailing 0.
+ * @error: location to store the error occuring, or %NULL to ignore
+ * errors. Any of the errors in #GConvertError other than
+ * %G_CONVERT_ERROR_NO_CONVERSION may occur.
+ *
+ * Convert a string from UTF-8 to UTF-16. A 0 character will be
+ * added to the result after the converted text.
+ *
+ * Return value: a pointer to a newly allocated UTF-16 string.
+ * This value must be freed with g_free(). If an
+ * error occurs, %NULL will be returned and
+ * @error set.
+ **/
+gunichar2 *
+g_utf8_to_utf16 (const gchar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error)
+{
+ gunichar2 *result = NULL;
+ gint n16;
+ const gchar *in;
+ gint i;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ in = str;
+ n16 = 0;
+ while ((len < 0 || str + len - in > 0) && *in)
+ {
+ gunichar wc = g_utf8_get_char_extended (in, len < 0 ? 6 : str + len - in);
+ if (wc & 0x80000000)
+ {
+ if (wc == (gunichar)-2)
+ {
+ if (items_read)
+ break;
+ else
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
+ _("Partial character sequence at end of input"));
+ }
+ else
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Invalid byte sequence in conversion input"));
+
+ goto err_out;
+ }
+
+ if (wc < 0xd800)
+ n16 += 1;
+ else if (wc < 0xe000)
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Invalid sequence in conversion input"));
+
+ goto err_out;
+ }
+ else if (wc < 0x10000)
+ n16 += 1;
+ else if (wc < 0x110000)
+ n16 += 2;
+ else
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Character out of range for UTF-16"));
+
+ goto err_out;
+ }
+
+ in = g_utf8_next_char (in);
+ }
+
+ result = g_new (gunichar2, n16 + 1);
+
+ in = str;
+ for (i = 0; i < n16;)
+ {
+ gunichar wc = g_utf8_get_char (in);
+
+ if (wc < 0x10000)
+ {
+ result[i++] = wc;
+ }
+ else
+ {
+ result[i++] = (wc - 0x10000) / 0x400 + 0xd800;
+ result[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
+ }
+
+ in = g_utf8_next_char (in);
+ }
+
+ result[i] = 0;
+
+ if (items_written)
+ *items_written = n16;
+
+ err_out:
+ if (items_read)
+ *items_read = in - str;
+
+ return result;
+}
+
+/**
+ * g_ucs4_to_utf16:
+ * @str: a UCS-4 encoded string
+ * @len: the maximum length (number of characters) of @str to use.
+ * If @len < 0, then the string is nul-terminated.
+ * @items_read: location to store number of bytes read, or %NULL.
+ * If an error occurs then the index of the invalid input
+ * is stored here.
+ * @items_written: location to store number of <type>gunichar2</type>
+ * written, or %NULL. The value stored here does not
+ * include the trailing 0.
+ * @error: location to store the error occuring, or %NULL to ignore
+ * errors. Any of the errors in #GConvertError other than
+ * %G_CONVERT_ERROR_NO_CONVERSION may occur.
+ *
+ * Convert a string from UCS-4 to UTF-16. A 0 character will be
+ * added to the result after the converted text.
+ *
+ * Return value: a pointer to a newly allocated UTF-16 string.
+ * This value must be freed with g_free(). If an
+ * error occurs, %NULL will be returned and
+ * @error set.
+ **/
+gunichar2 *
+g_ucs4_to_utf16 (const gunichar *str,
+ glong len,
+ glong *items_read,
+ glong *items_written,
+ GError **error)
+{
+ gunichar2 *result = NULL;
+ gint n16;
+ gint i, j;
+
+ n16 = 0;
+ i = 0;
+ while ((len < 0 || i < len) && str[i])
+ {
+ gunichar wc = str[i];
+
+ if (wc < 0xd800)
+ n16 += 1;
+ else if (wc < 0xe000)
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Invalid sequence in conversion input"));
+
+ goto err_out;
+ }
+ else if (wc < 0x10000)
+ n16 += 1;
+ else if (wc < 0x110000)
+ n16 += 2;
+ else
+ {
+ g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+ _("Character out of range for UTF-16"));
+
+ goto err_out;
+ }
+
+ i++;
+ }
+
+ result = g_new (gunichar2, n16 + 1);
+
+ for (i = 0, j = 0; j < n16; i++)
+ {
+ gunichar wc = str[i];
+
+ if (wc < 0x10000)
+ {
+ result[j++] = wc;
+ }
+ else
+ {
+ result[j++] = (wc - 0x10000) / 0x400 + 0xd800;
+ result[j++] = (wc - 0x10000) % 0x400 + 0xdc00;
+ }
+ }
+ result[j] = 0;
+
+ if (items_written)
+ *items_written = n16;
+
+ err_out:
+ if (items_read)
+ *items_read = i;
+
+ return result;
+}
+
+#define CONTINUATION_CHAR \
+ G_STMT_START { \
+ if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */ \
+ goto error; \
+ val <<= 6; \
+ val |= (*(guchar *)p) & 0x3f; \
+ } G_STMT_END
+
+static const gchar *
+fast_validate (const char *str)
+
+{
+ gunichar val = 0;
+ gunichar min = 0;
+ const gchar *p;
+
+ for (p = str; *p; p++)
+ {
+ if (*(guchar *)p < 128)
+ /* done */;
+ else
+ {
+ const gchar *last;
+
+ last = p;
+ if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */
+ {
+ if (G_UNLIKELY ((*(guchar *)p & 0x1e) == 0))
+ goto error;
+ p++;
+ if (G_UNLIKELY ((*(guchar *)p & 0xc0) != 0x80)) /* 10xxxxxx */
+ goto error;
+ }
+ else
+ {
+ if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */
+ {
+ min = (1 << 11);
+ val = *(guchar *)p & 0x0f;
+ goto TWO_REMAINING;
+ }
+ else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */
+ {
+ min = (1 << 16);
+ val = *(guchar *)p & 0x07;
+ }
+ else
+ goto error;
+
+ p++;
+ CONTINUATION_CHAR;
+ TWO_REMAINING:
+ p++;
+ CONTINUATION_CHAR;
+ p++;
+ CONTINUATION_CHAR;
+
+ if (G_UNLIKELY (val < min))
+ goto error;
+
+ if (G_UNLIKELY (!UNICODE_VALID(val)))
+ goto error;
+ }
+
+ continue;
+
+ error:
+ return last;
+ }
+ }
+
+ return p;
+}
+
+static const gchar *
+fast_validate_len (const char *str,
+ gssize max_len)
+
+{
+ gunichar val = 0;
+ gunichar min = 0;
+ const gchar *p;
+
+ g_assert (max_len >= 0);
+
+ for (p = str; ((p - str) < max_len) && *p; p++)
+ {
+ if (*(guchar *)p < 128)
+ /* done */;
+ else
+ {
+ const gchar *last;
+
+ last = p;
+ if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */
+ {
+ if (G_UNLIKELY (max_len - (p - str) < 2))
+ goto error;
+
+ if (G_UNLIKELY ((*(guchar *)p & 0x1e) == 0))
+ goto error;
+ p++;
+ if (G_UNLIKELY ((*(guchar *)p & 0xc0) != 0x80)) /* 10xxxxxx */
+ goto error;
+ }
+ else
+ {
+ if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */
+ {
+ if (G_UNLIKELY (max_len - (p - str) < 3))
+ goto error;
+
+ min = (1 << 11);
+ val = *(guchar *)p & 0x0f;
+ goto TWO_REMAINING;
+ }
+ else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */
+ {
+ if (G_UNLIKELY (max_len - (p - str) < 4))
+ goto error;
+
+ min = (1 << 16);
+ val = *(guchar *)p & 0x07;
+ }
+ else
+ goto error;
+
+ p++;
+ CONTINUATION_CHAR;
+ TWO_REMAINING:
+ p++;
+ CONTINUATION_CHAR;
+ p++;
+ CONTINUATION_CHAR;
+
+ if (G_UNLIKELY (val < min))
+ goto error;
+ if (G_UNLIKELY (!UNICODE_VALID(val)))
+ goto error;
+ }
+
+ continue;
+
+ error:
+ return last;
+ }
+ }
+
+ return p;
+}
+
+/**
+ * g_utf8_validate:
+ * @str: a pointer to character data
+ * @max_len: max bytes to validate, or -1 to go until NUL
+ * @end: return location for end of valid data
+ *
+ * Validates UTF-8 encoded text. @str is the text to validate;
+ * if @str is nul-terminated, then @max_len can be -1, otherwise
+ * @max_len should be the number of bytes to validate.
+ * If @end is non-%NULL, then the end of the valid range
+ * will be stored there (i.e. the start of the first invalid
+ * character if some bytes were invalid, or the end of the text
+ * being validated otherwise).
+ *
+ * Note that g_utf8_validate() returns %FALSE if @max_len is
+ * positive and NUL is met before @max_len bytes have been read.
+ *
+ * Returns %TRUE if all of @str was valid. Many GLib and GTK+
+ * routines <emphasis>require</emphasis> valid UTF-8 as input;
+ * so data read from a file or the network should be checked
+ * with g_utf8_validate() before doing anything else with it.
+ *
+ * Return value: %TRUE if the text was valid UTF-8
+ **/
+gboolean
+g_utf8_validate (const char *str,
+ gssize max_len,
+ const gchar **end)
+
+{
+ const gchar *p;
+
+ if (max_len < 0)
+ p = fast_validate (str);
+ else
+ p = fast_validate_len (str, max_len);
+
+ if (end)
+ *end = p;
+
+ if ((max_len >= 0 && p != str + max_len) ||
+ (max_len < 0 && *p != '\0'))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+/**
+ * g_unichar_validate:
+ * @ch: a Unicode character
+ *
+ * Checks whether @ch is a valid Unicode character. Some possible
+ * integer values of @ch will not be valid. 0 is considered a valid
+ * character, though it's normally a string terminator.
+ *
+ * Return value: %TRUE if @ch is a valid Unicode character
+ **/
+gboolean
+g_unichar_validate (gunichar ch)
+{
+ return UNICODE_VALID (ch);
+}
+
+/**
+ * g_utf8_strreverse:
+ * @str: a UTF-8 encoded string
+ * @len: the maximum length of @str to use, in bytes. If @len < 0,
+ * then the string is nul-terminated.
+ *
+ * Reverses a UTF-8 string. @str must be valid UTF-8 encoded text.
+ * (Use g_utf8_validate() on all text before trying to use UTF-8
+ * utility functions with it.)
+ *
+ * This function is intended for programmatic uses of reversed strings.
+ * It pays no attention to decomposed characters, combining marks, byte
+ * order marks, directional indicators (LRM, LRO, etc) and similar
+ * characters which might need special handling when reversing a string
+ * for display purposes.
+ *
+ * Note that unlike g_strreverse(), this function returns
+ * newly-allocated memory, which should be freed with g_free() when
+ * no longer needed.
+ *
+ * Returns: a newly-allocated string which is the reverse of @str.
+ *
+ * Since: 2.2
+ */
+gchar *
+g_utf8_strreverse (const gchar *str,
+ gssize len)
+{
+ gchar *r, *result;
+ const gchar *p;
+
+ if (len < 0)
+ len = strlen (str);
+
+ result = g_new (gchar, len + 1);
+ r = result + len;
+ p = str;
+ while (r > result)
+ {
+ gchar *m, skip = g_utf8_skip[*(guchar*) p];
+ r -= skip;
+ for (m = r; skip; skip--)
+ *m++ = *p++;
+ }
+ result[len] = 0;
+
+ return result;
+}
+
+
+gchar *
+_g_utf8_make_valid (const gchar *name)
+{
+ GString *string;
+ const gchar *remainder, *invalid;
+ gint remaining_bytes, valid_bytes;
+
+ string = NULL;
+ remainder = name;
+ remaining_bytes = strlen (name);
+
+ while (remaining_bytes != 0)
+ {
+ if (g_utf8_validate (remainder, remaining_bytes, &invalid))
+ break;
+ valid_bytes = invalid - remainder;
+
+ if (string == NULL)
+ string = g_string_sized_new (remaining_bytes);
+
+ g_string_append_len (string, remainder, valid_bytes);
+ /* append U+FFFD REPLACEMENT CHARACTER */
+ g_string_append (string, "\357\277\275");
+
+ remaining_bytes -= valid_bytes + 1;
+ remainder = invalid + 1;
+ }
+
+ if (string == NULL)
+ return g_strdup (name);
+
+ g_string_append (string, remainder);
+
+ g_assert (g_utf8_validate (string->str, -1, NULL));
+
+ return g_string_free (string, FALSE);
+}
+
+#endif
+
+#define __G_UTF8_C__
+#include "galiasdef.c"
diff --git a/support/glib/gutils.c b/support/glib/gutils.c
new file mode 100644
index 00000000..f88890cd
--- /dev/null
+++ b/support/glib/gutils.c
@@ -0,0 +1,3416 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library 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 library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe for the unix part, FIXME: make the win32 part MT safe as well.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <locale.h>
+#include <string.h>
+#include <ctype.h> /* For tolower() */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_CRT_EXTERNS_H
+#include <crt_externs.h> /* for _NSGetEnviron */
+#endif
+
+/* implement gutils's inline functions
+ */
+#define G_IMPLEMENT_INLINES 1
+#define __G_UTILS_C__
+#include "glib.h"
+#include "gprintfint.h"
+#include "gthreadprivate.h"
+#include "glibintl.h"
+#include "galias.h"
+
+#ifdef MAXPATHLEN
+#define G_PATH_LENGTH MAXPATHLEN
+#elif defined (PATH_MAX)
+#define G_PATH_LENGTH PATH_MAX
+#elif defined (_PC_PATH_MAX)
+#define G_PATH_LENGTH sysconf(_PC_PATH_MAX)
+#else
+#define G_PATH_LENGTH 2048
+#endif
+
+#ifdef G_PLATFORM_WIN32
+# define STRICT /* Strict typing, please */
+# include <windows.h>
+# undef STRICT
+# ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
+# define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
+# define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
+# endif
+# include <lmcons.h> /* For UNLEN */
+#endif /* G_PLATFORM_WIN32 */
+
+#ifdef G_OS_WIN32
+#if NOT_NEEDED_FOR_NAVIT
+# include <direct.h>
+#endif /* NOT_NEEDED_FOR_NAVIT */
+# include <shlobj.h>
+ /* older SDK (e.g. msvc 5.0) does not have these*/
+# ifndef CSIDL_MYMUSIC
+# define CSIDL_MYMUSIC 13
+# endif
+# ifndef CSIDL_MYVIDEO
+# define CSIDL_MYVIDEO 14
+# endif
+# ifndef CSIDL_INTERNET_CACHE
+# define CSIDL_INTERNET_CACHE 32
+# endif
+# ifndef CSIDL_COMMON_APPDATA
+# define CSIDL_COMMON_APPDATA 35
+# endif
+# ifndef CSIDL_MYPICTURES
+# define CSIDL_MYPICTURES 0x27
+# endif
+# ifndef CSIDL_COMMON_DOCUMENTS
+# define CSIDL_COMMON_DOCUMENTS 46
+# endif
+# ifndef CSIDL_PROFILE
+# define CSIDL_PROFILE 40
+# endif
+# include <process.h>
+#endif
+
+#ifdef HAVE_CARBON
+#include <CoreServices/CoreServices.h>
+#endif
+
+#ifdef HAVE_CODESET
+#include <langinfo.h>
+#endif
+
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+#include <libintl.h>
+#endif
+
+#if NOT_NEEDED_FOR_NAVIT
+const guint glib_major_version = GLIB_MAJOR_VERSION;
+const guint glib_minor_version = GLIB_MINOR_VERSION;
+const guint glib_micro_version = GLIB_MICRO_VERSION;
+const guint glib_interface_age = GLIB_INTERFACE_AGE;
+const guint glib_binary_age = GLIB_BINARY_AGE;
+
+#ifdef G_PLATFORM_WIN32
+
+static HMODULE glib_dll = NULL;
+
+#ifdef DLL_EXPORT
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved)
+{
+ if (fdwReason == DLL_PROCESS_ATTACH)
+ glib_dll = hinstDLL;
+
+ return TRUE;
+}
+
+#endif
+
+gchar *
+_glib_get_installation_directory (void)
+{
+#ifdef DLL_EXPORT
+ if (glib_dll == NULL)
+ return NULL;
+#endif
+ /* In a static build of GLib just use the application's .exe file's
+ * installation directory...
+ */
+ return g_win32_get_package_installation_directory_of_module (glib_dll);
+}
+
+#endif
+
+/**
+ * glib_check_version:
+ * @required_major: the required major version.
+ * @required_minor: the required minor version.
+ * @required_micro: the required micro version.
+ *
+ * Checks that the GLib library in use is compatible with the
+ * given version. Generally you would pass in the constants
+ * #GLIB_MAJOR_VERSION, #GLIB_MINOR_VERSION, #GLIB_MICRO_VERSION
+ * as the three arguments to this function; that produces
+ * a check that the library in use is compatible with
+ * the version of GLib the application or module was compiled
+ * against.
+ *
+ * Compatibility is defined by two things: first the version
+ * of the running library is newer than the version
+ * @required_major.required_minor.@required_micro. Second
+ * the running library must be binary compatible with the
+ * version @required_major.required_minor.@required_micro
+ * (same major version.)
+ *
+ * Return value: %NULL if the GLib library is compatible with the
+ * given version, or a string describing the version mismatch.
+ * The returned string is owned by GLib and must not be modified
+ * or freed.
+ *
+ * Since: 2.6
+ **/
+const gchar *
+glib_check_version (guint required_major,
+ guint required_minor,
+ guint required_micro)
+{
+ gint glib_effective_micro = 100 * GLIB_MINOR_VERSION + GLIB_MICRO_VERSION;
+ gint required_effective_micro = 100 * required_minor + required_micro;
+
+ if (required_major > GLIB_MAJOR_VERSION)
+ return "GLib version too old (major mismatch)";
+ if (required_major < GLIB_MAJOR_VERSION)
+ return "GLib version too new (major mismatch)";
+ if (required_effective_micro < glib_effective_micro - GLIB_BINARY_AGE)
+ return "GLib version too new (micro mismatch)";
+ if (required_effective_micro > glib_effective_micro)
+ return "GLib version too old (micro mismatch)";
+ return NULL;
+}
+
+#if !defined (HAVE_MEMMOVE) && !defined (HAVE_WORKING_BCOPY)
+/**
+ * g_memmove:
+ * @dest: the destination address to copy the bytes to.
+ * @src: the source address to copy the bytes from.
+ * @len: the number of bytes to copy.
+ *
+ * Copies a block of memory @len bytes long, from @src to @dest.
+ * The source and destination areas may overlap.
+ *
+ * In order to use this function, you must include
+ * <filename>string.h</filename> yourself, because this macro will
+ * typically simply resolve to memmove() and GLib does not include
+ * <filename>string.h</filename> for you.
+ */
+void
+g_memmove (gpointer dest,
+ gconstpointer src,
+ gulong len)
+{
+ gchar* destptr = dest;
+ const gchar* srcptr = src;
+ if (src + len < dest || dest + len < src)
+ {
+ bcopy (src, dest, len);
+ return;
+ }
+ else if (dest <= src)
+ {
+ while (len--)
+ *(destptr++) = *(srcptr++);
+ }
+ else
+ {
+ destptr += len;
+ srcptr += len;
+ while (len--)
+ *(--destptr) = *(--srcptr);
+ }
+}
+#endif /* !HAVE_MEMMOVE && !HAVE_WORKING_BCOPY */
+
+#ifdef G_OS_WIN32
+#undef g_atexit
+#endif
+
+/**
+ * g_atexit:
+ * @func: the function to call on normal program termination.
+ *
+ * Specifies a function to be called at normal program termination.
+ *
+ * Since GLib 2.8.2, on Windows g_atexit() actually is a preprocessor
+ * macro that maps to a call to the atexit() function in the C
+ * library. This means that in case the code that calls g_atexit(),
+ * i.e. atexit(), is in a DLL, the function will be called when the
+ * DLL is detached from the program. This typically makes more sense
+ * than that the function is called when the GLib DLL is detached,
+ * which happened earlier when g_atexit() was a function in the GLib
+ * DLL.
+ *
+ * The behaviour of atexit() in the context of dynamically loaded
+ * modules is not formally specified and varies wildly.
+ *
+ * On POSIX systems, calling g_atexit() (or atexit()) in a dynamically
+ * loaded module which is unloaded before the program terminates might
+ * well cause a crash at program exit.
+ *
+ * Some POSIX systems implement atexit() like Windows, and have each
+ * dynamically loaded module maintain an own atexit chain that is
+ * called when the module is unloaded.
+ *
+ * On other POSIX systems, before a dynamically loaded module is
+ * unloaded, the registered atexit functions (if any) residing in that
+ * module are called, regardless where the code that registered them
+ * resided. This is presumably the most robust approach.
+ *
+ * As can be seen from the above, for portability it's best to avoid
+ * calling g_atexit() (or atexit()) except in the main executable of a
+ * program.
+ */
+void
+g_atexit (GVoidFunc func)
+{
+ gint result;
+ const gchar *error = NULL;
+
+ /* keep this in sync with glib.h */
+
+#ifdef G_NATIVE_ATEXIT
+ result = ATEXIT (func);
+ if (result)
+ error = g_strerror (errno);
+#elif defined (HAVE_ATEXIT)
+# ifdef NeXT /* @#%@! NeXTStep */
+ result = !atexit ((void (*)(void)) func);
+ if (result)
+ error = g_strerror (errno);
+# else
+ result = atexit ((void (*)(void)) func);
+ if (result)
+ error = g_strerror (errno);
+# endif /* NeXT */
+#elif defined (HAVE_ON_EXIT)
+ result = on_exit ((void (*)(int, void *)) func, NULL);
+ if (result)
+ error = g_strerror (errno);
+#else
+ result = 0;
+ error = "no implementation";
+#endif /* G_NATIVE_ATEXIT */
+
+ if (error)
+ g_error ("Could not register atexit() function: %s", error);
+}
+
+/* Based on execvp() from GNU Libc.
+ * Some of this code is cut-and-pasted into gspawn.c
+ */
+
+static gchar*
+my_strchrnul (const gchar *str,
+ gchar c)
+{
+ gchar *p = (gchar*)str;
+ while (*p && (*p != c))
+ ++p;
+
+ return p;
+}
+
+#ifdef G_OS_WIN32
+
+static gchar *inner_find_program_in_path (const gchar *program);
+
+gchar*
+g_find_program_in_path (const gchar *program)
+{
+ const gchar *last_dot = strrchr (program, '.');
+
+ if (last_dot == NULL ||
+ strchr (last_dot, '\\') != NULL ||
+ strchr (last_dot, '/') != NULL)
+ {
+ const gint program_length = strlen (program);
+ gchar *pathext = g_build_path (";",
+ ".exe;.cmd;.bat;.com",
+ g_getenv ("PATHEXT"),
+ NULL);
+ gchar *p;
+ gchar *decorated_program;
+ gchar *retval;
+
+ p = pathext;
+ do
+ {
+ gchar *q = my_strchrnul (p, ';');
+
+ decorated_program = g_malloc (program_length + (q-p) + 1);
+ memcpy (decorated_program, program, program_length);
+ memcpy (decorated_program+program_length, p, q-p);
+ decorated_program [program_length + (q-p)] = '\0';
+
+ retval = inner_find_program_in_path (decorated_program);
+ g_free (decorated_program);
+
+ if (retval != NULL)
+ {
+ g_free (pathext);
+ return retval;
+ }
+ p = q;
+ } while (*p++ != '\0');
+ g_free (pathext);
+ return NULL;
+ }
+ else
+ return inner_find_program_in_path (program);
+}
+
+#endif
+
+/**
+ * g_find_program_in_path:
+ * @program: a program name in the GLib file name encoding
+ *
+ * Locates the first executable named @program in the user's path, in the
+ * same way that execvp() would locate it. Returns an allocated string
+ * with the absolute path name, or %NULL if the program is not found in
+ * the path. If @program is already an absolute path, returns a copy of
+ * @program if @program exists and is executable, and %NULL otherwise.
+ *
+ * On Windows, if @program does not have a file type suffix, tries
+ * with the suffixes .exe, .cmd, .bat and .com, and the suffixes in
+ * the <envar>PATHEXT</envar> environment variable.
+ *
+ * On Windows, it looks for the file in the same way as CreateProcess()
+ * would. This means first in the directory where the executing
+ * program was loaded from, then in the current directory, then in the
+ * Windows 32-bit system directory, then in the Windows directory, and
+ * finally in the directories in the <envar>PATH</envar> environment
+ * variable. If the program is found, the return value contains the
+ * full name including the type suffix.
+ *
+ * Return value: absolute path, or %NULL
+ **/
+#ifdef G_OS_WIN32
+static gchar *
+inner_find_program_in_path (const gchar *program)
+#else
+gchar*
+g_find_program_in_path (const gchar *program)
+#endif
+{
+ const gchar *path, *p;
+ gchar *name, *freeme;
+#ifdef G_OS_WIN32
+ const gchar *path_copy;
+ gchar *filename = NULL, *appdir = NULL;
+ gchar *sysdir = NULL, *windir = NULL;
+ int n;
+ wchar_t wfilename[MAXPATHLEN], wsysdir[MAXPATHLEN],
+ wwindir[MAXPATHLEN];
+#endif
+ gsize len;
+ gsize pathlen;
+
+ g_return_val_if_fail (program != NULL, NULL);
+
+ /* If it is an absolute path, or a relative path including subdirectories,
+ * don't look in PATH.
+ */
+ if (g_path_is_absolute (program)
+ || strchr (program, G_DIR_SEPARATOR) != NULL
+#ifdef G_OS_WIN32
+ || strchr (program, '/') != NULL
+#endif
+ )
+ {
+ if (g_file_test (program, G_FILE_TEST_IS_EXECUTABLE) &&
+ !g_file_test (program, G_FILE_TEST_IS_DIR))
+ return g_strdup (program);
+ else
+ return NULL;
+ }
+
+ path = g_getenv ("PATH");
+#if defined(G_OS_UNIX) || defined(G_OS_BEOS)
+ if (path == NULL)
+ {
+ /* There is no `PATH' in the environment. The default
+ * search path in GNU libc is the current directory followed by
+ * the path `confstr' returns for `_CS_PATH'.
+ */
+
+ /* In GLib we put . last, for security, and don't use the
+ * unportable confstr(); UNIX98 does not actually specify
+ * what to search if PATH is unset. POSIX may, dunno.
+ */
+
+ path = "/bin:/usr/bin:.";
+ }
+#else
+ n = GetModuleFileNameW (NULL, wfilename, MAXPATHLEN);
+ if (n > 0 && n < MAXPATHLEN)
+ filename = g_utf16_to_utf8 (wfilename, -1, NULL, NULL, NULL);
+
+ n = GetSystemDirectoryW (wsysdir, MAXPATHLEN);
+ if (n > 0 && n < MAXPATHLEN)
+ sysdir = g_utf16_to_utf8 (wsysdir, -1, NULL, NULL, NULL);
+
+ n = GetWindowsDirectoryW (wwindir, MAXPATHLEN);
+ if (n > 0 && n < MAXPATHLEN)
+ windir = g_utf16_to_utf8 (wwindir, -1, NULL, NULL, NULL);
+
+ if (filename)
+ {
+ appdir = g_path_get_dirname (filename);
+ g_free (filename);
+ }
+
+ path = g_strdup (path);
+
+ if (windir)
+ {
+ const gchar *tem = path;
+ path = g_strconcat (windir, ";", path, NULL);
+ g_free ((gchar *) tem);
+ g_free (windir);
+ }
+
+ if (sysdir)
+ {
+ const gchar *tem = path;
+ path = g_strconcat (sysdir, ";", path, NULL);
+ g_free ((gchar *) tem);
+ g_free (sysdir);
+ }
+
+ {
+ const gchar *tem = path;
+ path = g_strconcat (".;", path, NULL);
+ g_free ((gchar *) tem);
+ }
+
+ if (appdir)
+ {
+ const gchar *tem = path;
+ path = g_strconcat (appdir, ";", path, NULL);
+ g_free ((gchar *) tem);
+ g_free (appdir);
+ }
+
+ path_copy = path;
+#endif
+
+ len = strlen (program) + 1;
+ pathlen = strlen (path);
+ freeme = name = g_malloc (pathlen + len + 1);
+
+ /* Copy the file name at the top, including '\0' */
+ memcpy (name + pathlen + 1, program, len);
+ name = name + pathlen;
+ /* And add the slash before the filename */
+ *name = G_DIR_SEPARATOR;
+
+ p = path;
+ do
+ {
+ char *startp;
+
+ path = p;
+ p = my_strchrnul (path, G_SEARCHPATH_SEPARATOR);
+
+ if (p == path)
+ /* Two adjacent colons, or a colon at the beginning or the end
+ * of `PATH' means to search the current directory.
+ */
+ startp = name + 1;
+ else
+ startp = memcpy (name - (p - path), path, p - path);
+
+ if (g_file_test (startp, G_FILE_TEST_IS_EXECUTABLE) &&
+ !g_file_test (startp, G_FILE_TEST_IS_DIR))
+ {
+ gchar *ret;
+ ret = g_strdup (startp);
+ g_free (freeme);
+#ifdef G_OS_WIN32
+ g_free ((gchar *) path_copy);
+#endif
+ return ret;
+ }
+ }
+ while (*p++ != '\0');
+
+ g_free (freeme);
+#ifdef G_OS_WIN32
+ g_free ((gchar *) path_copy);
+#endif
+
+ return NULL;
+}
+
+static gboolean
+debug_key_matches (const gchar *key,
+ const gchar *token,
+ guint length)
+{
+ for (; length; length--, key++, token++)
+ {
+ char k = (*key == '_') ? '-' : tolower (*key );
+ char t = (*token == '_') ? '-' : tolower (*token);
+
+ if (k != t)
+ return FALSE;
+ }
+
+ return *key == '\0';
+}
+
+/**
+ * g_parse_debug_string:
+ * @string: a list of debug options separated by colons, spaces, or
+ * commas; or the string "all" to set all flags, or %NULL.
+ * @keys: pointer to an array of #GDebugKey which associate
+ * strings with bit flags.
+ * @nkeys: the number of #GDebugKey<!-- -->s in the array.
+ *
+ * Parses a string containing debugging options
+ * into a %guint containing bit flags. This is used
+ * within GDK and GTK+ to parse the debug options passed on the
+ * command line or through environment variables.
+ *
+ * Returns: the combined set of bit flags.
+ */
+guint
+g_parse_debug_string (const gchar *string,
+ const GDebugKey *keys,
+ guint nkeys)
+{
+ guint i;
+ guint result = 0;
+
+ if (string == NULL)
+ return 0;
+
+ /* this function is used by gmem.c/gslice.c initialization code,
+ * so introducing malloc dependencies here would require adaptions
+ * of those code portions.
+ */
+
+ if (!g_ascii_strcasecmp (string, "all"))
+ {
+ for (i=0; i<nkeys; i++)
+ result |= keys[i].value;
+ }
+ else
+ {
+ const gchar *p = string;
+ const gchar *q;
+
+ while (*p)
+ {
+ q = strpbrk (p, ":;, \t");
+ if (!q)
+ q = p + strlen(p);
+
+ for (i = 0; i < nkeys; i++)
+ if (debug_key_matches (keys[i].key, p, q - p))
+ result |= keys[i].value;
+
+ p = q;
+ if (*p)
+ p++;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * g_basename:
+ * @file_name: the name of the file.
+ *
+ * Gets the name of the file without any leading directory components.
+ * It returns a pointer into the given file name string.
+ *
+ * Return value: the name of the file without any leading directory components.
+ *
+ * Deprecated:2.2: Use g_path_get_basename() instead, but notice that
+ * g_path_get_basename() allocates new memory for the returned string, unlike
+ * this function which returns a pointer into the argument.
+ **/
+G_CONST_RETURN gchar*
+g_basename (const gchar *file_name)
+{
+ register gchar *base;
+
+ g_return_val_if_fail (file_name != NULL, NULL);
+
+ base = strrchr (file_name, G_DIR_SEPARATOR);
+
+#ifdef G_OS_WIN32
+ {
+ gchar *q = strrchr (file_name, '/');
+ if (base == NULL || (q != NULL && q > base))
+ base = q;
+ }
+#endif
+
+ if (base)
+ return base + 1;
+
+#ifdef G_OS_WIN32
+ if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
+ return (gchar*) file_name + 2;
+#endif /* G_OS_WIN32 */
+
+ return (gchar*) file_name;
+}
+
+/**
+ * g_path_get_basename:
+ * @file_name: the name of the file.
+ *
+ * Gets the last component of the filename. If @file_name ends with a
+ * directory separator it gets the component before the last slash. If
+ * @file_name consists only of directory separators (and on Windows,
+ * possibly a drive letter), a single separator is returned. If
+ * @file_name is empty, it gets ".".
+ *
+ * Return value: a newly allocated string containing the last component of
+ * the filename.
+ */
+gchar*
+g_path_get_basename (const gchar *file_name)
+{
+ register gssize base;
+ register gssize last_nonslash;
+ gsize len;
+ gchar *retval;
+
+ g_return_val_if_fail (file_name != NULL, NULL);
+
+ if (file_name[0] == '\0')
+ /* empty string */
+ return g_strdup (".");
+
+ last_nonslash = strlen (file_name) - 1;
+
+ while (last_nonslash >= 0 && G_IS_DIR_SEPARATOR (file_name [last_nonslash]))
+ last_nonslash--;
+
+ if (last_nonslash == -1)
+ /* string only containing slashes */
+ return g_strdup (G_DIR_SEPARATOR_S);
+
+#ifdef G_OS_WIN32
+ if (last_nonslash == 1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
+ /* string only containing slashes and a drive */
+ return g_strdup (G_DIR_SEPARATOR_S);
+#endif /* G_OS_WIN32 */
+
+ base = last_nonslash;
+
+ while (base >=0 && !G_IS_DIR_SEPARATOR (file_name [base]))
+ base--;
+
+#ifdef G_OS_WIN32
+ if (base == -1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
+ base = 1;
+#endif /* G_OS_WIN32 */
+
+ len = last_nonslash - base;
+ retval = g_malloc (len + 1);
+ memcpy (retval, file_name + base + 1, len);
+ retval [len] = '\0';
+ return retval;
+}
+
+/**
+ * g_path_is_absolute:
+ * @file_name: a file name.
+ *
+ * Returns %TRUE if the given @file_name is an absolute file name,
+ * i.e. it contains a full path from the root directory such as "/usr/local"
+ * on UNIX or "C:\windows" on Windows systems.
+ *
+ * Returns: %TRUE if @file_name is an absolute path.
+ */
+gboolean
+g_path_is_absolute (const gchar *file_name)
+{
+ g_return_val_if_fail (file_name != NULL, FALSE);
+
+ if (G_IS_DIR_SEPARATOR (file_name[0]))
+ return TRUE;
+
+#ifdef G_OS_WIN32
+ /* Recognize drive letter on native Windows */
+ if (g_ascii_isalpha (file_name[0]) &&
+ file_name[1] == ':' && G_IS_DIR_SEPARATOR (file_name[2]))
+ return TRUE;
+#endif /* G_OS_WIN32 */
+
+ return FALSE;
+}
+
+/**
+ * g_path_skip_root:
+ * @file_name: a file name.
+ *
+ * Returns a pointer into @file_name after the root component, i.e. after
+ * the "/" in UNIX or "C:\" under Windows. If @file_name is not an absolute
+ * path it returns %NULL.
+ *
+ * Returns: a pointer into @file_name after the root component.
+ */
+G_CONST_RETURN gchar*
+g_path_skip_root (const gchar *file_name)
+{
+ g_return_val_if_fail (file_name != NULL, NULL);
+
+#ifdef G_PLATFORM_WIN32
+ /* Skip \\server\share or //server/share */
+ if (G_IS_DIR_SEPARATOR (file_name[0]) &&
+ G_IS_DIR_SEPARATOR (file_name[1]) &&
+ file_name[2] &&
+ !G_IS_DIR_SEPARATOR (file_name[2]))
+ {
+ gchar *p;
+
+ p = strchr (file_name + 2, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+ {
+ gchar *q = strchr (file_name + 2, '/');
+ if (p == NULL || (q != NULL && q < p))
+ p = q;
+ }
+#endif
+ if (p &&
+ p > file_name + 2 &&
+ p[1])
+ {
+ file_name = p + 1;
+
+ while (file_name[0] && !G_IS_DIR_SEPARATOR (file_name[0]))
+ file_name++;
+
+ /* Possibly skip a backslash after the share name */
+ if (G_IS_DIR_SEPARATOR (file_name[0]))
+ file_name++;
+
+ return (gchar *)file_name;
+ }
+ }
+#endif
+
+ /* Skip initial slashes */
+ if (G_IS_DIR_SEPARATOR (file_name[0]))
+ {
+ while (G_IS_DIR_SEPARATOR (file_name[0]))
+ file_name++;
+ return (gchar *)file_name;
+ }
+
+#ifdef G_OS_WIN32
+ /* Skip X:\ */
+ if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':' && G_IS_DIR_SEPARATOR (file_name[2]))
+ return (gchar *)file_name + 3;
+#endif
+
+ return NULL;
+}
+
+/**
+ * g_path_get_dirname:
+ * @file_name: the name of the file.
+ *
+ * Gets the directory components of a file name. If the file name has no
+ * directory components "." is returned. The returned string should be
+ * freed when no longer needed.
+ *
+ * Returns: the directory components of the file.
+ */
+gchar*
+g_path_get_dirname (const gchar *file_name)
+{
+ register gchar *base;
+ register gsize len;
+
+ g_return_val_if_fail (file_name != NULL, NULL);
+
+ base = strrchr (file_name, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+ {
+ gchar *q = strrchr (file_name, '/');
+ if (base == NULL || (q != NULL && q > base))
+ base = q;
+ }
+#endif
+ if (!base)
+ {
+#ifdef G_OS_WIN32
+ if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
+ {
+ gchar drive_colon_dot[4];
+
+ drive_colon_dot[0] = file_name[0];
+ drive_colon_dot[1] = ':';
+ drive_colon_dot[2] = '.';
+ drive_colon_dot[3] = '\0';
+
+ return g_strdup (drive_colon_dot);
+ }
+#endif
+ return g_strdup (".");
+ }
+
+ while (base > file_name && G_IS_DIR_SEPARATOR (*base))
+ base--;
+
+#ifdef G_OS_WIN32
+ /* base points to the char before the last slash.
+ *
+ * In case file_name is the root of a drive (X:\) or a child of the
+ * root of a drive (X:\foo), include the slash.
+ *
+ * In case file_name is the root share of an UNC path
+ * (\\server\share), add a slash, returning \\server\share\ .
+ *
+ * In case file_name is a direct child of a share in an UNC path
+ * (\\server\share\foo), include the slash after the share name,
+ * returning \\server\share\ .
+ */
+ if (base == file_name + 1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
+ base++;
+ else if (G_IS_DIR_SEPARATOR (file_name[0]) &&
+ G_IS_DIR_SEPARATOR (file_name[1]) &&
+ file_name[2] &&
+ !G_IS_DIR_SEPARATOR (file_name[2]) &&
+ base >= file_name + 2)
+ {
+ const gchar *p = file_name + 2;
+ while (*p && !G_IS_DIR_SEPARATOR (*p))
+ p++;
+ if (p == base + 1)
+ {
+ len = (guint) strlen (file_name) + 1;
+ base = g_new (gchar, len + 1);
+ strcpy (base, file_name);
+ base[len-1] = G_DIR_SEPARATOR;
+ base[len] = 0;
+ return base;
+ }
+ if (G_IS_DIR_SEPARATOR (*p))
+ {
+ p++;
+ while (*p && !G_IS_DIR_SEPARATOR (*p))
+ p++;
+ if (p == base + 1)
+ base++;
+ }
+ }
+#endif
+
+ len = (guint) 1 + base - file_name;
+
+ base = g_new (gchar, len + 1);
+ g_memmove (base, file_name, len);
+ base[len] = 0;
+
+ return base;
+}
+
+/**
+ * g_get_current_dir:
+ *
+ * Gets the current directory.
+ * The returned string should be freed when no longer needed. The encoding
+ * of the returned string is system defined. On Windows, it is always UTF-8.
+ *
+ * Returns: the current directory.
+ */
+gchar*
+g_get_current_dir (void)
+{
+#ifdef G_OS_WIN32
+
+ gchar *dir = NULL;
+ wchar_t dummy[2], *wdir;
+ int len;
+
+ len = GetCurrentDirectoryW (2, dummy);
+ wdir = g_new (wchar_t, len);
+
+ if (GetCurrentDirectoryW (len, wdir) == len - 1)
+ dir = g_utf16_to_utf8 (wdir, -1, NULL, NULL, NULL);
+
+ g_free (wdir);
+
+ if (dir == NULL)
+ dir = g_strdup ("\\");
+
+ return dir;
+
+#else
+
+ gchar *buffer = NULL;
+ gchar *dir = NULL;
+ static gulong max_len = 0;
+
+ if (max_len == 0)
+ max_len = (G_PATH_LENGTH == -1) ? 2048 : G_PATH_LENGTH;
+
+ /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
+ * and, if that wasn't bad enough, hangs in doing so.
+ */
+#if (defined (sun) && !defined (__SVR4)) || !defined(HAVE_GETCWD)
+ buffer = g_new (gchar, max_len + 1);
+ *buffer = 0;
+ dir = getwd (buffer);
+#else /* !sun || !HAVE_GETCWD */
+ while (max_len < G_MAXULONG / 2)
+ {
+ g_free (buffer);
+ buffer = g_new (gchar, max_len + 1);
+ *buffer = 0;
+ dir = getcwd (buffer, max_len);
+
+ if (dir || errno != ERANGE)
+ break;
+
+ max_len *= 2;
+ }
+#endif /* !sun || !HAVE_GETCWD */
+
+ if (!dir || !*buffer)
+ {
+ /* hm, should we g_error() out here?
+ * this can happen if e.g. "./" has mode \0000
+ */
+ buffer[0] = G_DIR_SEPARATOR;
+ buffer[1] = 0;
+ }
+
+ dir = g_strdup (buffer);
+ g_free (buffer);
+
+ return dir;
+#endif /* !Win32 */
+}
+
+/**
+ * g_getenv:
+ * @variable: the environment variable to get, in the GLib file name encoding.
+ *
+ * Returns the value of an environment variable. The name and value
+ * are in the GLib file name encoding. On UNIX, this means the actual
+ * bytes which might or might not be in some consistent character set
+ * and encoding. On Windows, it is in UTF-8. On Windows, in case the
+ * environment variable's value contains references to other
+ * environment variables, they are expanded.
+ *
+ * Return value: the value of the environment variable, or %NULL if
+ * the environment variable is not found. The returned string may be
+ * overwritten by the next call to g_getenv(), g_setenv() or
+ * g_unsetenv().
+ **/
+G_CONST_RETURN gchar*
+g_getenv (const gchar *variable)
+{
+#ifndef G_OS_WIN32
+
+ g_return_val_if_fail (variable != NULL, NULL);
+
+ return getenv (variable);
+
+#else /* G_OS_WIN32 */
+
+ GQuark quark;
+ gchar *value;
+ wchar_t dummy[2], *wname, *wvalue;
+ int len;
+
+ g_return_val_if_fail (variable != NULL, NULL);
+ g_return_val_if_fail (g_utf8_validate (variable, -1, NULL), NULL);
+
+ /* On Windows NT, it is relatively typical that environment
+ * variables contain references to other environment variables. If
+ * so, use ExpandEnvironmentStrings(). (In an ideal world, such
+ * environment variables would be stored in the Registry as
+ * REG_EXPAND_SZ type values, and would then get automatically
+ * expanded before a program sees them. But there is broken software
+ * that stores environment variables as REG_SZ values even if they
+ * contain references to other environment variables.)
+ */
+
+ wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
+
+ len = GetEnvironmentVariableW (wname, dummy, 2);
+
+ if (len == 0)
+ {
+ g_free (wname);
+ return NULL;
+ }
+ else if (len == 1)
+ len = 2;
+
+ wvalue = g_new (wchar_t, len);
+
+ if (GetEnvironmentVariableW (wname, wvalue, len) != len - 1)
+ {
+ g_free (wname);
+ g_free (wvalue);
+ return NULL;
+ }
+
+ if (wcschr (wvalue, L'%') != NULL)
+ {
+ wchar_t *tem = wvalue;
+
+ len = ExpandEnvironmentStringsW (wvalue, dummy, 2);
+
+ if (len > 0)
+ {
+ wvalue = g_new (wchar_t, len);
+
+ if (ExpandEnvironmentStringsW (tem, wvalue, len) != len)
+ {
+ g_free (wvalue);
+ wvalue = tem;
+ }
+ else
+ g_free (tem);
+ }
+ }
+
+ value = g_utf16_to_utf8 (wvalue, -1, NULL, NULL, NULL);
+
+ g_free (wname);
+ g_free (wvalue);
+
+ quark = g_quark_from_string (value);
+ g_free (value);
+
+ return g_quark_to_string (quark);
+
+#endif /* G_OS_WIN32 */
+}
+
+/* _g_getenv_nomalloc
+ * this function does a getenv() without doing any kind of allocation
+ * through glib. it's suitable for chars <= 127 only (both, for the
+ * variable name and the contents) and for contents < 1024 chars in
+ * length. also, it aliases "" to a NULL return value.
+ **/
+const gchar*
+_g_getenv_nomalloc (const gchar *variable,
+ gchar buffer[1024])
+{
+ const gchar *retval = getenv (variable);
+ if (retval && retval[0])
+ {
+ gint l = strlen (retval);
+ if (l < 1024)
+ {
+ strncpy (buffer, retval, l);
+ buffer[l] = 0;
+ return buffer;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * g_setenv:
+ * @variable: the environment variable to set, must not contain '='.
+ * @value: the value for to set the variable to.
+ * @overwrite: whether to change the variable if it already exists.
+ *
+ * Sets an environment variable. Both the variable's name and value
+ * should be in the GLib file name encoding. On UNIX, this means that
+ * they can be any sequence of bytes. On Windows, they should be in
+ * UTF-8.
+ *
+ * Note that on some systems, when variables are overwritten, the memory
+ * used for the previous variables and its value isn't reclaimed.
+ *
+ * Returns: %FALSE if the environment variable couldn't be set.
+ *
+ * Since: 2.4
+ */
+gboolean
+g_setenv (const gchar *variable,
+ const gchar *value,
+ gboolean overwrite)
+{
+#ifndef G_OS_WIN32
+
+ gint result;
+#ifndef HAVE_SETENV
+ gchar *string;
+#endif
+
+ g_return_val_if_fail (variable != NULL, FALSE);
+ g_return_val_if_fail (strchr (variable, '=') == NULL, FALSE);
+
+#ifdef HAVE_SETENV
+ result = setenv (variable, value, overwrite);
+#else
+ if (!overwrite && getenv (variable) != NULL)
+ return TRUE;
+
+ /* This results in a leak when you overwrite existing
+ * settings. It would be fairly easy to fix this by keeping
+ * our own parallel array or hash table.
+ */
+ string = g_strconcat (variable, "=", value, NULL);
+ result = putenv (string);
+#endif
+ return result == 0;
+
+#else /* G_OS_WIN32 */
+
+ gboolean retval;
+ wchar_t *wname, *wvalue, *wassignment;
+ gchar *tem;
+
+ g_return_val_if_fail (variable != NULL, FALSE);
+ g_return_val_if_fail (strchr (variable, '=') == NULL, FALSE);
+ g_return_val_if_fail (g_utf8_validate (variable, -1, NULL), FALSE);
+ g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
+
+ if (!overwrite && g_getenv (variable) != NULL)
+ return TRUE;
+
+ /* We want to (if possible) set both the environment variable copy
+ * kept by the C runtime and the one kept by the system.
+ *
+ * We can't use only the C runtime's putenv or _wputenv() as that
+ * won't work for arbitrary Unicode strings in a "non-Unicode" app
+ * (with main() and not wmain()). In a "main()" app the C runtime
+ * initializes the C runtime's environment table by converting the
+ * real (wide char) environment variables to system codepage, thus
+ * breaking those that aren't representable in the system codepage.
+ *
+ * As the C runtime's putenv() will also set the system copy, we do
+ * the putenv() first, then call SetEnvironmentValueW ourselves.
+ */
+
+ wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
+ wvalue = g_utf8_to_utf16 (value, -1, NULL, NULL, NULL);
+ tem = g_strconcat (variable, "=", value, NULL);
+ wassignment = g_utf8_to_utf16 (tem, -1, NULL, NULL, NULL);
+
+ g_free (tem);
+ _wputenv (wassignment);
+ g_free (wassignment);
+
+ retval = (SetEnvironmentVariableW (wname, wvalue) != 0);
+
+ g_free (wname);
+ g_free (wvalue);
+
+ return retval;
+
+#endif /* G_OS_WIN32 */
+}
+
+#ifdef HAVE__NSGETENVIRON
+#define environ (*_NSGetEnviron())
+#elif !defined(G_OS_WIN32)
+
+/* According to the Single Unix Specification, environ is not in
+ * any system header, although unistd.h often declares it.
+ */
+extern char **environ;
+#endif
+
+/**
+ * g_unsetenv:
+ * @variable: the environment variable to remove, must not contain '='.
+ *
+ * Removes an environment variable from the environment.
+ *
+ * Note that on some systems, when variables are overwritten, the memory
+ * used for the previous variables and its value isn't reclaimed.
+ * Furthermore, this function can't be guaranteed to operate in a
+ * threadsafe way.
+ *
+ * Since: 2.4
+ **/
+void
+g_unsetenv (const gchar *variable)
+{
+#ifndef G_OS_WIN32
+
+#ifdef HAVE_UNSETENV
+ g_return_if_fail (variable != NULL);
+ g_return_if_fail (strchr (variable, '=') == NULL);
+
+ unsetenv (variable);
+#else /* !HAVE_UNSETENV */
+ int len;
+ gchar **e, **f;
+
+ g_return_if_fail (variable != NULL);
+ g_return_if_fail (strchr (variable, '=') == NULL);
+
+ len = strlen (variable);
+
+ /* Mess directly with the environ array.
+ * This seems to be the only portable way to do this.
+ *
+ * Note that we remove *all* environment entries for
+ * the variable name, not just the first.
+ */
+ e = f = environ;
+ while (*e != NULL)
+ {
+ if (strncmp (*e, variable, len) != 0 || (*e)[len] != '=')
+ {
+ *f = *e;
+ f++;
+ }
+ e++;
+ }
+ *f = NULL;
+#endif /* !HAVE_UNSETENV */
+
+#else /* G_OS_WIN32 */
+
+ wchar_t *wname, *wassignment;
+ gchar *tem;
+
+ g_return_if_fail (variable != NULL);
+ g_return_if_fail (strchr (variable, '=') == NULL);
+ g_return_if_fail (g_utf8_validate (variable, -1, NULL));
+
+ wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
+ tem = g_strconcat (variable, "=", NULL);
+ wassignment = g_utf8_to_utf16 (tem, -1, NULL, NULL, NULL);
+
+ g_free (tem);
+ _wputenv (wassignment);
+ g_free (wassignment);
+
+ SetEnvironmentVariableW (wname, NULL);
+
+ g_free (wname);
+
+#endif /* G_OS_WIN32 */
+}
+
+/**
+ * g_listenv:
+ *
+ * Gets the names of all variables set in the environment.
+ *
+ * Returns: a %NULL-terminated list of strings which must be freed
+ * with g_strfreev().
+ *
+ * Programs that want to be portable to Windows should typically use
+ * this function and g_getenv() instead of using the environ array
+ * from the C library directly. On Windows, the strings in the environ
+ * array are in system codepage encoding, while in most of the typical
+ * use cases for environment variables in GLib-using programs you want
+ * the UTF-8 encoding that this function and g_getenv() provide.
+ *
+ * Since: 2.8
+ */
+gchar **
+g_listenv (void)
+{
+#ifndef G_OS_WIN32
+ gchar **result, *eq;
+ gint len, i, j;
+
+ len = g_strv_length (environ);
+ result = g_new0 (gchar *, len + 1);
+
+ j = 0;
+ for (i = 0; i < len; i++)
+ {
+ eq = strchr (environ[i], '=');
+ if (eq)
+ result[j++] = g_strndup (environ[i], eq - environ[i]);
+ }
+
+ result[j] = NULL;
+
+ return result;
+#else
+ gchar **result, *eq;
+ gint len = 0, j;
+ wchar_t *p, *q;
+
+ p = (wchar_t *) GetEnvironmentStringsW ();
+ if (p != NULL)
+ {
+ q = p;
+ while (*q)
+ {
+ q += wcslen (q) + 1;
+ len++;
+ }
+ }
+ result = g_new0 (gchar *, len + 1);
+
+ j = 0;
+ q = p;
+ while (*q)
+ {
+ result[j] = g_utf16_to_utf8 (q, -1, NULL, NULL, NULL);
+ if (result[j] != NULL)
+ {
+ eq = strchr (result[j], '=');
+ if (eq && eq > result[j])
+ {
+ *eq = '\0';
+ j++;
+ }
+ else
+ g_free (result[j]);
+ }
+ q += wcslen (q) + 1;
+ }
+ result[j] = NULL;
+ FreeEnvironmentStringsW (p);
+
+ return result;
+#endif
+}
+
+G_LOCK_DEFINE_STATIC (g_utils_global);
+
+static gchar *g_tmp_dir = NULL;
+static gchar *g_user_name = NULL;
+static gchar *g_real_name = NULL;
+static gchar *g_home_dir = NULL;
+static gchar *g_host_name = NULL;
+
+#ifdef G_OS_WIN32
+/* System codepage versions of the above, kept at file level so that they,
+ * too, are produced only once.
+ */
+static gchar *g_tmp_dir_cp = NULL;
+static gchar *g_user_name_cp = NULL;
+static gchar *g_real_name_cp = NULL;
+static gchar *g_home_dir_cp = NULL;
+#endif
+
+static gchar *g_user_data_dir = NULL;
+static gchar **g_system_data_dirs = NULL;
+static gchar *g_user_cache_dir = NULL;
+static gchar *g_user_config_dir = NULL;
+static gchar **g_system_config_dirs = NULL;
+
+static gchar **g_user_special_dirs = NULL;
+
+/* fifteen minutes of fame for everybody */
+#define G_USER_DIRS_EXPIRE 15 * 60
+
+#ifdef G_OS_WIN32
+
+static gchar *
+get_special_folder (int csidl)
+{
+ wchar_t path[MAX_PATH+1];
+ HRESULT hr;
+ LPITEMIDLIST pidl = NULL;
+ BOOL b;
+ gchar *retval = NULL;
+
+ hr = SHGetSpecialFolderLocation (NULL, csidl, &pidl);
+ if (hr == S_OK)
+ {
+ b = SHGetPathFromIDListW (pidl, path);
+ if (b)
+ retval = g_utf16_to_utf8 (path, -1, NULL, NULL, NULL);
+ CoTaskMemFree (pidl);
+ }
+ return retval;
+}
+
+static char *
+get_windows_directory_root (void)
+{
+ wchar_t wwindowsdir[MAX_PATH];
+
+ if (GetWindowsDirectoryW (wwindowsdir, G_N_ELEMENTS (wwindowsdir)))
+ {
+ /* Usually X:\Windows, but in terminal server environments
+ * might be an UNC path, AFAIK.
+ */
+ char *windowsdir = g_utf16_to_utf8 (wwindowsdir, -1, NULL, NULL, NULL);
+ char *p;
+
+ if (windowsdir == NULL)
+ return g_strdup ("C:\\");
+
+ p = (char *) g_path_skip_root (windowsdir);
+ if (G_IS_DIR_SEPARATOR (p[-1]) && p[-2] != ':')
+ p--;
+ *p = '\0';
+ return windowsdir;
+ }
+ else
+ return g_strdup ("C:\\");
+}
+
+#endif
+
+/* HOLDS: g_utils_global_lock */
+static void
+g_get_any_init_do (void)
+{
+ gchar hostname[100];
+
+ g_tmp_dir = g_strdup (g_getenv ("TMPDIR"));
+ if (!g_tmp_dir)
+ g_tmp_dir = g_strdup (g_getenv ("TMP"));
+ if (!g_tmp_dir)
+ g_tmp_dir = g_strdup (g_getenv ("TEMP"));
+
+#ifdef G_OS_WIN32
+ if (!g_tmp_dir)
+ g_tmp_dir = get_windows_directory_root ();
+#else
+#ifdef P_tmpdir
+ if (!g_tmp_dir)
+ {
+ gsize k;
+ g_tmp_dir = g_strdup (P_tmpdir);
+ k = strlen (g_tmp_dir);
+ if (k > 1 && G_IS_DIR_SEPARATOR (g_tmp_dir[k - 1]))
+ g_tmp_dir[k - 1] = '\0';
+ }
+#endif
+
+ if (!g_tmp_dir)
+ {
+ g_tmp_dir = g_strdup ("/tmp");
+ }
+#endif /* !G_OS_WIN32 */
+
+#ifdef G_OS_WIN32
+ /* We check $HOME first for Win32, though it is a last resort for Unix
+ * where we prefer the results of getpwuid().
+ */
+ g_home_dir = g_strdup (g_getenv ("HOME"));
+
+ /* Only believe HOME if it is an absolute path and exists */
+ if (g_home_dir)
+ {
+ if (!(g_path_is_absolute (g_home_dir) &&
+ g_file_test (g_home_dir, G_FILE_TEST_IS_DIR)))
+ {
+ g_free (g_home_dir);
+ g_home_dir = NULL;
+ }
+ }
+
+ /* In case HOME is Unix-style (it happens), convert it to
+ * Windows style.
+ */
+ if (g_home_dir)
+ {
+ gchar *p;
+ while ((p = strchr (g_home_dir, '/')) != NULL)
+ *p = '\\';
+ }
+
+ if (!g_home_dir)
+ {
+ /* USERPROFILE is probably the closest equivalent to $HOME? */
+ if (g_getenv ("USERPROFILE") != NULL)
+ g_home_dir = g_strdup (g_getenv ("USERPROFILE"));
+ }
+
+ if (!g_home_dir)
+ g_home_dir = get_special_folder (CSIDL_PROFILE);
+
+ if (!g_home_dir)
+ g_home_dir = get_windows_directory_root ();
+#endif /* G_OS_WIN32 */
+
+#ifdef HAVE_PWD_H
+ {
+ struct passwd *pw = NULL;
+ gpointer buffer = NULL;
+ gint error;
+ gchar *logname;
+
+# if defined (HAVE_POSIX_GETPWUID_R) || defined (HAVE_NONPOSIX_GETPWUID_R)
+ struct passwd pwd;
+# ifdef _SC_GETPW_R_SIZE_MAX
+ /* This reurns the maximum length */
+ glong bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
+
+ if (bufsize < 0)
+ bufsize = 64;
+# else /* _SC_GETPW_R_SIZE_MAX */
+ glong bufsize = 64;
+# endif /* _SC_GETPW_R_SIZE_MAX */
+
+ logname = (gchar *) g_getenv ("LOGNAME");
+
+ do
+ {
+ g_free (buffer);
+ /* we allocate 6 extra bytes to work around a bug in
+ * Mac OS < 10.3. See #156446
+ */
+ buffer = g_malloc (bufsize + 6);
+ errno = 0;
+
+# ifdef HAVE_POSIX_GETPWUID_R
+ if (logname) {
+ error = getpwnam_r (logname, &pwd, buffer, bufsize, &pw);
+ if (!pw || (pw->pw_uid != getuid ())) {
+ /* LOGNAME is lying, fall back to looking up the uid */
+ error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
+ }
+ } else {
+ error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
+ }
+ error = error < 0 ? errno : error;
+# else /* HAVE_NONPOSIX_GETPWUID_R */
+ /* HPUX 11 falls into the HAVE_POSIX_GETPWUID_R case */
+# if defined(_AIX) || defined(__hpux)
+ error = getpwuid_r (getuid (), &pwd, buffer, bufsize);
+ pw = error == 0 ? &pwd : NULL;
+# else /* !_AIX */
+ if (logname) {
+ pw = getpwnam_r (logname, &pwd, buffer, bufsize);
+ if (!pw || (pw->pw_uid != getuid ())) {
+ /* LOGNAME is lying, fall back to looking up the uid */
+ pw = getpwuid_r (getuid (), &pwd, buffer, bufsize);
+ }
+ } else {
+ pw = getpwuid_r (getuid (), &pwd, buffer, bufsize);
+ }
+ error = pw ? 0 : errno;
+# endif /* !_AIX */
+# endif /* HAVE_NONPOSIX_GETPWUID_R */
+
+ if (!pw)
+ {
+ /* we bail out prematurely if the user id can't be found
+ * (should be pretty rare case actually), or if the buffer
+ * should be sufficiently big and lookups are still not
+ * successfull.
+ */
+ if (error == 0 || error == ENOENT)
+ {
+ g_warning ("getpwuid_r(): failed due to unknown user id (%lu)",
+ (gulong) getuid ());
+ break;
+ }
+ if (bufsize > 32 * 1024)
+ {
+ g_warning ("getpwuid_r(): failed due to: %s.",
+ g_strerror (error));
+ break;
+ }
+
+ bufsize *= 2;
+ }
+ }
+ while (!pw);
+# endif /* HAVE_POSIX_GETPWUID_R || HAVE_NONPOSIX_GETPWUID_R */
+
+ if (!pw)
+ {
+ setpwent ();
+ pw = getpwuid (getuid ());
+ endpwent ();
+ }
+ if (pw)
+ {
+ g_user_name = g_strdup (pw->pw_name);
+
+ if (pw->pw_gecos && *pw->pw_gecos != '\0')
+ {
+ gchar **gecos_fields;
+ gchar **name_parts;
+
+ /* split the gecos field and substitute '&' */
+ gecos_fields = g_strsplit (pw->pw_gecos, ",", 0);
+ name_parts = g_strsplit (gecos_fields[0], "&", 0);
+ pw->pw_name[0] = g_ascii_toupper (pw->pw_name[0]);
+ g_real_name = g_strjoinv (pw->pw_name, name_parts);
+ g_strfreev (gecos_fields);
+ g_strfreev (name_parts);
+ }
+
+ if (!g_home_dir)
+ g_home_dir = g_strdup (pw->pw_dir);
+ }
+ g_free (buffer);
+ }
+
+#else /* !HAVE_PWD_H */
+
+#ifdef G_OS_WIN32
+ {
+ guint len = UNLEN+1;
+ wchar_t buffer[UNLEN+1];
+
+ if (GetUserNameW (buffer, (LPDWORD) &len))
+ {
+ g_user_name = g_utf16_to_utf8 (buffer, -1, NULL, NULL, NULL);
+ g_real_name = g_strdup (g_user_name);
+ }
+ }
+#endif /* G_OS_WIN32 */
+
+#endif /* !HAVE_PWD_H */
+
+#ifndef G_OS_WIN32
+ if (!g_home_dir)
+ g_home_dir = g_strdup (g_getenv ("HOME"));
+#endif
+
+#ifdef __EMX__
+ /* change '\\' in %HOME% to '/' */
+ g_strdelimit (g_home_dir, "\\",'/');
+#endif
+ if (!g_user_name)
+ g_user_name = g_strdup ("somebody");
+ if (!g_real_name)
+ g_real_name = g_strdup ("Unknown");
+
+ {
+#ifndef G_OS_WIN32
+ gboolean hostname_fail = (gethostname (hostname, sizeof (hostname)) == -1);
+#else
+ DWORD size = sizeof (hostname);
+ gboolean hostname_fail = (!GetComputerName (hostname, &size));
+#endif
+ g_host_name = g_strdup (hostname_fail ? "localhost" : hostname);
+ }
+
+#ifdef G_OS_WIN32
+ g_tmp_dir_cp = g_locale_from_utf8 (g_tmp_dir, -1, NULL, NULL, NULL);
+ g_user_name_cp = g_locale_from_utf8 (g_user_name, -1, NULL, NULL, NULL);
+ g_real_name_cp = g_locale_from_utf8 (g_real_name, -1, NULL, NULL, NULL);
+
+ if (!g_tmp_dir_cp)
+ g_tmp_dir_cp = g_strdup ("\\");
+ if (!g_user_name_cp)
+ g_user_name_cp = g_strdup ("somebody");
+ if (!g_real_name_cp)
+ g_real_name_cp = g_strdup ("Unknown");
+
+ /* home_dir might be NULL, unlike tmp_dir, user_name and
+ * real_name.
+ */
+ if (g_home_dir)
+ g_home_dir_cp = g_locale_from_utf8 (g_home_dir, -1, NULL, NULL, NULL);
+ else
+ g_home_dir_cp = NULL;
+#endif /* G_OS_WIN32 */
+}
+
+static inline void
+g_get_any_init (void)
+{
+ if (!g_tmp_dir)
+ g_get_any_init_do ();
+}
+
+static inline void
+g_get_any_init_locked (void)
+{
+ G_LOCK (g_utils_global);
+ g_get_any_init ();
+ G_UNLOCK (g_utils_global);
+}
+
+
+/**
+ * g_get_user_name:
+ *
+ * Gets the user name of the current user. The encoding of the returned
+ * string is system-defined. On UNIX, it might be the preferred file name
+ * encoding, or something else, and there is no guarantee that it is even
+ * consistent on a machine. On Windows, it is always UTF-8.
+ *
+ * Returns: the user name of the current user.
+ */
+G_CONST_RETURN gchar*
+g_get_user_name (void)
+{
+ g_get_any_init_locked ();
+ return g_user_name;
+}
+
+/**
+ * g_get_real_name:
+ *
+ * Gets the real name of the user. This usually comes from the user's entry
+ * in the <filename>passwd</filename> file. The encoding of the returned
+ * string is system-defined. (On Windows, it is, however, always UTF-8.)
+ * If the real user name cannot be determined, the string "Unknown" is
+ * returned.
+ *
+ * Returns: the user's real name.
+ */
+G_CONST_RETURN gchar*
+g_get_real_name (void)
+{
+ g_get_any_init_locked ();
+ return g_real_name;
+}
+
+/**
+ * g_get_home_dir:
+ *
+ * Gets the current user's home directory as defined in the
+ * password database.
+ *
+ * Note that in contrast to traditional UNIX tools, this function
+ * prefers <filename>passwd</filename> entries over the <envar>HOME</envar>
+ * environment variable.
+ *
+ * One of the reasons for this decision is that applications in many
+ * cases need special handling to deal with the case where
+ * <envar>HOME</envar> is
+ * <simplelist>
+ * <member>Not owned by the user</member>
+ * <member>Not writeable</member>
+ * <member>Not even readable</member>
+ * </simplelist>
+ * Since applications are in general <emphasis>not</emphasis> written
+ * to deal with these situations it was considered better to make
+ * g_get_home_dir() not pay attention to <envar>HOME</envar> and to
+ * return the real home directory for the user. If applications
+ * want to pay attention to <envar>HOME</envar>, they can do:
+ * |[
+ * const char *homedir = g_getenv ("HOME");
+ * if (!homedir)
+ * homedir = g_get_home_dir (<!-- -->);
+ * ]|
+ *
+ * Returns: the current user's home directory
+ */
+G_CONST_RETURN gchar*
+g_get_home_dir (void)
+{
+ g_get_any_init_locked ();
+ return g_home_dir;
+}
+
+/**
+ * g_get_tmp_dir:
+ *
+ * Gets the directory to use for temporary files. This is found from
+ * inspecting the environment variables <envar>TMPDIR</envar>,
+ * <envar>TMP</envar>, and <envar>TEMP</envar> in that order. If none
+ * of those are defined "/tmp" is returned on UNIX and "C:\" on Windows.
+ * The encoding of the returned string is system-defined. On Windows,
+ * it is always UTF-8. The return value is never %NULL.
+ *
+ * Returns: the directory to use for temporary files.
+ */
+G_CONST_RETURN gchar*
+g_get_tmp_dir (void)
+{
+ g_get_any_init_locked ();
+ return g_tmp_dir;
+}
+
+/**
+ * g_get_host_name:
+ *
+ * Return a name for the machine.
+ *
+ * The returned name is not necessarily a fully-qualified domain name,
+ * or even present in DNS or some other name service at all. It need
+ * not even be unique on your local network or site, but usually it
+ * is. Callers should not rely on the return value having any specific
+ * properties like uniqueness for security purposes. Even if the name
+ * of the machine is changed while an application is running, the
+ * return value from this function does not change. The returned
+ * string is owned by GLib and should not be modified or freed. If no
+ * name can be determined, a default fixed string "localhost" is
+ * returned.
+ *
+ * Returns: the host name of the machine.
+ *
+ * Since: 2.8
+ */
+const gchar *
+g_get_host_name (void)
+{
+ g_get_any_init_locked ();
+ return g_host_name;
+}
+
+G_LOCK_DEFINE_STATIC (g_prgname);
+static gchar *g_prgname = NULL;
+
+/**
+ * g_get_prgname:
+ *
+ * Gets the name of the program. This name should <emphasis>not</emphasis>
+ * be localized, contrast with g_get_application_name().
+ * (If you are using GDK or GTK+ the program name is set in gdk_init(),
+ * which is called by gtk_init(). The program name is found by taking
+ * the last component of <literal>argv[0]</literal>.)
+ *
+ * Returns: the name of the program. The returned string belongs
+ * to GLib and must not be modified or freed.
+ */
+gchar*
+g_get_prgname (void)
+{
+ gchar* retval;
+
+ G_LOCK (g_prgname);
+#ifdef G_OS_WIN32
+ if (g_prgname == NULL)
+ {
+ static gboolean beenhere = FALSE;
+
+ if (!beenhere)
+ {
+ gchar *utf8_buf = NULL;
+ wchar_t buf[MAX_PATH+1];
+
+ beenhere = TRUE;
+ if (GetModuleFileNameW (GetModuleHandle (NULL),
+ buf, G_N_ELEMENTS (buf)) > 0)
+ utf8_buf = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL);
+
+ if (utf8_buf)
+ {
+ g_prgname = g_path_get_basename (utf8_buf);
+ g_free (utf8_buf);
+ }
+ }
+ }
+#endif
+ retval = g_prgname;
+ G_UNLOCK (g_prgname);
+
+ return retval;
+}
+
+/**
+ * g_set_prgname:
+ * @prgname: the name of the program.
+ *
+ * Sets the name of the program. This name should <emphasis>not</emphasis>
+ * be localized, contrast with g_set_application_name(). Note that for
+ * thread-safety reasons this function can only be called once.
+ */
+void
+g_set_prgname (const gchar *prgname)
+{
+ G_LOCK (g_prgname);
+ g_free (g_prgname);
+ g_prgname = g_strdup (prgname);
+ G_UNLOCK (g_prgname);
+}
+
+G_LOCK_DEFINE_STATIC (g_application_name);
+static gchar *g_application_name = NULL;
+
+/**
+ * g_get_application_name:
+ *
+ * Gets a human-readable name for the application, as set by
+ * g_set_application_name(). This name should be localized if
+ * possible, and is intended for display to the user. Contrast with
+ * g_get_prgname(), which gets a non-localized name. If
+ * g_set_application_name() has not been called, returns the result of
+ * g_get_prgname() (which may be %NULL if g_set_prgname() has also not
+ * been called).
+ *
+ * Return value: human-readable application name. may return %NULL
+ *
+ * Since: 2.2
+ **/
+G_CONST_RETURN gchar*
+g_get_application_name (void)
+{
+ gchar* retval;
+
+ G_LOCK (g_application_name);
+ retval = g_application_name;
+ G_UNLOCK (g_application_name);
+
+ if (retval == NULL)
+ return g_get_prgname ();
+
+ return retval;
+}
+
+/**
+ * g_set_application_name:
+ * @application_name: localized name of the application
+ *
+ * Sets a human-readable name for the application. This name should be
+ * localized if possible, and is intended for display to the user.
+ * Contrast with g_set_prgname(), which sets a non-localized name.
+ * g_set_prgname() will be called automatically by gtk_init(),
+ * but g_set_application_name() will not.
+ *
+ * Note that for thread safety reasons, this function can only
+ * be called once.
+ *
+ * The application name will be used in contexts such as error messages,
+ * or when displaying an application's name in the task list.
+ *
+ * Since: 2.2
+ **/
+void
+g_set_application_name (const gchar *application_name)
+{
+ gboolean already_set = FALSE;
+
+ G_LOCK (g_application_name);
+ if (g_application_name)
+ already_set = TRUE;
+ else
+ g_application_name = g_strdup (application_name);
+ G_UNLOCK (g_application_name);
+
+ if (already_set)
+ g_warning ("g_set_application() name called multiple times");
+}
+
+/**
+ * g_get_user_data_dir:
+ *
+ * Returns a base directory in which to access application data such
+ * as icons that is customized for a particular user.
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ *
+ * Return value: a string owned by GLib that must not be modified
+ * or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar*
+g_get_user_data_dir (void)
+{
+ gchar *data_dir;
+
+ G_LOCK (g_utils_global);
+
+ if (!g_user_data_dir)
+ {
+#ifdef G_OS_WIN32
+ data_dir = get_special_folder (CSIDL_PERSONAL);
+#else
+ data_dir = (gchar *) g_getenv ("XDG_DATA_HOME");
+
+ if (data_dir && data_dir[0])
+ data_dir = g_strdup (data_dir);
+#endif
+ if (!data_dir || !data_dir[0])
+ {
+ g_get_any_init ();
+
+ if (g_home_dir)
+ data_dir = g_build_filename (g_home_dir, ".local",
+ "share", NULL);
+ else
+ data_dir = g_build_filename (g_tmp_dir, g_user_name, ".local",
+ "share", NULL);
+ }
+
+ g_user_data_dir = data_dir;
+ }
+ else
+ data_dir = g_user_data_dir;
+
+ G_UNLOCK (g_utils_global);
+
+ return data_dir;
+}
+
+static void
+g_init_user_config_dir (void)
+{
+ gchar *config_dir;
+
+ if (!g_user_config_dir)
+ {
+#ifdef G_OS_WIN32
+ config_dir = get_special_folder (CSIDL_APPDATA);
+#else
+ config_dir = (gchar *) g_getenv ("XDG_CONFIG_HOME");
+
+ if (config_dir && config_dir[0])
+ config_dir = g_strdup (config_dir);
+#endif
+ if (!config_dir || !config_dir[0])
+ {
+ g_get_any_init ();
+
+ if (g_home_dir)
+ config_dir = g_build_filename (g_home_dir, ".config", NULL);
+ else
+ config_dir = g_build_filename (g_tmp_dir, g_user_name, ".config", NULL);
+ }
+
+ g_user_config_dir = config_dir;
+ }
+}
+
+/**
+ * g_get_user_config_dir:
+ *
+ * Returns a base directory in which to store user-specific application
+ * configuration information such as user preferences and settings.
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ *
+ * Return value: a string owned by GLib that must not be modified
+ * or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar*
+g_get_user_config_dir (void)
+{
+ G_LOCK (g_utils_global);
+
+ g_init_user_config_dir ();
+
+ G_UNLOCK (g_utils_global);
+
+ return g_user_config_dir;
+}
+
+/**
+ * g_get_user_cache_dir:
+ *
+ * Returns a base directory in which to store non-essential, cached
+ * data specific to particular user.
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ *
+ * Return value: a string owned by GLib that must not be modified
+ * or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar*
+g_get_user_cache_dir (void)
+{
+ gchar *cache_dir;
+
+ G_LOCK (g_utils_global);
+
+ if (!g_user_cache_dir)
+ {
+#ifdef G_OS_WIN32
+ cache_dir = get_special_folder (CSIDL_INTERNET_CACHE); /* XXX correct? */
+#else
+ cache_dir = (gchar *) g_getenv ("XDG_CACHE_HOME");
+
+ if (cache_dir && cache_dir[0])
+ cache_dir = g_strdup (cache_dir);
+#endif
+ if (!cache_dir || !cache_dir[0])
+ {
+ g_get_any_init ();
+
+ if (g_home_dir)
+ cache_dir = g_build_filename (g_home_dir, ".cache", NULL);
+ else
+ cache_dir = g_build_filename (g_tmp_dir, g_user_name, ".cache", NULL);
+ }
+ g_user_cache_dir = cache_dir;
+ }
+ else
+ cache_dir = g_user_cache_dir;
+
+ G_UNLOCK (g_utils_global);
+
+ return cache_dir;
+}
+
+#ifdef HAVE_CARBON
+
+static gchar *
+find_folder (OSType type)
+{
+ gchar *filename = NULL;
+ FSRef found;
+
+ if (FSFindFolder (kUserDomain, type, kDontCreateFolder, &found) == noErr)
+ {
+ CFURLRef url = CFURLCreateFromFSRef (kCFAllocatorSystemDefault, &found);
+
+ if (url)
+ {
+ CFStringRef path = CFURLCopyFileSystemPath (url, kCFURLPOSIXPathStyle);
+
+ if (path)
+ {
+ filename = g_strdup (CFStringGetCStringPtr (path, kCFStringEncodingUTF8));
+
+ if (! filename)
+ {
+ filename = g_new0 (gchar, CFStringGetLength (path) * 3 + 1);
+
+ CFStringGetCString (path, filename,
+ CFStringGetLength (path) * 3 + 1,
+ kCFStringEncodingUTF8);
+ }
+
+ CFRelease (path);
+ }
+
+ CFRelease (url);
+ }
+ }
+
+ return filename;
+}
+
+static void
+load_user_special_dirs (void)
+{
+ g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = find_folder (kDesktopFolderType);
+ g_user_special_dirs[G_USER_DIRECTORY_DOCUMENTS] = find_folder (kDocumentsFolderType);
+ g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = find_folder (kDesktopFolderType); /* XXX correct ? */
+ g_user_special_dirs[G_USER_DIRECTORY_MUSIC] = find_folder (kMusicDocumentsFolderType);
+ g_user_special_dirs[G_USER_DIRECTORY_PICTURES] = find_folder (kPictureDocumentsFolderType);
+ g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = NULL;
+ g_user_special_dirs[G_USER_DIRECTORY_TEMPLATES] = NULL;
+ g_user_special_dirs[G_USER_DIRECTORY_VIDEOS] = find_folder (kMovieDocumentsFolderType);
+}
+
+#endif /* HAVE_CARBON */
+
+#if defined(G_OS_WIN32)
+static void
+load_user_special_dirs (void)
+{
+ typedef HRESULT (WINAPI *t_SHGetKnownFolderPath) (const GUID *rfid,
+ DWORD dwFlags,
+ HANDLE hToken,
+ PWSTR *ppszPath);
+ t_SHGetKnownFolderPath p_SHGetKnownFolderPath;
+ static const GUID FOLDERID_Downloads =
+ { 0x374de290, 0x123f, 0x4565, { 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b } };
+ static const GUID FOLDERID_Public =
+ { 0xDFDF76A2, 0xC82A, 0x4D63, { 0x90, 0x6A, 0x56, 0x44, 0xAC, 0x45, 0x73, 0x85 } };
+ wchar_t *wcp;
+
+ p_SHGetKnownFolderPath = (t_SHGetKnownFolderPath) GetProcAddress (LoadLibrary ("shell32.dll"),
+ "SHGetKnownFolderPath");
+
+ g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
+ g_user_special_dirs[G_USER_DIRECTORY_DOCUMENTS] = get_special_folder (CSIDL_PERSONAL);
+
+ if (p_SHGetKnownFolderPath == NULL)
+ {
+ g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
+ }
+ else
+ {
+ wcp = NULL;
+ (*p_SHGetKnownFolderPath) (&FOLDERID_Downloads, 0, NULL, &wcp);
+ g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = g_utf16_to_utf8 (wcp, -1, NULL, NULL, NULL);
+ if (g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] == NULL)
+ g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
+ CoTaskMemFree (wcp);
+ }
+
+ g_user_special_dirs[G_USER_DIRECTORY_MUSIC] = get_special_folder (CSIDL_MYMUSIC);
+ g_user_special_dirs[G_USER_DIRECTORY_PICTURES] = get_special_folder (CSIDL_MYPICTURES);
+
+ if (p_SHGetKnownFolderPath == NULL)
+ {
+ /* XXX */
+ g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (CSIDL_COMMON_DOCUMENTS);
+ }
+ else
+ {
+ wcp = NULL;
+ (*p_SHGetKnownFolderPath) (&FOLDERID_Public, 0, NULL, &wcp);
+ g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = g_utf16_to_utf8 (wcp, -1, NULL, NULL, NULL);
+ if (g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] == NULL)
+ g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (CSIDL_COMMON_DOCUMENTS);
+ CoTaskMemFree (wcp);
+ }
+
+ g_user_special_dirs[G_USER_DIRECTORY_TEMPLATES] = get_special_folder (CSIDL_TEMPLATES);
+ g_user_special_dirs[G_USER_DIRECTORY_VIDEOS] = get_special_folder (CSIDL_MYVIDEO);
+}
+#endif /* G_OS_WIN32 */
+
+static void g_init_user_config_dir (void);
+
+#if defined(G_OS_UNIX) && !defined(HAVE_CARBON)
+
+/* adapted from xdg-user-dir-lookup.c
+ *
+ * Copyright (C) 2007 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+static void
+load_user_special_dirs (void)
+{
+ gchar *config_file;
+ gchar *data;
+ gchar **lines;
+ gint n_lines, i;
+
+ g_init_user_config_dir ();
+ config_file = g_build_filename (g_user_config_dir,
+ "user-dirs.dirs",
+ NULL);
+
+ if (!g_file_get_contents (config_file, &data, NULL, NULL))
+ {
+ g_free (config_file);
+ return;
+ }
+
+ lines = g_strsplit (data, "\n", -1);
+ n_lines = g_strv_length (lines);
+ g_free (data);
+
+ for (i = 0; i < n_lines; i++)
+ {
+ gchar *buffer = lines[i];
+ gchar *d, *p;
+ gint len;
+ gboolean is_relative = FALSE;
+ GUserDirectory directory;
+
+ /* Remove newline at end */
+ len = strlen (buffer);
+ if (len > 0 && buffer[len - 1] == '\n')
+ buffer[len - 1] = 0;
+
+ p = buffer;
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (strncmp (p, "XDG_DESKTOP_DIR", strlen ("XDG_DESKTOP_DIR")) == 0)
+ {
+ directory = G_USER_DIRECTORY_DESKTOP;
+ p += strlen ("XDG_DESKTOP_DIR");
+ }
+ else if (strncmp (p, "XDG_DOCUMENTS_DIR", strlen ("XDG_DOCUMENTS_DIR")) == 0)
+ {
+ directory = G_USER_DIRECTORY_DOCUMENTS;
+ p += strlen ("XDG_DOCUMENTS_DIR");
+ }
+ else if (strncmp (p, "XDG_DOWNLOAD_DIR", strlen ("XDG_DOWNLOAD_DIR")) == 0)
+ {
+ directory = G_USER_DIRECTORY_DOWNLOAD;
+ p += strlen ("XDG_DOWNLOAD_DIR");
+ }
+ else if (strncmp (p, "XDG_MUSIC_DIR", strlen ("XDG_MUSIC_DIR")) == 0)
+ {
+ directory = G_USER_DIRECTORY_MUSIC;
+ p += strlen ("XDG_MUSIC_DIR");
+ }
+ else if (strncmp (p, "XDG_PICTURES_DIR", strlen ("XDG_PICTURES_DIR")) == 0)
+ {
+ directory = G_USER_DIRECTORY_PICTURES;
+ p += strlen ("XDG_PICTURES_DIR");
+ }
+ else if (strncmp (p, "XDG_PUBLICSHARE_DIR", strlen ("XDG_PUBLICSHARE_DIR")) == 0)
+ {
+ directory = G_USER_DIRECTORY_PUBLIC_SHARE;
+ p += strlen ("XDG_PUBLICSHARE_DIR");
+ }
+ else if (strncmp (p, "XDG_TEMPLATES_DIR", strlen ("XDG_TEMPLATES_DIR")) == 0)
+ {
+ directory = G_USER_DIRECTORY_TEMPLATES;
+ p += strlen ("XDG_TEMPLATES_DIR");
+ }
+ else if (strncmp (p, "XDG_VIDEOS_DIR", strlen ("XDG_VIDEOS_DIR")) == 0)
+ {
+ directory = G_USER_DIRECTORY_VIDEOS;
+ p += strlen ("XDG_VIDEOS_DIR");
+ }
+ else
+ continue;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (*p != '=')
+ continue;
+ p++;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (*p != '"')
+ continue;
+ p++;
+
+ if (strncmp (p, "$HOME", 5) == 0)
+ {
+ p += 5;
+ is_relative = TRUE;
+ }
+ else if (*p != '/')
+ continue;
+
+ d = strrchr (p, '"');
+ if (!d)
+ continue;
+ *d = 0;
+
+ d = p;
+
+ /* remove trailing slashes */
+ len = strlen (d);
+ if (d[len - 1] == '/')
+ d[len - 1] = 0;
+
+ if (is_relative)
+ {
+ g_get_any_init ();
+ g_user_special_dirs[directory] = g_build_filename (g_home_dir, d, NULL);
+ }
+ else
+ g_user_special_dirs[directory] = g_strdup (d);
+ }
+
+ g_strfreev (lines);
+ g_free (config_file);
+}
+
+#endif /* G_OS_UNIX && !HAVE_CARBON */
+
+/**
+ * g_get_user_special_dir:
+ * @directory: the logical id of special directory
+ *
+ * Returns the full path of a special directory using its logical id.
+ *
+ * On Unix this is done using the XDG special user directories.
+ * For compatibility with existing practise, %G_USER_DIRECTORY_DESKTOP
+ * falls back to <filename>$HOME/Desktop</filename> when XDG special
+ * user directories have not been set up.
+ *
+ * Depending on the platform, the user might be able to change the path
+ * of the special directory without requiring the session to restart; GLib
+ * will not reflect any change once the special directories are loaded.
+ *
+ * Return value: the path to the specified special directory, or %NULL
+ * if the logical id was not found. The returned string is owned by
+ * GLib and should not be modified or freed.
+ *
+ * Since: 2.14
+ */
+G_CONST_RETURN gchar *
+g_get_user_special_dir (GUserDirectory directory)
+{
+ g_return_val_if_fail (directory >= G_USER_DIRECTORY_DESKTOP &&
+ directory < G_USER_N_DIRECTORIES, NULL);
+
+ G_LOCK (g_utils_global);
+
+ if (G_UNLIKELY (g_user_special_dirs == NULL))
+ {
+ g_user_special_dirs = g_new0 (gchar *, G_USER_N_DIRECTORIES);
+
+ load_user_special_dirs ();
+
+ /* Special-case desktop for historical compatibility */
+ if (g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] == NULL)
+ {
+ g_get_any_init ();
+
+ g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] =
+ g_build_filename (g_home_dir, "Desktop", NULL);
+ }
+ }
+
+ G_UNLOCK (g_utils_global);
+
+ return g_user_special_dirs[directory];
+}
+
+#ifdef G_OS_WIN32
+
+#undef g_get_system_data_dirs
+
+static HMODULE
+get_module_for_address (gconstpointer address)
+{
+ /* Holds the g_utils_global lock */
+
+ static gboolean beenhere = FALSE;
+ typedef BOOL (WINAPI *t_GetModuleHandleExA) (DWORD, LPCTSTR, HMODULE *);
+ static t_GetModuleHandleExA p_GetModuleHandleExA = NULL;
+ HMODULE hmodule = NULL;
+
+ if (!address)
+ return NULL;
+
+ if (!beenhere)
+ {
+ p_GetModuleHandleExA =
+ (t_GetModuleHandleExA) GetProcAddress (LoadLibrary ("kernel32.dll"),
+ "GetModuleHandleExA");
+ beenhere = TRUE;
+ }
+
+ if (p_GetModuleHandleExA == NULL ||
+ !(*p_GetModuleHandleExA) (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ address, &hmodule))
+ {
+ MEMORY_BASIC_INFORMATION mbi;
+ VirtualQuery (address, &mbi, sizeof (mbi));
+ hmodule = (HMODULE) mbi.AllocationBase;
+ }
+
+ return hmodule;
+}
+
+static gchar *
+get_module_share_dir (gconstpointer address)
+{
+ HMODULE hmodule;
+ gchar *filename;
+ gchar *retval;
+
+ hmodule = get_module_for_address (address);
+ if (hmodule == NULL)
+ return NULL;
+
+ filename = g_win32_get_package_installation_directory_of_module (hmodule);
+ retval = g_build_filename (filename, "share", NULL);
+ g_free (filename);
+
+ return retval;
+}
+
+G_CONST_RETURN gchar * G_CONST_RETURN *
+g_win32_get_system_data_dirs_for_module (gconstpointer address)
+{
+ GArray *data_dirs;
+ HMODULE hmodule;
+ static GHashTable *per_module_data_dirs = NULL;
+ gchar **retval;
+ gchar *p;
+ gchar *exe_root;
+
+ if (address)
+ {
+ G_LOCK (g_utils_global);
+ hmodule = get_module_for_address (address);
+ if (hmodule != NULL)
+ {
+ if (per_module_data_dirs == NULL)
+ per_module_data_dirs = g_hash_table_new (NULL, NULL);
+ else
+ {
+ retval = g_hash_table_lookup (per_module_data_dirs, hmodule);
+
+ if (retval != NULL)
+ {
+ G_UNLOCK (g_utils_global);
+ return (G_CONST_RETURN gchar * G_CONST_RETURN *) retval;
+ }
+ }
+ }
+ }
+
+ data_dirs = g_array_new (TRUE, TRUE, sizeof (char *));
+
+ /* Documents and Settings\All Users\Application Data */
+ p = get_special_folder (CSIDL_COMMON_APPDATA);
+ if (p)
+ g_array_append_val (data_dirs, p);
+
+ /* Documents and Settings\All Users\Documents */
+ p = get_special_folder (CSIDL_COMMON_DOCUMENTS);
+ if (p)
+ g_array_append_val (data_dirs, p);
+
+ /* Using the above subfolders of Documents and Settings perhaps
+ * makes sense from a Windows perspective.
+ *
+ * But looking at the actual use cases of this function in GTK+
+ * and GNOME software, what we really want is the "share"
+ * subdirectory of the installation directory for the package
+ * our caller is a part of.
+ *
+ * The address parameter, if non-NULL, points to a function in the
+ * calling module. Use that to determine that module's installation
+ * folder, and use its "share" subfolder.
+ *
+ * Additionally, also use the "share" subfolder of the installation
+ * locations of GLib and the .exe file being run.
+ *
+ * To guard against none of the above being what is really wanted,
+ * callers of this function should have Win32-specific code to look
+ * up their installation folder themselves, and handle a subfolder
+ * "share" of it in the same way as the folders returned from this
+ * function.
+ */
+
+ p = get_module_share_dir (address);
+ if (p)
+ g_array_append_val (data_dirs, p);
+
+ if (glib_dll != NULL)
+ {
+ gchar *glib_root = g_win32_get_package_installation_directory_of_module (glib_dll);
+ p = g_build_filename (glib_root, "share", NULL);
+ if (p)
+ g_array_append_val (data_dirs, p);
+ g_free (glib_root);
+ }
+
+ exe_root = g_win32_get_package_installation_directory_of_module (NULL);
+ p = g_build_filename (exe_root, "share", NULL);
+ if (p)
+ g_array_append_val (data_dirs, p);
+ g_free (exe_root);
+
+ retval = (gchar **) g_array_free (data_dirs, FALSE);
+
+ if (address)
+ {
+ if (hmodule != NULL)
+ g_hash_table_insert (per_module_data_dirs, hmodule, retval);
+ G_UNLOCK (g_utils_global);
+ }
+
+ return (G_CONST_RETURN gchar * G_CONST_RETURN *) retval;
+}
+
+#endif
+
+/**
+ * g_get_system_data_dirs:
+ *
+ * Returns an ordered list of base directories in which to access
+ * system-wide application data.
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ *
+ * On Windows the first elements in the list are the Application Data
+ * and Documents folders for All Users. (These can be determined only
+ * on Windows 2000 or later and are not present in the list on other
+ * Windows versions.) See documentation for CSIDL_COMMON_APPDATA and
+ * CSIDL_COMMON_DOCUMENTS.
+ *
+ * Then follows the "share" subfolder in the installation folder for
+ * the package containing the DLL that calls this function, if it can
+ * be determined.
+ *
+ * Finally the list contains the "share" subfolder in the installation
+ * folder for GLib, and in the installation folder for the package the
+ * application's .exe file belongs to.
+ *
+ * The installation folders above are determined by looking up the
+ * folder where the module (DLL or EXE) in question is located. If the
+ * folder's name is "bin", its parent is used, otherwise the folder
+ * itself.
+ *
+ * Note that on Windows the returned list can vary depending on where
+ * this function is called.
+ *
+ * Return value: a %NULL-terminated array of strings owned by GLib that must
+ * not be modified or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar * G_CONST_RETURN *
+g_get_system_data_dirs (void)
+{
+ gchar **data_dir_vector;
+
+ G_LOCK (g_utils_global);
+
+ if (!g_system_data_dirs)
+ {
+#ifdef G_OS_WIN32
+ data_dir_vector = (gchar **) g_win32_get_system_data_dirs_for_module (NULL);
+#else
+ gchar *data_dirs = (gchar *) g_getenv ("XDG_DATA_DIRS");
+
+ if (!data_dirs || !data_dirs[0])
+ data_dirs = "/usr/local/share/:/usr/share/";
+
+ data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
+#endif
+
+ g_system_data_dirs = data_dir_vector;
+ }
+ else
+ data_dir_vector = g_system_data_dirs;
+
+ G_UNLOCK (g_utils_global);
+
+ return (G_CONST_RETURN gchar * G_CONST_RETURN *) data_dir_vector;
+}
+
+/**
+ * g_get_system_config_dirs:
+ *
+ * Returns an ordered list of base directories in which to access
+ * system-wide configuration information.
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ *
+ * Return value: a %NULL-terminated array of strings owned by GLib that must
+ * not be modified or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar * G_CONST_RETURN *
+g_get_system_config_dirs (void)
+{
+ gchar *conf_dirs, **conf_dir_vector;
+
+ G_LOCK (g_utils_global);
+
+ if (!g_system_config_dirs)
+ {
+#ifdef G_OS_WIN32
+ conf_dirs = get_special_folder (CSIDL_COMMON_APPDATA);
+ if (conf_dirs)
+ {
+ conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
+ g_free (conf_dirs);
+ }
+ else
+ {
+ /* Return empty list */
+ conf_dir_vector = g_strsplit ("", G_SEARCHPATH_SEPARATOR_S, 0);
+ }
+#else
+ conf_dirs = (gchar *) g_getenv ("XDG_CONFIG_DIRS");
+
+ if (!conf_dirs || !conf_dirs[0])
+ conf_dirs = "/etc/xdg";
+
+ conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
+#endif
+
+ g_system_config_dirs = conf_dir_vector;
+ }
+ else
+ conf_dir_vector = g_system_config_dirs;
+ G_UNLOCK (g_utils_global);
+
+ return (G_CONST_RETURN gchar * G_CONST_RETURN *) conf_dir_vector;
+}
+
+#ifndef G_OS_WIN32
+
+static GHashTable *alias_table = NULL;
+
+/* read an alias file for the locales */
+static void
+read_aliases (gchar *file)
+{
+ FILE *fp;
+ char buf[256];
+
+ if (!alias_table)
+ alias_table = g_hash_table_new (g_str_hash, g_str_equal);
+ fp = fopen (file,"r");
+ if (!fp)
+ return;
+ while (fgets (buf, 256, fp))
+ {
+ char *p, *q;
+
+ g_strstrip (buf);
+
+ /* Line is a comment */
+ if ((buf[0] == '#') || (buf[0] == '\0'))
+ continue;
+
+ /* Reads first column */
+ for (p = buf, q = NULL; *p; p++) {
+ if ((*p == '\t') || (*p == ' ') || (*p == ':')) {
+ *p = '\0';
+ q = p+1;
+ while ((*q == '\t') || (*q == ' ')) {
+ q++;
+ }
+ break;
+ }
+ }
+ /* The line only had one column */
+ if (!q || *q == '\0')
+ continue;
+
+ /* Read second column */
+ for (p = q; *p; p++) {
+ if ((*p == '\t') || (*p == ' ')) {
+ *p = '\0';
+ break;
+ }
+ }
+
+ /* Add to alias table if necessary */
+ if (!g_hash_table_lookup (alias_table, buf)) {
+ g_hash_table_insert (alias_table, g_strdup (buf), g_strdup (q));
+ }
+ }
+ fclose (fp);
+}
+
+#endif
+
+static char *
+unalias_lang (char *lang)
+{
+#ifndef G_OS_WIN32
+ char *p;
+ int i;
+
+ if (!alias_table)
+ read_aliases ("/usr/share/locale/locale.alias");
+
+ i = 0;
+ while ((p = g_hash_table_lookup (alias_table, lang)) && (strcmp (p, lang) != 0))
+ {
+ lang = p;
+ if (i++ == 30)
+ {
+ static gboolean said_before = FALSE;
+ if (!said_before)
+ g_warning ("Too many alias levels for a locale, "
+ "may indicate a loop");
+ said_before = TRUE;
+ return lang;
+ }
+ }
+#endif
+ return lang;
+}
+
+/* Mask for components of locale spec. The ordering here is from
+ * least significant to most significant
+ */
+enum
+{
+ COMPONENT_CODESET = 1 << 0,
+ COMPONENT_TERRITORY = 1 << 1,
+ COMPONENT_MODIFIER = 1 << 2
+};
+
+/* Break an X/Open style locale specification into components
+ */
+static guint
+explode_locale (const gchar *locale,
+ gchar **language,
+ gchar **territory,
+ gchar **codeset,
+ gchar **modifier)
+{
+ const gchar *uscore_pos;
+ const gchar *at_pos;
+ const gchar *dot_pos;
+
+ guint mask = 0;
+
+ uscore_pos = strchr (locale, '_');
+ dot_pos = strchr (uscore_pos ? uscore_pos : locale, '.');
+ at_pos = strchr (dot_pos ? dot_pos : (uscore_pos ? uscore_pos : locale), '@');
+
+ if (at_pos)
+ {
+ mask |= COMPONENT_MODIFIER;
+ *modifier = g_strdup (at_pos);
+ }
+ else
+ at_pos = locale + strlen (locale);
+
+ if (dot_pos)
+ {
+ mask |= COMPONENT_CODESET;
+ *codeset = g_strndup (dot_pos, at_pos - dot_pos);
+ }
+ else
+ dot_pos = at_pos;
+
+ if (uscore_pos)
+ {
+ mask |= COMPONENT_TERRITORY;
+ *territory = g_strndup (uscore_pos, dot_pos - uscore_pos);
+ }
+ else
+ uscore_pos = dot_pos;
+
+ *language = g_strndup (locale, uscore_pos - locale);
+
+ return mask;
+}
+
+/*
+ * Compute all interesting variants for a given locale name -
+ * by stripping off different components of the value.
+ *
+ * For simplicity, we assume that the locale is in
+ * X/Open format: language[_territory][.codeset][@modifier]
+ *
+ * TODO: Extend this to handle the CEN format (see the GNUlibc docs)
+ * as well. We could just copy the code from glibc wholesale
+ * but it is big, ugly, and complicated, so I'm reluctant
+ * to do so when this should handle 99% of the time...
+ */
+GSList *
+_g_compute_locale_variants (const gchar *locale)
+{
+ GSList *retval = NULL;
+
+ gchar *language = NULL;
+ gchar *territory = NULL;
+ gchar *codeset = NULL;
+ gchar *modifier = NULL;
+
+ guint mask;
+ guint i;
+
+ g_return_val_if_fail (locale != NULL, NULL);
+
+ mask = explode_locale (locale, &language, &territory, &codeset, &modifier);
+
+ /* Iterate through all possible combinations, from least attractive
+ * to most attractive.
+ */
+ for (i = 0; i <= mask; i++)
+ if ((i & ~mask) == 0)
+ {
+ gchar *val = g_strconcat (language,
+ (i & COMPONENT_TERRITORY) ? territory : "",
+ (i & COMPONENT_CODESET) ? codeset : "",
+ (i & COMPONENT_MODIFIER) ? modifier : "",
+ NULL);
+ retval = g_slist_prepend (retval, val);
+ }
+
+ g_free (language);
+ if (mask & COMPONENT_CODESET)
+ g_free (codeset);
+ if (mask & COMPONENT_TERRITORY)
+ g_free (territory);
+ if (mask & COMPONENT_MODIFIER)
+ g_free (modifier);
+
+ return retval;
+}
+
+/* The following is (partly) taken from the gettext package.
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. */
+
+static const gchar *
+guess_category_value (const gchar *category_name)
+{
+ const gchar *retval;
+
+ /* The highest priority value is the `LANGUAGE' environment
+ variable. This is a GNU extension. */
+ retval = g_getenv ("LANGUAGE");
+ if ((retval != NULL) && (retval[0] != '\0'))
+ return retval;
+
+ /* `LANGUAGE' is not set. So we have to proceed with the POSIX
+ methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some
+ systems this can be done by the `setlocale' function itself. */
+
+ /* Setting of LC_ALL overwrites all other. */
+ retval = g_getenv ("LC_ALL");
+ if ((retval != NULL) && (retval[0] != '\0'))
+ return retval;
+
+ /* Next comes the name of the desired category. */
+ retval = g_getenv (category_name);
+ if ((retval != NULL) && (retval[0] != '\0'))
+ return retval;
+
+ /* Last possibility is the LANG environment variable. */
+ retval = g_getenv ("LANG");
+ if ((retval != NULL) && (retval[0] != '\0'))
+ return retval;
+
+#ifdef G_PLATFORM_WIN32
+ /* g_win32_getlocale() first checks for LC_ALL, LC_MESSAGES and
+ * LANG, which we already did above. Oh well. The main point of
+ * calling g_win32_getlocale() is to get the thread's locale as used
+ * by Windows and the Microsoft C runtime (in the "English_United
+ * States" format) translated into the Unixish format.
+ */
+ retval = g_win32_getlocale ();
+ if ((retval != NULL) && (retval[0] != '\0'))
+ return retval;
+#endif
+
+ return NULL;
+}
+
+typedef struct _GLanguageNamesCache GLanguageNamesCache;
+
+struct _GLanguageNamesCache {
+ gchar *languages;
+ gchar **language_names;
+};
+
+static void
+language_names_cache_free (gpointer data)
+{
+ GLanguageNamesCache *cache = data;
+ g_free (cache->languages);
+ g_strfreev (cache->language_names);
+ g_free (cache);
+}
+
+/**
+ * g_get_language_names:
+ *
+ * Computes a list of applicable locale names, which can be used to
+ * e.g. construct locale-dependent filenames or search paths. The returned
+ * list is sorted from most desirable to least desirable and always contains
+ * the default locale "C".
+ *
+ * For example, if LANGUAGE=de:en_US, then the returned list is
+ * "de", "en_US", "en", "C".
+ *
+ * This function consults the environment variables <envar>LANGUAGE</envar>,
+ * <envar>LC_ALL</envar>, <envar>LC_MESSAGES</envar> and <envar>LANG</envar>
+ * to find the list of locales specified by the user.
+ *
+ * Return value: a %NULL-terminated array of strings owned by GLib
+ * that must not be modified or freed.
+ *
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar * G_CONST_RETURN *
+g_get_language_names (void)
+{
+ static GStaticPrivate cache_private = G_STATIC_PRIVATE_INIT;
+ GLanguageNamesCache *cache = g_static_private_get (&cache_private);
+ const gchar *value;
+
+ if (!cache)
+ {
+ cache = g_new0 (GLanguageNamesCache, 1);
+ g_static_private_set (&cache_private, cache, language_names_cache_free);
+ }
+
+ value = guess_category_value ("LC_MESSAGES");
+ if (!value)
+ value = "C";
+
+ if (!(cache->languages && strcmp (cache->languages, value) == 0))
+ {
+ gchar **languages;
+ gchar **alist, **a;
+ GSList *list, *l;
+ gint i;
+
+ g_free (cache->languages);
+ g_strfreev (cache->language_names);
+ cache->languages = g_strdup (value);
+
+ alist = g_strsplit (value, ":", 0);
+ list = NULL;
+ for (a = alist; *a; a++)
+ {
+ gchar *b = unalias_lang (*a);
+ list = g_slist_concat (list, _g_compute_locale_variants (b));
+ }
+ g_strfreev (alist);
+ list = g_slist_append (list, g_strdup ("C"));
+
+ cache->language_names = languages = g_new (gchar *, g_slist_length (list) + 1);
+ for (l = list, i = 0; l; l = l->next, i++)
+ languages[i] = l->data;
+ languages[i] = NULL;
+
+ g_slist_free (list);
+ }
+
+ return (G_CONST_RETURN gchar * G_CONST_RETURN *) cache->language_names;
+}
+
+#endif /* NOT_NEEDED_FOR_NAVIT */
+/**
+ * g_direct_hash:
+ * @v: a #gpointer key
+ *
+ * Converts a gpointer to a hash value.
+ * It can be passed to g_hash_table_new() as the @hash_func parameter,
+ * when using pointers as keys in a #GHashTable.
+ *
+ * Returns: a hash value corresponding to the key.
+ */
+guint
+g_direct_hash (gconstpointer v)
+{
+ return GPOINTER_TO_UINT (v);
+}
+
+/**
+ * g_direct_equal:
+ * @v1: a key.
+ * @v2: a key to compare with @v1.
+ *
+ * Compares two #gpointer arguments and returns %TRUE if they are equal.
+ * It can be passed to g_hash_table_new() as the @key_equal_func
+ * parameter, when using pointers as keys in a #GHashTable.
+ *
+ * Returns: %TRUE if the two keys match.
+ */
+gboolean
+g_direct_equal (gconstpointer v1,
+ gconstpointer v2)
+{
+ return v1 == v2;
+}
+
+/**
+ * g_int_equal:
+ * @v1: a pointer to a #gint key.
+ * @v2: a pointer to a #gint key to compare with @v1.
+ *
+ * Compares the two #gint values being pointed to and returns
+ * %TRUE if they are equal.
+ * It can be passed to g_hash_table_new() as the @key_equal_func
+ * parameter, when using pointers to integers as keys in a #GHashTable.
+ *
+ * Returns: %TRUE if the two keys match.
+ */
+gboolean
+g_int_equal (gconstpointer v1,
+ gconstpointer v2)
+{
+ return *((const gint*) v1) == *((const gint*) v2);
+}
+
+/**
+ * g_int_hash:
+ * @v: a pointer to a #gint key
+ *
+ * Converts a pointer to a #gint to a hash value.
+ * It can be passed to g_hash_table_new() as the @hash_func parameter,
+ * when using pointers to integers values as keys in a #GHashTable.
+ *
+ * Returns: a hash value corresponding to the key.
+ */
+guint
+g_int_hash (gconstpointer v)
+{
+ return *(const gint*) v;
+}
+
+#if NOT_NEEDED_FOR_NAVIT
+/**
+ * g_nullify_pointer:
+ * @nullify_location: the memory address of the pointer.
+ *
+ * Set the pointer at the specified location to %NULL.
+ **/
+void
+g_nullify_pointer (gpointer *nullify_location)
+{
+ g_return_if_fail (nullify_location != NULL);
+
+ *nullify_location = NULL;
+}
+
+/**
+ * g_get_codeset:
+ *
+ * Get the codeset for the current locale.
+ *
+ * Return value: a newly allocated string containing the name
+ * of the codeset. This string must be freed with g_free().
+ **/
+gchar *
+g_get_codeset (void)
+{
+ const gchar *charset;
+
+ g_get_charset (&charset);
+
+ return g_strdup (charset);
+}
+
+/* This is called from g_thread_init(). It's used to
+ * initialize some static data in a threadsafe way.
+ */
+void
+_g_utils_thread_init (void)
+{
+ g_get_language_names ();
+}
+
+#ifdef G_OS_WIN32
+
+/**
+ * _glib_get_locale_dir:
+ *
+ * Return the path to the share\locale or lib\locale subfolder of the
+ * GLib installation folder. The path is in the system codepage. We
+ * have to use system codepage as bindtextdomain() doesn't have a
+ * UTF-8 interface.
+ */
+static gchar *
+_glib_get_locale_dir (void)
+{
+ gchar *install_dir = NULL, *locale_dir;
+ gchar *retval = NULL;
+
+ if (glib_dll != NULL)
+ install_dir = g_win32_get_package_installation_directory_of_module (glib_dll);
+
+ if (install_dir)
+ {
+ /*
+ * Append "/share/locale" or "/lib/locale" depending on whether
+ * autoconfigury detected GNU gettext or not.
+ */
+ const char *p = GLIB_LOCALE_DIR + strlen (GLIB_LOCALE_DIR);
+ while (*--p != '/')
+ ;
+ while (*--p != '/')
+ ;
+
+ locale_dir = g_build_filename (install_dir, p, NULL);
+
+ retval = g_win32_locale_filename_from_utf8 (locale_dir);
+
+ g_free (install_dir);
+ g_free (locale_dir);
+ }
+
+ if (retval)
+ return retval;
+ else
+ return g_strdup ("");
+}
+
+#undef GLIB_LOCALE_DIR
+
+#endif /* G_OS_WIN32 */
+
+/**
+ * glib_gettext:
+ * @str: The string to be translated
+ *
+ * Returns the translated string from the glib translations.
+ * This is an internal function and should only be used by
+ * the internals of glib (such as libgio).
+ *
+ * Returns: the transation of @str to the current locale
+ */
+G_CONST_RETURN gchar *
+glib_gettext (const gchar *str)
+{
+ static gboolean _glib_gettext_initialized = FALSE;
+
+ if (!_glib_gettext_initialized)
+ {
+#ifdef G_OS_WIN32
+ gchar *tmp = _glib_get_locale_dir ();
+ bindtextdomain (GETTEXT_PACKAGE, tmp);
+ g_free (tmp);
+#else
+ bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
+#endif
+# ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+# endif
+ _glib_gettext_initialized = TRUE;
+ }
+
+ return g_dgettext (GETTEXT_PACKAGE, str);
+}
+
+#if defined (G_OS_WIN32) && !defined (_WIN64)
+
+/* Binary compatibility versions. Not for newly compiled code. */
+
+#undef g_find_program_in_path
+
+gchar*
+g_find_program_in_path (const gchar *program)
+{
+ gchar *utf8_program = g_locale_to_utf8 (program, -1, NULL, NULL, NULL);
+ gchar *utf8_retval = g_find_program_in_path_utf8 (utf8_program);
+ gchar *retval;
+
+ g_free (utf8_program);
+ if (utf8_retval == NULL)
+ return NULL;
+ retval = g_locale_from_utf8 (utf8_retval, -1, NULL, NULL, NULL);
+ g_free (utf8_retval);
+
+ return retval;
+}
+
+#undef g_get_current_dir
+
+gchar*
+g_get_current_dir (void)
+{
+ gchar *utf8_dir = g_get_current_dir_utf8 ();
+ gchar *dir = g_locale_from_utf8 (utf8_dir, -1, NULL, NULL, NULL);
+ g_free (utf8_dir);
+ return dir;
+}
+
+#undef g_getenv
+
+G_CONST_RETURN gchar*
+g_getenv (const gchar *variable)
+{
+ gchar *utf8_variable = g_locale_to_utf8 (variable, -1, NULL, NULL, NULL);
+ const gchar *utf8_value = g_getenv_utf8 (utf8_variable);
+ gchar *value;
+ GQuark quark;
+
+ g_free (utf8_variable);
+ if (!utf8_value)
+ return NULL;
+ value = g_locale_from_utf8 (utf8_value, -1, NULL, NULL, NULL);
+ quark = g_quark_from_string (value);
+ g_free (value);
+
+ return g_quark_to_string (quark);
+}
+
+#undef g_setenv
+
+gboolean
+g_setenv (const gchar *variable,
+ const gchar *value,
+ gboolean overwrite)
+{
+ gchar *utf8_variable = g_locale_to_utf8 (variable, -1, NULL, NULL, NULL);
+ gchar *utf8_value = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
+ gboolean retval = g_setenv_utf8 (utf8_variable, utf8_value, overwrite);
+
+ g_free (utf8_variable);
+ g_free (utf8_value);
+
+ return retval;
+}
+
+#undef g_unsetenv
+
+void
+g_unsetenv (const gchar *variable)
+{
+ gchar *utf8_variable = g_locale_to_utf8 (variable, -1, NULL, NULL, NULL);
+
+ g_unsetenv_utf8 (utf8_variable);
+
+ g_free (utf8_variable);
+}
+
+#undef g_get_user_name
+
+G_CONST_RETURN gchar*
+g_get_user_name (void)
+{
+ g_get_any_init_locked ();
+ return g_user_name_cp;
+}
+
+#undef g_get_real_name
+
+G_CONST_RETURN gchar*
+g_get_real_name (void)
+{
+ g_get_any_init_locked ();
+ return g_real_name_cp;
+}
+
+#undef g_get_home_dir
+
+G_CONST_RETURN gchar*
+g_get_home_dir (void)
+{
+ g_get_any_init_locked ();
+ return g_home_dir_cp;
+}
+
+#undef g_get_tmp_dir
+
+G_CONST_RETURN gchar*
+g_get_tmp_dir (void)
+{
+ g_get_any_init_locked ();
+ return g_tmp_dir_cp;
+}
+
+#endif
+#endif /* NOT_NEEDED_FOR_NAVIT */
+
+#define __G_UTILS_C__
+#include "galiasdef.c"
diff --git a/support/libc/Makefile.am b/support/libc/Makefile.am
new file mode 100644
index 00000000..fd98ea7a
--- /dev/null
+++ b/support/libc/Makefile.am
@@ -0,0 +1,4 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=support_libc
+noinst_LTLIBRARIES = libsupport_libc.la
+libsupport_libc_la_SOURCES = libc.c libc_init.c
diff --git a/support/libc/errno.h b/support/libc/errno.h
new file mode 100644
index 00000000..5ef0a7bd
--- /dev/null
+++ b/support/libc/errno.h
@@ -0,0 +1,4 @@
+extern int errno;
+#define ENOMEM 12
+#define EINVAL 22
+#define ERANGE 34
diff --git a/support/libc/libc.c b/support/libc/libc.c
new file mode 100644
index 00000000..9b5cfe73
--- /dev/null
+++ b/support/libc/libc.c
@@ -0,0 +1,158 @@
+#include "locale.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+int errno;
+
+#define MAXENV 32
+static char *envnames[MAXENV];
+static char *envvars[MAXENV];
+
+static void cleanup_libc(void) __attribute__((destructor));
+static void cleanup_libc(void)
+{
+ int i;
+ for (i=0; i <MAXENV; i++) {
+ if (envnames[i])
+ free(envnames[i]);
+ if (envvars[i])
+ free(envvars[i]);
+ }
+}
+
+char *
+getenv(const char *name)
+{
+ int i;
+ for (i=0; i < MAXENV; i++) {
+ if (envnames[i] && !strcmp(envnames[i], name))
+ return envvars[i];
+ }
+ return NULL;
+}
+
+int
+setenv(const char *name, const char *value, int overwrite)
+{
+ int i;
+ char *val;
+ for (i=0; i < MAXENV; i++) {
+ if (envnames[i] && !strcmp(envnames[i], name)) {
+ if (overwrite) {
+ val = strdup(value);
+ if (!val)
+ return -1;
+ if (envvars[i])
+ free(envvars[i]);
+ envvars[i] = val;
+ }
+ return 0;
+ }
+ }
+ for (i=0; i < MAXENV; i++) {
+ if (!envnames[i]) {
+ envnames[i] = strdup(name);
+ envvars[i] = strdup(value);
+ if (!envnames[i] || !envvars[i]) {
+ if (envnames[i])
+ free(envnames[i]);
+ if (envvars[i])
+ free(envvars[i]);
+ envnames[i] = NULL;
+ envvars[i] = NULL;
+ return -1;
+ }
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int unsetenv(const char *name)
+{
+ int i;
+ for (i=0; i < MAXENV; i++) {
+ if (envnames[i] && !strcmp(envnames[i], name)) {
+ free(envnames[i]);
+ envnames[i] = NULL;
+ if (envvars[i])
+ free(envvars[i]);
+ envvars[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+char *
+getcwd(char *buf, int size)
+{
+ return "dummy";
+}
+
+char *
+getwd(char *buf)
+{
+ return "dummy";
+}
+
+char *strtok_r(char *str, const char *delim, char **saveptr)
+{
+ return strtok(str, delim);
+}
+
+void
+perror(const char *x)
+{
+}
+
+void
+raise(void)
+{
+}
+
+void *
+popen(void)
+{
+ return 0;
+}
+
+void
+pclose(void)
+{
+}
+
+void
+rewind(void)
+{
+}
+
+int
+GetThreadLocale(void)
+{
+ return 0;
+}
+
+int
+signal(void)
+{
+ return 0;
+}
+
+void
+setlocale(void)
+{
+ return 0;
+}
+
+static struct lconv localedata={"."};
+
+struct lconv *
+localeconv(void)
+{
+ return &localedata;
+}
+
+unsigned int
+alarm(unsigned int seconds)
+{
+}
diff --git a/support/libc/libc_init.c b/support/libc/libc_init.c
new file mode 100644
index 00000000..32be387d
--- /dev/null
+++ b/support/libc/libc_init.c
@@ -0,0 +1,6 @@
+#include "plugin.h"
+
+void
+plugin_init(void)
+{
+}
diff --git a/support/libc/locale.h b/support/libc/locale.h
new file mode 100644
index 00000000..fad4f95d
--- /dev/null
+++ b/support/libc/locale.h
@@ -0,0 +1,12 @@
+#ifndef _LOCALE_H
+#define _LOCALE_H 1
+#define SUBLANG_BENGALI_BANGLADESH 0x02
+#define SUBLANG_PUNJABI_PAKISTAN 0x02
+#define SUBLANG_ROMANIAN_MOLDOVA 0x02
+struct lconv {
+ char *decimal_point;
+};
+
+#define LC_ALL 1
+#define LC_NUMERIC 2
+#endif
diff --git a/support/libc/signal.h b/support/libc/signal.h
new file mode 100644
index 00000000..18b65399
--- /dev/null
+++ b/support/libc/signal.h
@@ -0,0 +1,2 @@
+#define SIGFPE 8
+#define SIGSEGV 11
diff --git a/support/win32/ConvertUTF.c b/support/win32/ConvertUTF.c
new file mode 100644
index 00000000..9b3deebd
--- /dev/null
+++ b/support/win32/ConvertUTF.c
@@ -0,0 +1,539 @@
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Source code file.
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Sept 2001: fixed const & error conditions per
+ mods suggested by S. Parent & A. Lillich.
+ June 2002: Tim Dodd added detection and handling of incomplete
+ source sequences, enhanced error detection, added casts
+ to eliminate compiler warnings.
+ July 2003: slight mods to back out aggressive FFFE detection.
+ Jan 2004: updated switches in from-UTF8 conversions.
+ Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
+
+ See the header file "ConvertUTF.h" for complete documentation.
+
+------------------------------------------------------------------------ */
+
+
+#include "ConvertUTF.h"
+#ifdef CVTUTF_DEBUG
+#include <stdio.h>
+#endif
+
+static const int halfShift = 10; /* used for shifting by 10 bits */
+
+static const UTF32 halfBase = 0x0010000UL;
+static const UTF32 halfMask = 0x3FFUL;
+
+#define UNI_SUR_HIGH_START (UTF32)0xD800
+#define UNI_SUR_HIGH_END (UTF32)0xDBFF
+#define UNI_SUR_LOW_START (UTF32)0xDC00
+#define UNI_SUR_LOW_END (UTF32)0xDFFF
+#define false 0
+#define true 1
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF16 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF32* source = *sourceStart;
+ UTF16* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ if (target >= targetEnd) {
+ result = targetExhausted; break;
+ }
+ ch = *source++;
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_LEGAL_UTF32) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ --source; /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF32 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF16* source = *sourceStart;
+ UTF32* target = *targetStart;
+ UTF32 ch, ch2;
+ while (source < sourceEnd) {
+ const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ if (target >= targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ *target++ = ch;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+#ifdef CVTUTF_DEBUG
+if (result == sourceIllegal) {
+ fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
+ fflush(stderr);
+}
+#endif
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Index into the table below with the first byte of a UTF-8 sequence to
+ * get the number of trailing bytes that are supposed to follow it.
+ * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+ * left as-is for anyone who may want to do such conversion, which was
+ * allowed in earlier algorithms.
+ */
+static const char trailingBytesForUTF8[256] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+/*
+ * Magic values subtracted from a buffer value during UTF8 conversion.
+ * This table contains as many values as there might be trailing bytes
+ * in a UTF-8 sequence.
+ */
+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
+ 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+
+/*
+ * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+ * into the first byte, depending on how many bytes follow. There are
+ * as many entries in this table as there are UTF-8 sequence types.
+ * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
+ * for *legal* UTF-8 will be 4 or fewer bytes total.
+ */
+static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+/* --------------------------------------------------------------------- */
+
+/* The interface converts a whole buffer to avoid function-call overhead.
+ * Constants have been gathered. Loops & conditionals have been removed as
+ * much as possible for efficiency, in favor of drop-through switches.
+ * (See "Note A" at the bottom of the file for equivalent code.)
+ * If your compiler supports it, the "isLegalUTF8" call can be turned
+ * into an inline function.
+ */
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF8 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF16* source = *sourceStart;
+ UTF8* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ UTF32 ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /* Figure out how many bytes the result will require */
+ if (ch < (UTF32)0x80) { bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
+ } else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
+ } else { bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ target -= bytesToWrite; result = targetExhausted; break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+ * This must be called with the length pre-determined by the first byte.
+ * If not calling this from ConvertUTF8to*, then the length can be set by:
+ * length = trailingBytesForUTF8[*source]+1;
+ * and the sequence is illegal right away if there aren't that many bytes
+ * available.
+ * If presented with a length > 4, this returns false. The Unicode
+ * definition of UTF-8 goes up to 4-byte sequences.
+ */
+
+static Boolean isLegalUTF8(const UTF8 *source, int length) {
+ UTF8 a;
+ const UTF8 *srcptr = source+length;
+ switch (length) {
+ default: return false;
+ /* Everything else falls through when "true"... */
+ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 2: if ((a = (*--srcptr)) > 0xBF) return false;
+
+ switch (*source) {
+ /* no fall-through in this inner switch */
+ case 0xE0: if (a < 0xA0) return false; break;
+ case 0xED: if (a > 0x9F) return false; break;
+ case 0xF0: if (a < 0x90) return false; break;
+ case 0xF4: if (a > 0x8F) return false; break;
+ default: if (a < 0x80) return false;
+ }
+
+ case 1: if (*source >= 0x80 && *source < 0xC2) return false;
+ }
+ if (*source > 0xF4) return false;
+ return true;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Exported function to return whether a UTF-8 sequence is legal or not.
+ * This is not used here; it's just exported.
+ */
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
+ int length = trailingBytesForUTF8[*source]+1;
+ if (source+length > sourceEnd) {
+ return false;
+ }
+ return isLegalUTF8(source, length);
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF16 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF8* source = *sourceStart;
+ UTF16* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted; break;
+ }
+ /* Do this check whether lenient or strict */
+ if (! isLegalUTF8(source, extraBytesToRead+1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+ case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead+1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_UTF16) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ source -= (extraBytesToRead+1); /* return to the start */
+ break; /* Bail out; shouldn't continue */
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF8 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF32* source = *sourceStart;
+ UTF8* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ ch = *source++;
+ if (flags == strictConversion ) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /*
+ * Figure out how many bytes the result will require. Turn any
+ * illegally large UTF32 things (> Plane 17) into replacement chars.
+ */
+ if (ch < (UTF32)0x80) { bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
+ } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
+ } else { bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ result = sourceIllegal;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ --source; /* Back up source pointer! */
+ target -= bytesToWrite; result = targetExhausted; break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF32 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF8* source = *sourceStart;
+ UTF32* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted; break;
+ }
+ /* Do this check whether lenient or strict */
+ if (! isLegalUTF8(source, extraBytesToRead+1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5: ch += *source++; ch <<= 6;
+ case 4: ch += *source++; ch <<= 6;
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up the source pointer! */
+ result = targetExhausted; break;
+ }
+ if (ch <= UNI_MAX_LEGAL_UTF32) {
+ /*
+ * UTF-16 surrogate values are illegal in UTF-32, and anything
+ * over Plane 17 (> 0x10FFFF) is illegal.
+ */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead+1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = ch;
+ }
+ } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+ result = sourceIllegal;
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* ---------------------------------------------------------------------
+
+ Note A.
+ The fall-through switches in UTF-8 reading code save a
+ temp variable, some decrements & conditionals. The switches
+ are equivalent to the following loop:
+ {
+ int tmpBytesToRead = extraBytesToRead+1;
+ do {
+ ch += *source++;
+ --tmpBytesToRead;
+ if (tmpBytesToRead) ch <<= 6;
+ } while (tmpBytesToRead > 0);
+ }
+ In UTF-8 writing code, the switches on "bytesToWrite" are
+ similarly unrolled loops.
+
+ --------------------------------------------------------------------- */
diff --git a/support/win32/ConvertUTF.h b/support/win32/ConvertUTF.h
new file mode 100644
index 00000000..e2649153
--- /dev/null
+++ b/support/win32/ConvertUTF.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Header file.
+
+ Several funtions are included here, forming a complete set of
+ conversions between the three formats. UTF-7 is not included
+ here, but is handled in a separate source file.
+
+ Each of these routines takes pointers to input buffers and output
+ buffers. The input buffers are const.
+
+ Each routine converts the text between *sourceStart and sourceEnd,
+ putting the result into the buffer between *targetStart and
+ targetEnd. Note: the end pointers are *after* the last item: e.g.
+ *(sourceEnd - 1) is the last item.
+
+ The return result indicates whether the conversion was successful,
+ and if not, whether the problem was in the source or target buffers.
+ (Only the first encountered problem is indicated.)
+
+ After the conversion, *sourceStart and *targetStart are both
+ updated to point to the end of last text successfully converted in
+ the respective buffers.
+
+ Input parameters:
+ sourceStart - pointer to a pointer to the source buffer.
+ The contents of this are modified on return so that
+ it points at the next thing to be converted.
+ targetStart - similarly, pointer to pointer to the target buffer.
+ sourceEnd, targetEnd - respectively pointers to the ends of the
+ two buffers, for overflow checking only.
+
+ These conversion functions take a ConversionFlags argument. When this
+ flag is set to strict, both irregular sequences and isolated surrogates
+ will cause an error. When the flag is set to lenient, both irregular
+ sequences and isolated surrogates are converted.
+
+ Whether the flag is strict or lenient, all illegal sequences will cause
+ an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
+ or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
+ must check for illegal sequences.
+
+ When the flag is set to lenient, characters over 0x10FFFF are converted
+ to the replacement character; otherwise (when the flag is set to strict)
+ they constitute an error.
+
+ Output parameters:
+ The value "sourceIllegal" is returned from some routines if the input
+ sequence is malformed. When "sourceIllegal" is returned, the source
+ value will point to the illegal value that caused the problem. E.g.,
+ in UTF-8 when a sequence is malformed, it points to the start of the
+ malformed sequence.
+
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Fixes & updates, Sept 2001.
+
+------------------------------------------------------------------------ */
+
+/* ---------------------------------------------------------------------
+ The following 4 definitions are compiler-specific.
+ The C standard does not guarantee that wchar_t has at least
+ 16 bits, so wchar_t is no less portable than unsigned short!
+ All should be unsigned values to avoid sign extension during
+ bit mask & shift operations.
+------------------------------------------------------------------------ */
+
+typedef unsigned long UTF32; /* at least 32 bits */
+typedef unsigned short UTF16; /* at least 16 bits */
+typedef unsigned char UTF8; /* typically 8 bits */
+typedef unsigned char Boolean; /* 0 or 1 */
+
+/* Some fundamental constants */
+#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
+#define UNI_MAX_BMP (UTF32)0x0000FFFF
+#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
+#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
+#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
+
+typedef enum {
+ conversionOK, /* conversion successful */
+ sourceExhausted, /* partial character in source, but hit end */
+ targetExhausted, /* insuff. room in target for conversion */
+ sourceIllegal /* source sequence is illegal/malformed */
+} ConversionResult;
+
+typedef enum {
+ strictConversion = 0,
+ lenientConversion
+} ConversionFlags;
+
+/* This is for C++ and does no harm in C */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ConversionResult ConvertUTF8toUTF16 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF16toUTF8 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF8toUTF32 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF32toUTF8 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF16toUTF32 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF32toUTF16 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* --------------------------------------------------------------------- */
diff --git a/support/win32/Makefile.am b/support/win32/Makefile.am
new file mode 100644
index 00000000..0b71ae19
--- /dev/null
+++ b/support/win32/Makefile.am
@@ -0,0 +1,4 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=support_win32
+noinst_LTLIBRARIES = libsupport_win32.la
+libsupport_win32_la_SOURCES = mmap.c win32_init.c sys/mman.h ConvertUTF.c ConvertUTF.h
diff --git a/support/win32/mmap.c b/support/win32/mmap.c
new file mode 100644
index 00000000..008ffa66
--- /dev/null
+++ b/support/win32/mmap.c
@@ -0,0 +1,43 @@
+#include <windows.h>
+#include "sys/mman.h"
+
+void * mmap_readonly_win32( const char* name, long* map_handle_ptr, long* map_file_ptr )
+{
+ void * mapped_ptr = NULL;
+#if defined(__CEGCC__)
+
+ wchar_t filename[MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, strlen(name), 0, 0)];
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, strlen(name), filename, wcslen(filename)) ;
+
+ HANDLE hFile = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
+#else
+ HANDLE hFile = CreateFile (name, GENERIC_READ, FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
+#endif
+ *map_file_ptr = (long)hFile;
+ *map_handle_ptr = 0;
+
+ if ( hFile != HFILE_ERROR )
+ {
+ HANDLE hMapping = CreateFileMapping( (HANDLE)hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ mapped_ptr = MapViewOfFile(hMapping, FILE_MAP_READ, 0 , 0, 0 );
+ *map_handle_ptr = (long)hMapping;
+ }
+
+ return mapped_ptr;
+}
+
+void mmap_unmap_win32( void* mem_ptr, long map_handle, long map_file )
+{
+ if ( mem_ptr != NULL )
+ {
+ UnmapViewOfFile( mem_ptr );
+ }
+ if ( map_handle != 0)
+ {
+ CloseHandle( (HANDLE)map_handle );
+ }
+ if ( map_file != 0 )
+ {
+ CloseHandle( (HANDLE)map_file );
+ }
+}
diff --git a/support/win32/sys/mman.h b/support/win32/sys/mman.h
new file mode 100644
index 00000000..37e59b9e
--- /dev/null
+++ b/support/win32/sys/mman.h
@@ -0,0 +1,8 @@
+#ifndef _WIN32_MMAN_H_INCLUDED
+#define _WIN32_MMAN_H_INCLUDED
+
+void * mmap_readonly_win32( const char* name, long* map_handle_ptr, long* map_file_ptr );
+void mmap_unmap_win32( void* mem_ptr, long map_handle, long map_file );
+
+#endif /* !_WIN32_MMAN_H_INCLUDED */
+
diff --git a/support/win32/win32_init.c b/support/win32/win32_init.c
new file mode 100644
index 00000000..32be387d
--- /dev/null
+++ b/support/win32/win32_init.c
@@ -0,0 +1,6 @@
+#include "plugin.h"
+
+void
+plugin_init(void)
+{
+}
diff --git a/support/wordexp/Makefile.am b/support/wordexp/Makefile.am
new file mode 100644
index 00000000..44d5ad27
--- /dev/null
+++ b/support/wordexp/Makefile.am
@@ -0,0 +1,4 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=support_wordexp
+noinst_LTLIBRARIES = libsupport_wordexp.la
+libsupport_wordexp_la_SOURCES = wordexp.c wordexp_init.c wordexp.h glob.c glob.h
diff --git a/support/wordexp/glob.c b/support/wordexp/glob.c
new file mode 100644
index 00000000..3bb70de1
--- /dev/null
+++ b/support/wordexp/glob.c
@@ -0,0 +1,108 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * @file glob.c
+ */
+
+#include <config.h>
+
+#ifndef HAVE_GLOB
+#if defined _WIN32 || defined _WIN32_WCE
+#include <windows.h>
+#include "glob.h"
+
+/*
+ * @brief searches for all the pathnames matching pattern according to the rules
+ * which is similar to the rules used by common shells.
+ * here: expanding of ´*´ and ´?´ only in filenames
+ * @param pattern: no tilde expansion or parameter substitution is done.
+ * @param flags: not supported here
+ * @param errfunc: not supported here
+ * @param pglob: struct with array containing the matched files/directories
+ * @return FALSE on error.
+ */
+int glob(const char *pattern, int flags,
+ int (*errfunc)(const char *epath, int eerrno),
+ glob_t *pglob)
+{
+ char *pathend,
+ *filename;
+ int pathlen;
+ HANDLE hFiles;
+#ifndef UNICODE
+ WIN32_FIND_DATA xFindData;
+ hFiles = FindFirstFile (pattern, &xFindData);
+#else
+ int len = strlen(pattern) * sizeof(wchar_t*);
+ wchar_t *pathname = malloc(len);
+ WIN32_FIND_DATAW xFindData;
+ mbstowcs (pathname, pattern, len);
+ hFiles = FindFirstFile (pathname, &xFindData);
+#endif
+
+ if(hFiles == INVALID_HANDLE_VALUE)
+ {
+ return 1;
+ }
+ /* store the path information */
+ if (NULL == (pathend = strrchr (pattern, '\\'))) /* windows */
+ if (NULL == (pathend = strrchr (pattern, '/'))) /* UNIX in windows is sometimes allowed also*/
+ pathend = (char *) pattern;
+ pathlen = pathend - pattern + 1;
+
+ /* glob */
+ pglob->gl_pathc = 0; /* number of founded files */
+ pglob->gl_offs = 0; /* not needed */
+ pglob->gl_pathv = malloc(sizeof(char*));
+
+ do
+ {
+ pglob->gl_pathc++;
+ pglob->gl_pathv = realloc (pglob->gl_pathv, pglob->gl_pathc * sizeof(char*));
+#ifndef UNICODE
+ filename = xFindData.cFileName;
+#else
+ len = wcslen(xFindData.cFileName) * sizeof(char*);
+ filename = malloc (len);
+ wcstombs (filename, xFindData.cFileName, len);
+#endif
+ pglob->gl_pathv[pglob->gl_pathc - 1] = malloc ((pathlen + strlen (filename) + 1) * sizeof(char*));
+ strncpy (pglob->gl_pathv[pglob->gl_pathc - 1], pattern, pathlen);
+ strcpy (pglob->gl_pathv[pglob->gl_pathc - 1] + pathlen, filename);
+ } while (FindNextFile (hFiles, &xFindData));
+
+ FindClose(hFiles);
+ return 0;
+}
+
+void globfree(glob_t *pglob)
+{
+ int i;
+
+ for (i=0; i < pglob->gl_pathc; i++)
+ {
+ free (pglob->gl_pathv[i]);
+ }
+ free (pglob->gl_pathv);
+ pglob->gl_pathc = 0;
+}
+
+#endif /* _WIN32 || _WIN32_WCE */
+#endif /* HAVE_GLOB */
diff --git a/support/wordexp/glob.h b/support/wordexp/glob.h
new file mode 100644
index 00000000..052b76f4
--- /dev/null
+++ b/support/wordexp/glob.h
@@ -0,0 +1,19 @@
+#ifndef _GLOB_H_
+#define _GLOB_H_
+
+#ifndef HAVE_GLOB
+#ifdef __MINGW32__
+
+typedef struct {
+ size_t gl_pathc;
+ char **gl_pathv;
+ size_t gl_offs;
+} glob_t;
+
+int glob(const char *pattern, int flags, int (*errfunc)(const char *epath, int eerrno), glob_t *pglob);
+void globfree(glob_t *pglob);
+
+#endif
+#endif
+
+#endif /* _GLOB_H_ */
diff --git a/support/wordexp/wordexp.c b/support/wordexp/wordexp.c
new file mode 100644
index 00000000..d4ad44a9
--- /dev/null
+++ b/support/wordexp/wordexp.c
@@ -0,0 +1,134 @@
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "wordexp.h"
+#include "glob.h"
+
+
+static int
+is_valid_variable_char(char c, int pos)
+{
+ if ( (pos && c >= '0' && c <= '9') ||
+ c == '_' ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z'))
+ return 1;
+ return 0;
+}
+
+/*
+ * @brief replace all names of $NAME ${NAME}
+ * with the corresponding environment variable
+ * @ param in: the string to be checked
+ * @ return the expanded string or a copy of the existing string
+ * must be free() by the calling function
+*/
+static char *
+expand_variables(const char *in)
+{
+ char *var,*pos,*ret=strdup(in);
+ char *val,*str;
+ pos=ret;
+ while ((var=strchr(pos, '$'))) {
+ char *name,*begin=var+1;
+ int npos=0,bpos=0,slen,elen;
+ *var='\0';
+ if (var[1] == '{') {
+ begin++;
+ while (begin[npos]) {
+ bpos=npos;
+ if (begin[npos++] == '}')
+ break;
+ }
+ } else {
+ while (is_valid_variable_char(begin[npos],npos))
+ npos++;
+ bpos=npos;
+ }
+ name=strdup(begin);
+ name[bpos]='\0';
+ val=getenv(name);
+ free(name);
+ if (! val)
+ val="";
+ slen=strlen(ret)+strlen(val);
+ elen=strlen(begin+npos);
+ str=malloc(slen+elen+1);
+ strcpy(str,ret);
+ strcat(str,val);
+ strcat(str,begin+npos);
+ free(ret);
+ ret=str;
+ pos=ret+slen;
+ }
+ return ret;
+}
+
+/*
+ * @brief minimal realization of wordexp according to IEEE standard
+ * shall perform word expansion as described in the Shell
+ * expansion of ´$NAME´ or ´${NAME}´
+ * expansion of ´*´ and ´?´
+ * @param words: pointer to a string containing one or more words to be expanded
+ * but here only one word supported
+ */
+int
+wordexp(const char *words, wordexp_t *we, int flags)
+{
+ int i;
+ int error;
+ char *words_expanded;
+ glob_t pglob;
+
+ assert(we != NULL);
+ assert(words != NULL);
+
+ /* expansion of ´$NAME´ or ´${NAME}´ */
+ words_expanded=expand_variables(words);
+
+ /* expansion of ´*´, ´?´ */
+ error=glob(words_expanded, 0, NULL, &pglob);
+ if (!error)
+ {
+ /* copy the content of struct of glob into struct of wordexp */
+ we->we_wordc = pglob.gl_pathc;
+ we->we_offs = pglob.gl_offs;
+ we->we_wordv = malloc(we->we_wordc * sizeof(char*));
+ for (i=0; i<we->we_wordc; i++)
+ {
+ we->we_wordv[i] = strdup(pglob.gl_pathv[i]);
+ }
+ globfree(&pglob);
+ free(words_expanded);
+ }
+ else
+ {
+ we->we_wordc = 1;
+ we->we_wordv = malloc(sizeof(char*));
+ we->we_wordv[0] = words_expanded;
+ }
+
+
+ return error;
+}
+
+
+void wordfree(wordexp_t *we)
+{
+ int i;
+
+ for (i=0; i < we->we_wordc; i++)
+ {
+ free (we->we_wordv[i]);
+ }
+
+ free (we->we_wordv);
+ we->we_wordc = 0;
+}
diff --git a/support/wordexp/wordexp.h b/support/wordexp/wordexp.h
new file mode 100644
index 00000000..ad18c785
--- /dev/null
+++ b/support/wordexp/wordexp.h
@@ -0,0 +1,42 @@
+#ifndef _WORDEXP_H_
+#define _WORDEXP_H_
+
+
+typedef struct {
+ size_t we_wordc; /* count of words matched */
+ char **we_wordv; /* pointer to list of words */
+ size_t we_offs; /* slots to reserve in we_wordv */
+ /* following are internals */
+ char *we_strings; /* storage for wordv strings */
+ size_t we_nbytes; /* size of we_strings */
+} wordexp_t;
+
+/*
+ * Flags for wordexp().
+ */
+#define WRDE_APPEND 0x1 /* append to previously generated */
+#define WRDE_DOOFFS 0x2 /* we_offs member is valid */
+#define WRDE_NOCMD 0x4 /* disallow command substitution */
+#define WRDE_REUSE 0x8 /* reuse wordexp_t */
+#define WRDE_SHOWERR 0x10 /* don't redirect stderr to /dev/null */
+#define WRDE_UNDEF 0x20 /* disallow undefined shell vars */
+
+/*
+ * Return values from wordexp().
+ */
+#define WRDE_BADCHAR 1 /* unquoted special character */
+#define WRDE_BADVAL 2 /* undefined variable */
+#define WRDE_CMDSUB 3 /* command substitution not allowed */
+#define WRDE_NOSPACE 4 /* no memory for result */
+#if (_XOPEN_SOURCE - 0) >= 4 || defined(_NETBSD_SOURCE)
+#define WRDE_NOSYS 5 /* obsolete, reserved */
+#endif
+#define WRDE_SYNTAX 6 /* shell syntax error */
+#define WRDE_ERRNO 7 /* other errors see errno */
+
+void wordfree(wordexp_t *);
+int wordexp(const char * words, wordexp_t * we, int flags);
+
+
+#endif /* !_WORDEXP_H_ */
+
diff --git a/support/wordexp/wordexp_init.c b/support/wordexp/wordexp_init.c
new file mode 100644
index 00000000..32be387d
--- /dev/null
+++ b/support/wordexp/wordexp_init.c
@@ -0,0 +1,6 @@
+#include "plugin.h"
+
+void
+plugin_init(void)
+{
+}
diff --git a/support/zlib/Makefile.am b/support/zlib/Makefile.am
new file mode 100644
index 00000000..a49fe3ca
--- /dev/null
+++ b/support/zlib/Makefile.am
@@ -0,0 +1,4 @@
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/navit -DMODULE=support_zlib
+noinst_LTLIBRARIES = libsupport_zlib.la
+libsupport_zlib_la_SOURCES = adler32.c crc32.c crc32.h infback.c inffast.c inffast.h inffixed.h inflate.c inflate.h inftrees.c inftrees.h zconf.h zlib.h zutil.c zutil.h zlib_init.c
diff --git a/support/zlib/adler32.c b/support/zlib/adler32.c
new file mode 100644
index 00000000..007ba262
--- /dev/null
+++ b/support/zlib/adler32.c
@@ -0,0 +1,149 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD4(a) \
+ do { \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD4(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ rem = (unsigned)(len2 % BASE);
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 > BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
diff --git a/support/zlib/crc32.c b/support/zlib/crc32.c
new file mode 100644
index 00000000..f658a9ef
--- /dev/null
+++ b/support/zlib/crc32.c
@@ -0,0 +1,423 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# ifdef STDC /* need ANSI C limits.h to determine sizes */
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+# endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ unsigned long c;
+ int n, k;
+ unsigned long poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0UL;
+ for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ poly |= 1UL << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = REV(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = REV(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const unsigned long FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const unsigned long FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case */
+ if (len2 == 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320L; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
diff --git a/support/zlib/crc32.h b/support/zlib/crc32.h
new file mode 100644
index 00000000..8053b611
--- /dev/null
+++ b/support/zlib/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/support/zlib/infback.c b/support/zlib/infback.c
new file mode 100644
index 00000000..455dbc9e
--- /dev/null
+++ b/support/zlib/infback.c
@@ -0,0 +1,623 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ This code is largely copied from inflate.c. Normally either infback.o or
+ inflate.o would be linked into an application--not both. The interface
+ with inffast.c is retained so that optimized assembler-coded versions of
+ inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ windowBits is in the range 8..15, and window is a user-supplied
+ window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL ||
+ windowBits < 8 || windowBits > 15)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->dmax = 32768U;
+ state->wbits = windowBits;
+ state->wsize = 1U << windowBits;
+ state->window = window;
+ state->write = 0;
+ state->whave = 0;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = state->window; \
+ left = state->wsize; \
+ state->whave = left; \
+ if (out(out_desc, put, left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ state->mode = TYPE;
+ state->last = 0;
+ state->whave = 0;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = state->window;
+ left = state->wsize;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (state->mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (state->last) {
+ BYTEBITS();
+ state->mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (state->length != 0) {
+ copy = state->length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+
+ case LEN:
+ /* use inflate_fast() if we have enough input and output */
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ if (state->whave < state->wsize)
+ state->whave = state->wsize - left;
+ inflate_fast(strm, state->wsize);
+ LOAD();
+ break;
+ }
+
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+
+ /* process literal */
+ if (this.op == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ ROOM();
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+
+ /* get distance code */
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+
+ /* get distance extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ if (state->offset > state->wsize - (state->whave < state->wsize ?
+ left : 0)) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = state->wsize - state->offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - state->offset;
+ copy = left;
+ }
+ if (copy > state->length) copy = state->length;
+ state->length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (state->length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < state->wsize) {
+ if (out(out_desc, state->window, state->wsize - left))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
diff --git a/support/zlib/inffast.c b/support/zlib/inffast.c
new file mode 100644
index 00000000..bbee92ed
--- /dev/null
+++ b/support/zlib/inffast.c
@@ -0,0 +1,318 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *in; /* local strm->next_in */
+ unsigned char FAR *last; /* while in < last, enough input available */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code this; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ write = state->write;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ PUP(out) = (unsigned char)(this.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ from = window - OFF;
+ if (write == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (write < op) { /* wrap around window */
+ from += wsize + write - op;
+ op -= write;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (write < len) { /* some from start of window */
+ op = write;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += write - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ this = dcode[this.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ this = lcode[this.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and write == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/support/zlib/inffast.h b/support/zlib/inffast.h
new file mode 100644
index 00000000..1e88d2d9
--- /dev/null
+++ b/support/zlib/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/support/zlib/inffixed.h b/support/zlib/inffixed.h
new file mode 100644
index 00000000..75ed4b59
--- /dev/null
+++ b/support/zlib/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications. It
+ is part of the implementation of the compression library and
+ is subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/support/zlib/inflate.c b/support/zlib/inflate.c
new file mode 100644
index 00000000..792fdee8
--- /dev/null
+++ b/support/zlib/inflate.c
@@ -0,0 +1,1368 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ strm->adler = 1; /* to support ill-conceived Java test suite */
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->wsize = 0;
+ state->whave = 0;
+ state->write = 0;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ if (windowBits < 0) {
+ state->wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48) windowBits &= 15;
+#endif
+ }
+ if (windowBits < 8 || windowBits > 15) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ return Z_STREAM_ERROR;
+ }
+ state->wbits = (unsigned)windowBits;
+ state->window = Z_NULL;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+ state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+ struct inflate_state FAR *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->write = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->write = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->write;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, strm->next_out - copy, copy);
+ state->write = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->write += dist;
+ if (state->write == state->wsize) state->write = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ break;
+ }
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+ if ((int)(this.op) == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ state->mode = LIT;
+ break;
+ }
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ if (state->offset > state->whave + out - left) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->write) {
+ copy -= state->write;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->write - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ if (updatewindow(strm, out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ if (state->mode == DICT) {
+ id = adler32(0L, Z_NULL, 0);
+ id = adler32(id, dictionary, dictLength);
+ if (id != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window */
+ if (updatewindow(strm, strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ if (dictLength > state->wsize) {
+ zmemcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ zmemcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy(dest, source, sizeof(z_stream));
+ zmemcpy(copy, state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
diff --git a/support/zlib/inflate.h b/support/zlib/inflate.h
new file mode 100644
index 00000000..07bd3e78
--- /dev/null
+++ b/support/zlib/inflate.h
@@ -0,0 +1,115 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN, /* i: waiting for length/lit code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+ NAME -> COMMENT -> HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or CHECK
+ STORED -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
diff --git a/support/zlib/inftrees.c b/support/zlib/inftrees.c
new file mode 100644
index 00000000..8a9c13ff
--- /dev/null
+++ b/support/zlib/inftrees.c
@@ -0,0 +1,329 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)1;
+ this.val = (unsigned short)0;
+ *(*table)++ = this; /* make a table to force an error */
+ *(*table)++ = this;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked when a LENS table is being made
+ against the space in *table, ENOUGH, minus the maximum space needed by
+ the worst case distance code, MAXD. This should never happen, but the
+ sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+ This assumes that when type == LENS, bits == 9.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ this.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/support/zlib/inftrees.h b/support/zlib/inftrees.h
new file mode 100644
index 00000000..b1104c87
--- /dev/null
+++ b/support/zlib/inftrees.h
@@ -0,0 +1,55 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1444 code structures (852 for length/literals
+ and 592 for distances, the latter actually the result of an
+ exhaustive search). The true maximum is not known, but the value
+ below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/support/zlib/zconf.h b/support/zlib/zconf.h
new file mode 100644
index 00000000..03a9431c
--- /dev/null
+++ b/support/zlib/zconf.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define deflateBound z_deflateBound
+# define deflatePrime z_deflatePrime
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateCopy z_inflateCopy
+# define inflateReset z_inflateReset
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+# define zError z_zError
+
+# define alloc_func z_alloc_func
+# define free_func z_free_func
+# define in_func z_in_func
+# define out_func z_out_func
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(__OS400__)
+# define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+# ifdef FAR
+# undef FAR
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(deflateBound,"DEBND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(compressBound,"CMBND")
+# pragma map(inflate_table,"INTABL")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/support/zlib/zlib.h b/support/zlib/zlib.h
new file mode 100644
index 00000000..02281792
--- /dev/null
+++ b/support/zlib/zlib.h
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.3, July 18th, 2005
+
+ Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumualte before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ the value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+ Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+ if and when it gets to the next deflate block boundary. When decoding the
+ zlib or gzip format, this will cause inflate() to return immediately after
+ the header and before the first block. When doing a raw inflate, inflate()
+ will go ahead and process the first block, and will return when it gets to
+ the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64
+ if inflate() is currently decoding the last block in the deflate stream,
+ plus 128 if inflate() returned immediately after decoding an end-of-block
+ code or decoding the complete header up to just before the first byte of the
+ deflate stream. The end-of-block will not be indicated until all of the
+ uncompressed data from that block has been written to strm->next_out. The
+ number of unused bits may in general be greater than seven, except when
+ bit 7 of data_type is set, in which case the number of unused bits will be
+ less than eight.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster approach
+ may be used for the single inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically. Any information
+ contained in the gzip header is not retained, so applications that need that
+ information should instead use raw inflate, see inflateInit2() below, or
+ inflateBack() and perform their own processing of the gzip header and
+ trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may then
+ call inflateSync() to look for a good compression block if a partial recovery
+ of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero),
+ no header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+ Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+ parameter only affects the compression ratio but not the correctness of the
+ compressed output even if it is not set appropriately. Z_FIXED prevents the
+ use of dynamic Huffman codes, allowing for a simpler decoder for special
+ applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front. In addition, the
+ current implementation of deflate will use at most the window size minus
+ 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit()
+ or deflateInit2(). This would be used to allocate an output buffer
+ for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the
+ bits leftover from a previous deflate stream when appending to it. As such,
+ this function can only be used for raw deflate, and must be used before the
+ first deflate() call after a deflateInit2() or deflateReset(). bits must be
+ less than or equal to 16, and that many of the least significant bits of
+ value will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is
+ a crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+ is set to null if there is no error message. inflateInit2 does not perform
+ any decompression apart from reading the zlib header if present: this will
+ be done by inflate(). (So next_in and avail_in may be modified, but next_out
+ and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK can be used to
+ force inflate() to return immediately after header processing is complete
+ and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When
+ any of extra, name, or comment are not Z_NULL and the respective field is
+ not present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+ be allocated, or Z_VERSION_ERROR if the version of the library does not
+ match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free
+ the allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects
+ only the raw deflate stream to decompress. This is different from the
+ normal behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format
+ error in the deflate stream (in which case strm->msg is set to indicate the
+ nature of the error), or Z_STREAM_ERROR if the stream was not properly
+ initialized. In the case of Z_BUF_ERROR, an input or output error can be
+ distinguished using strm->next_in which will be Z_NULL only if in() returned
+ an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+ out() returning non-zero. (in() will always be called before out(), so
+ strm->next_in is assured to be defined if out() returns non-zero.) Note
+ that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least the value returned
+ by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before
+ a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h", or 'R' for run-length encoding
+ as in "wb1R". (See the description of deflateInit2 for more information
+ about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error). The number of
+ uncompressed bytes written is limited to 4095. The caller should assure that
+ this limit is not exceeded. If it is exceeded, then gzprintf() will return
+ return an error (0) with nothing written. In this case, there may also be a
+ buffer overflow with unpredictable consequences, which is possible only if
+ zlib was compiled with the insecure functions sprintf() or vsprintf()
+ because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read again later.
+ Only one character of push-back is allowed. gzungetc() returns the
+ character pushed, or -1 on failure. gzungetc() will fail if a
+ character has been pushed but not read yet, or if c is -1. The pushed
+ character will be discarded if the stream is repositioned with gzseek()
+ or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns 1 if file is being read directly without decompression, otherwise
+ zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+/*
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is NULL, this function returns the required initial
+ value for the for the crc. Pre- and post-conditioning (one's complement) is
+ performed within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/support/zlib/zlib_init.c b/support/zlib/zlib_init.c
new file mode 100644
index 00000000..32be387d
--- /dev/null
+++ b/support/zlib/zlib_init.c
@@ -0,0 +1,6 @@
+#include "plugin.h"
+
+void
+plugin_init(void)
+{
+}
diff --git a/support/zlib/zutil.c b/support/zlib/zutil.c
new file mode 100644
index 00000000..d55f5948
--- /dev/null
+++ b/support/zlib/zutil.c
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch (sizeof(uInt)) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch (sizeof(uLong)) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch (sizeof(voidpf)) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch (sizeof(z_off_t)) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#ifdef STDC
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/support/zlib/zutil.h b/support/zlib/zutil.h
new file mode 100644
index 00000000..6cca50b9
--- /dev/null
+++ b/support/zlib/zutil.h
@@ -0,0 +1,269 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+# ifndef _WIN32_WCE
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+# ifdef _WIN32_WCE
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used. We rename it to
+ * avoid conflict with other libraries that use the same workaround.
+ */
+# define errno z_errno
+# endif
+ extern int errno;
+#else
+# ifndef _WIN32_WCE
+# include <errno.h>
+# endif
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# ifdef M_I86
+ #include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600)) || defined(__MINGW32__)
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+ /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+ /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+#endif
+#ifdef VMS
+# define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */