Gitweb links:

...log 
http://git.netsurf-browser.org/netsurf.git/shortlog/0569fbf1709fcd7101586c9de5fb17686394a827
...commit 
http://git.netsurf-browser.org/netsurf.git/commit/0569fbf1709fcd7101586c9de5fb17686394a827
...tree 
http://git.netsurf-browser.org/netsurf.git/tree/0569fbf1709fcd7101586c9de5fb17686394a827

The branch, master has been updated
       via  0569fbf1709fcd7101586c9de5fb17686394a827 (commit)
       via  2c7d24c5bc8b99738c25fce68c5b3e485530b5cc (commit)
       via  43582c50552021bbced0ea11f0ff6c4b2b618529 (commit)
       via  d196ea7795ada760dbc243fe640769eb9bc65dff (commit)
       via  b94b96e272140f17a82ce0847e1634d081b5dc6c (commit)
       via  cfa5856eea7c0d840a19590baf1e66f6fee06b83 (commit)
      from  a8bf9b05aa94392b391d6015ed037e5c241ab172 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=0569fbf1709fcd7101586c9de5fb17686394a827
commit 0569fbf1709fcd7101586c9de5fb17686394a827
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>

    change tab next and back accelerators
    
    fixes bug #2581

diff --git a/frontends/gtk/res/accelerators b/frontends/gtk/res/accelerators
index e4140fc..2da229a 100644
--- a/frontends/gtk/res/accelerators
+++ b/frontends/gtk/res/accelerators
@@ -5,8 +5,8 @@
 # The key names are the same as those in the gdk/gdkkeysyms.h header file
 #   but without the leading “GDK_KEY_”.
 
-gtkNextTab:<Control>Right
-gtkPrevTab:<Control>Left
+gtkNextTab:<Control>Page_Down
+gtkPrevTab:<Control>Page_Up
 gtkCloseTab:<Control>w
 gtkNewTab:<Control>t
 gtkNewWindow:<Control>n


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=2c7d24c5bc8b99738c25fce68c5b3e485530b5cc
commit 2c7d24c5bc8b99738c25fce68c5b3e485530b5cc
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>

    ensure stdint is included where required

diff --git a/frontends/beos/filetype.cpp b/frontends/beos/filetype.cpp
index 7a2ca97..bc988a8 100644
--- a/frontends/beos/filetype.cpp
+++ b/frontends/beos/filetype.cpp
@@ -18,6 +18,7 @@
 
 #define __STDBOOL_H__  1
 #include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
diff --git a/frontends/monkey/filetype.c b/frontends/monkey/filetype.c
index 979796b..65c84f9 100644
--- a/frontends/monkey/filetype.c
+++ b/frontends/monkey/filetype.c
@@ -32,6 +32,7 @@
 
 #include <stdio.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <string.h>
 #include <strings.h>
 #include <stdlib.h>


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=43582c50552021bbced0ea11f0ff6c4b2b618529
commit 43582c50552021bbced0ea11f0ff6c4b2b618529
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>

    allow hash table add inline to be uncompressed

diff --git a/utils/hashtable.c b/utils/hashtable.c
index 0de6f83..4935d6b 100644
--- a/utils/hashtable.c
+++ b/utils/hashtable.c
@@ -81,6 +81,175 @@ static inline unsigned int hash_string_fnv(const char 
*datum, unsigned int *len)
 }
 
 
+
+/**
+ * process a line of input.
+ *
+ * \param hash The hash table to add the line to
+ * \param ln The line to process
+ * \param lnlen The length of \ln
+ * \return NSERROR_OK on success else NSERROR_INVALID
+ */
+static nserror
+process_line(struct hash_table *hash, uint8_t *ln, int lnlen)
+{
+       uint8_t *key;
+       uint8_t *value;
+       uint8_t *colon;
+
+       key = ln; /* set key to start of line */
+       value = ln + lnlen; /* set value to end of line */
+
+       /* skip leading whitespace */
+       while ((key < value) &&
+              ((*key == ' ') || (*key == '\t'))) {
+               key++;
+       }
+
+       /* empty or comment lines */
+       if ((*key == 0) || (*key == '#')) {
+               return NSERROR_OK;
+       }
+
+       /* find first colon as key/value separator */
+       for (colon = key; colon < value; colon++) {
+               if (*colon == ':') {
+                       break;
+               }
+       }
+       if (colon == value) {
+               /* no colon found */
+               return NSERROR_INVALID;
+       }
+
+       *colon = 0;  /* terminate key */
+       value = colon + 1;
+
+       if (hash_add(hash, (char *)key, (char *)value) == false) {
+               NSLOG(netsurf, INFO,
+                     "Unable to add %s:%s to hash table", ln, value);
+               return NSERROR_INVALID;
+       }
+       return NSERROR_OK;
+}
+
+
+/**
+ * adds key/value pairs to a hash from a memory area
+ */
+static nserror
+hash_add_inline_plain(struct hash_table *ht, const uint8_t *data, size_t size)
+{
+       uint8_t s[LINE_BUFFER_SIZE]; /* line buffer */
+       unsigned int slen = 0;
+       nserror res = NSERROR_OK;
+
+       while (size > 0) {
+               s[slen] = *data;
+
+               if (s[slen] == '\n') {
+                       s[slen] = 0; /* replace newline with null termination */
+                       res = process_line(ht, s, slen);
+                       slen = 0;
+                       if (res != NSERROR_OK) {
+                               break;
+                       }
+               } else {
+                       slen++;
+                       if (slen > sizeof s) {
+                               NSLOG(netsurf, INFO, "Overlength line\n");
+                               slen = 0;
+                       }
+               }
+
+               size--;
+               data++;
+       }
+       if (slen > 0) {
+               s[slen] = 0;
+               res = process_line(ht, s, slen);
+       }
+
+       return res;
+}
+
+/**
+ * adds key/value pairs to a hash from a compressed memory area
+ */
+static nserror
+hash_add_inline_gzip(struct hash_table *ht, const uint8_t *data, size_t size)
+{
+       nserror res;
+       int ret; /* zlib return value */
+       z_stream strm;
+       uint8_t s[LINE_BUFFER_SIZE]; /* line buffer */
+       size_t used = 0; /* number of bytes in buffer in use */
+       uint8_t *nl;
+
+       strm.zalloc = Z_NULL;
+       strm.zfree = Z_NULL;
+       strm.opaque = Z_NULL;
+
+       strm.next_in = (uint8_t *)data;
+       strm.avail_in = size;
+
+       ret = inflateInit2(&strm, 32 + MAX_WBITS);
+       if (ret != Z_OK) {
+               NSLOG(netsurf, INFO, "inflateInit returned %d", ret);
+               return NSERROR_INVALID;
+       }
+
+       do {
+               strm.next_out = s + used;
+               strm.avail_out = sizeof(s) - used;
+
+               ret = inflate(&strm, Z_NO_FLUSH);
+               if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
+                       break;
+               }
+
+               used = sizeof(s) - strm.avail_out;
+               while (used > 0) {
+                       /* find nl */
+                       for (nl = &s[0]; nl < &s[used]; nl++) {
+                               if (*nl == '\n') {
+                                       break;
+                               }
+                       }
+                       if (nl == &s[used]) {
+                               /* no nl found */
+                               break;
+                       }
+                       /* found newline */
+                       *nl = 0; /* null terminate line */
+                       res = process_line(ht, &s[0], nl - &s[0]);
+                       if (res != NSERROR_OK) {
+                               inflateEnd(&strm);
+                               return res;
+                       }
+
+                       /* move data down */
+                       memmove(&s[0], nl + 1, used - ((nl + 1) - &s[0]) );
+                       used -= ((nl +1) - &s[0]);
+               }
+               if (used == sizeof(s)) {
+                       /* entire buffer used and no newline */
+                       NSLOG(netsurf, INFO, "Overlength line");
+                       used = 0;
+               }
+       } while (ret != Z_STREAM_END);
+
+       inflateEnd(&strm);
+
+       if (ret != Z_STREAM_END) {
+               NSLOG(netsurf, INFO, "inflate returned %d", ret);
+               return NSERROR_INVALID;
+       }
+       return NSERROR_OK;
+
+}
+
+
 /* exported interface documented in utils/hashtable.h */
 struct hash_table *hash_create(unsigned int chains)
 {
@@ -187,57 +356,6 @@ const char *hash_get(struct hash_table *ht, const char 
*key)
 }
 
 
-/**
- * process a line of input.
- *
- * \param hash The hash table to add the line to
- * \param ln The line to process
- * \param lnlen The length of \ln
- * \return NSERROR_OK on success else NSERROR_INVALID
- */
-static nserror
-process_line(struct hash_table *hash, uint8_t *ln, int lnlen)
-{
-       uint8_t *key;
-       uint8_t *value;
-       uint8_t *colon;
-
-       key = ln; /* set key to start of line */
-       value = ln + lnlen; /* set value to end of line */
-
-       /* skip leading whitespace */
-       while ((key < value) &&
-              ((*key == ' ') || (*key == '\t'))) {
-               key++;
-       }
-
-       /* empty or comment lines */
-       if ((*key == 0) || (*key == '#')) {
-               return NSERROR_OK;
-       }
-       
-       /* find first colon as key/value separator */
-       for (colon = key; colon < value; colon++) {
-               if (*colon == ':') {
-                       break;
-               }
-       }
-       if (colon == value) {
-               /* no colon found */
-               return NSERROR_INVALID;
-       }
-
-       *colon = 0;  /* terminate key */
-       value = colon + 1;
-
-       if (hash_add(hash, (char *)key, (char *)value) == false) {
-               NSLOG(netsurf, INFO,
-                     "Unable to add %s:%s to hash table", ln, value);
-               return NSERROR_INVALID;
-       }
-       return NSERROR_OK;
-}
-
 
 /* exported interface documented in utils/hashtable.h */
 nserror hash_add_file(struct hash_table *ht, const char *path)
@@ -262,7 +380,7 @@ nserror hash_add_file(struct hash_table *ht, const char 
*path)
        while (gzgets(fp, s, sizeof s)) {
                int slen = strlen(s);
                s[--slen] = 0;  /* remove \n at end */
-               
+
                res = process_line(ht, (uint8_t *)s, slen);
                if (res != NSERROR_OK) {
                        break;
@@ -274,75 +392,13 @@ nserror hash_add_file(struct hash_table *ht, const char 
*path)
        return res;
 }
 
+
 /* exported interface documented in utils/hashtable.h */
 nserror hash_add_inline(struct hash_table *ht, const uint8_t *data, size_t 
size)
 {
-       nserror res;
-       int ret; /* zlib return value */
-       z_stream strm;
-       uint8_t s[LINE_BUFFER_SIZE]; /* line buffer */
-       size_t used = 0; /* number of bytes in buffer in use */
-       uint8_t *nl;
-
-       strm.zalloc = Z_NULL;
-       strm.zfree = Z_NULL;
-       strm.opaque = Z_NULL;
-
-       strm.next_in = (uint8_t *)data;
-       strm.avail_in = size;
-
-       ret = inflateInit2(&strm, 32 + MAX_WBITS);
-       if (ret != Z_OK) {
-               NSLOG(netsurf, INFO, "inflateInit returned %d", ret);
-               return NSERROR_INVALID;
-       }
-
-       do {
-               strm.next_out = s + used;
-               strm.avail_out = sizeof(s) - used;
-
-               ret = inflate(&strm, Z_NO_FLUSH);
-               if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
-                       break;
-               }
-
-               used = sizeof(s) - strm.avail_out;
-               while (used > 0) {
-                       /* find nl */
-                       for (nl = &s[0]; nl < &s[used]; nl++) {
-                               if (*nl == '\n') {
-                                       break;
-                               }
-                       }
-                       if (nl == &s[used]) {
-                               /* no nl found */
-                               break;
-                       }
-                       /* found newline */
-                       *nl = 0; /* null terminate line */
-                       res = process_line(ht, &s[0], nl - &s[0]);
-                       if (res != NSERROR_OK) {
-                               inflateEnd(&strm);
-                               return res;
-                       }
-
-                       /* move data down */
-                       memmove(&s[0], nl + 1, used - ((nl + 1) - &s[0]) );
-                       used -= ((nl +1) - &s[0]);
-               }
-               if (used == sizeof(s)) {
-                       /* entire buffer used and no newline */
-                       NSLOG(netsurf, INFO, "Overlength line");
-                       used = 0;
-               }
-       } while (ret != Z_STREAM_END);
-
-       inflateEnd(&strm);
-
-       if (ret != Z_STREAM_END) {
-               NSLOG(netsurf, INFO, "inflate returned %d", ret);
-               return NSERROR_INVALID;
+       if ((data[0]==0x1f) && (data[1] == 0x8b)) {
+               /* gzip header detected */
+               return hash_add_inline_gzip(ht, data, size);
        }
-       return NSERROR_OK;
-
+       return hash_add_inline_plain(ht, data, size);
 }


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=d196ea7795ada760dbc243fe640769eb9bc65dff
commit d196ea7795ada760dbc243fe640769eb9bc65dff
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>

    fix gtk accelerator loading

diff --git a/frontends/gtk/accelerator.c b/frontends/gtk/accelerator.c
index 9339de8..11b7fb1 100644
--- a/frontends/gtk/accelerator.c
+++ b/frontends/gtk/accelerator.c
@@ -25,36 +25,55 @@
 #include <stdint.h>
 #include <gtk/gtk.h>
 
+#include "utils/log.h"
 #include "utils/errors.h"
 #include "utils/hashtable.h"
 
 #include "gtk/resources.h"
 #include "gtk/accelerator.h"
 
+/** acclelerators are stored in a fixed-size hash table. */
+#define HASH_SIZE 53
+
 /** The hash table used to store the accelerators */
 static struct hash_table *accelerators_hash = NULL;
 
 nserror nsgtk_accelerator_init(char **respaths)
 {
-       nserror ret;
+       nserror res;
        const uint8_t *data;
        size_t data_size;
 
-       ret = nsgtk_data_from_resname("accelerators", &data, &data_size);
-       if (ret == NSERROR_OK) {
-               //ret = hashtable_add_from_inline(data, data_size);
+       if (accelerators_hash == NULL) {
+               accelerators_hash = hash_create(HASH_SIZE);
+       }
+       if (accelerators_hash == NULL) {
+               NSLOG(netsurf, INFO, "Unable to create hash table");
+               return NSERROR_NOMEM;
+       }
+
+       res = nsgtk_data_from_resname("accelerators", &data, &data_size);
+       if (res == NSERROR_OK) {
+               res = hash_add_inline(accelerators_hash, data, data_size);
        } else {
-               const char *accelerators;
+               const char *accelerators_path;
                /* Obtain path to accelerators */
-               ret = nsgtk_path_from_resname("accelerators", &accelerators);
-               if (ret == NSERROR_OK) {
-                       //ret = hashtable_add_from_file(messages);
+               res = nsgtk_path_from_resname("accelerators",
+                                             &accelerators_path);
+               if (res == NSERROR_OK) {
+                       res = hash_add_file(accelerators_hash,
+                                           accelerators_path);
                }
        }
-       return ret;
+
+       return res;
 }
 
 const char *nsgtk_accelerator_get_desc(const char *key)
 {
-       return NULL;
+       if ((key == NULL) ||
+           (accelerators_hash == NULL)) {
+               return NULL;
+       }
+       return hash_get(accelerators_hash, key);
 }
diff --git a/frontends/gtk/fetch.c b/frontends/gtk/fetch.c
index 7286aec..b05c1bd 100644
--- a/frontends/gtk/fetch.c
+++ b/frontends/gtk/fetch.c
@@ -30,6 +30,7 @@
  * ASCII hence not using locale dependant ctype functions for parsing.
  */
 
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -39,8 +40,8 @@
 #include <strings.h>
 #include <gtk/gtk.h>
 
-#include "utils/hashtable.h"
 #include "utils/log.h"
+#include "utils/hashtable.h"
 #include "utils/filepath.h"
 #include "utils/file.h"
 #include "utils/nsurl.h"


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=b94b96e272140f17a82ce0847e1634d081b5dc6c
commit b94b96e272140f17a82ce0847e1634d081b5dc6c
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>

    add hash table population from file or memory

diff --git a/utils/hashtable.c b/utils/hashtable.c
index 3a1711d..0de6f83 100644
--- a/utils/hashtable.c
+++ b/utils/hashtable.c
@@ -28,11 +28,15 @@
  * it that has good coverage along side the other tests.
  */
 
+#include <stdint.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdbool.h>
-#include "utils/hashtable.h"
+#include <zlib.h>
+#include <errno.h>
+
 #include "utils/log.h"
+#include "utils/hashtable.h"
 
 
 struct hash_entry {
@@ -46,6 +50,8 @@ struct hash_table {
        struct hash_entry **chain;
 };
 
+/** maximum length of line for file or inline add */
+#define LINE_BUFFER_SIZE 512
 
 /**
  * Hash a string, returning a 32bit value.  The hash algorithm used is
@@ -179,3 +185,164 @@ const char *hash_get(struct hash_table *ht, const char 
*key)
 
        return NULL;
 }
+
+
+/**
+ * process a line of input.
+ *
+ * \param hash The hash table to add the line to
+ * \param ln The line to process
+ * \param lnlen The length of \ln
+ * \return NSERROR_OK on success else NSERROR_INVALID
+ */
+static nserror
+process_line(struct hash_table *hash, uint8_t *ln, int lnlen)
+{
+       uint8_t *key;
+       uint8_t *value;
+       uint8_t *colon;
+
+       key = ln; /* set key to start of line */
+       value = ln + lnlen; /* set value to end of line */
+
+       /* skip leading whitespace */
+       while ((key < value) &&
+              ((*key == ' ') || (*key == '\t'))) {
+               key++;
+       }
+
+       /* empty or comment lines */
+       if ((*key == 0) || (*key == '#')) {
+               return NSERROR_OK;
+       }
+       
+       /* find first colon as key/value separator */
+       for (colon = key; colon < value; colon++) {
+               if (*colon == ':') {
+                       break;
+               }
+       }
+       if (colon == value) {
+               /* no colon found */
+               return NSERROR_INVALID;
+       }
+
+       *colon = 0;  /* terminate key */
+       value = colon + 1;
+
+       if (hash_add(hash, (char *)key, (char *)value) == false) {
+               NSLOG(netsurf, INFO,
+                     "Unable to add %s:%s to hash table", ln, value);
+               return NSERROR_INVALID;
+       }
+       return NSERROR_OK;
+}
+
+
+/* exported interface documented in utils/hashtable.h */
+nserror hash_add_file(struct hash_table *ht, const char *path)
+{
+       nserror res = NSERROR_OK;
+       char s[LINE_BUFFER_SIZE]; /* line buffer */
+       gzFile fp; /* compressed file handle */
+
+       if (path == NULL) {
+               return NSERROR_BAD_PARAMETER;
+       }
+
+       fp = gzopen(path, "r");
+       if (!fp) {
+               NSLOG(netsurf, INFO,
+                     "Unable to open file \"%.100s\": %s", path,
+                     strerror(errno));
+
+               return NSERROR_NOT_FOUND;
+       }
+
+       while (gzgets(fp, s, sizeof s)) {
+               int slen = strlen(s);
+               s[--slen] = 0;  /* remove \n at end */
+               
+               res = process_line(ht, (uint8_t *)s, slen);
+               if (res != NSERROR_OK) {
+                       break;
+               }
+       }
+
+       gzclose(fp);
+
+       return res;
+}
+
+/* exported interface documented in utils/hashtable.h */
+nserror hash_add_inline(struct hash_table *ht, const uint8_t *data, size_t 
size)
+{
+       nserror res;
+       int ret; /* zlib return value */
+       z_stream strm;
+       uint8_t s[LINE_BUFFER_SIZE]; /* line buffer */
+       size_t used = 0; /* number of bytes in buffer in use */
+       uint8_t *nl;
+
+       strm.zalloc = Z_NULL;
+       strm.zfree = Z_NULL;
+       strm.opaque = Z_NULL;
+
+       strm.next_in = (uint8_t *)data;
+       strm.avail_in = size;
+
+       ret = inflateInit2(&strm, 32 + MAX_WBITS);
+       if (ret != Z_OK) {
+               NSLOG(netsurf, INFO, "inflateInit returned %d", ret);
+               return NSERROR_INVALID;
+       }
+
+       do {
+               strm.next_out = s + used;
+               strm.avail_out = sizeof(s) - used;
+
+               ret = inflate(&strm, Z_NO_FLUSH);
+               if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
+                       break;
+               }
+
+               used = sizeof(s) - strm.avail_out;
+               while (used > 0) {
+                       /* find nl */
+                       for (nl = &s[0]; nl < &s[used]; nl++) {
+                               if (*nl == '\n') {
+                                       break;
+                               }
+                       }
+                       if (nl == &s[used]) {
+                               /* no nl found */
+                               break;
+                       }
+                       /* found newline */
+                       *nl = 0; /* null terminate line */
+                       res = process_line(ht, &s[0], nl - &s[0]);
+                       if (res != NSERROR_OK) {
+                               inflateEnd(&strm);
+                               return res;
+                       }
+
+                       /* move data down */
+                       memmove(&s[0], nl + 1, used - ((nl + 1) - &s[0]) );
+                       used -= ((nl +1) - &s[0]);
+               }
+               if (used == sizeof(s)) {
+                       /* entire buffer used and no newline */
+                       NSLOG(netsurf, INFO, "Overlength line");
+                       used = 0;
+               }
+       } while (ret != Z_STREAM_END);
+
+       inflateEnd(&strm);
+
+       if (ret != Z_STREAM_END) {
+               NSLOG(netsurf, INFO, "inflate returned %d", ret);
+               return NSERROR_INVALID;
+       }
+       return NSERROR_OK;
+
+}
diff --git a/utils/hashtable.h b/utils/hashtable.h
index b0e7392..b1c0d5c 100644
--- a/utils/hashtable.h
+++ b/utils/hashtable.h
@@ -29,8 +29,11 @@
 struct hash_table;
 
 /**
- * Create a new hash table, and return a context for it.  The memory 
consumption
- * of a hash table is approximately 8 + (nchains * 12) bytes if it is empty.
+ * Create a new hash table
+ *
+ * Allocate a new hash table and return a context for it.  The memory
+ * consumption of a hash table is approximately 8 + (nchains * 12)
+ * bytes if it is empty.
  *
  * \param chains Number of chains/buckets this hash table will have.  This
  *               should be a prime number, and ideally a prime number just
@@ -41,18 +44,22 @@ struct hash_table;
 struct hash_table *hash_create(unsigned int chains);
 
 /**
- * Destroys a hash table, freeing all memory associated with it.
+ * Destroys a hash table
+ *
+ * Destroy a hash table freeing all memory associated with it.
  *
  * \param ht Hash table to destroy. After the function returns, this
- *            will nolonger be valid.
+ *             will no longer be valid.
  */
 void hash_destroy(struct hash_table *ht);
 
 /**
- * Adds a key/value pair to a hash table.  If the key you're adding is already
- * in the hash table, it does not replace it, but it does take precedent over
- * it.  The old key/value pair will be inaccessable but still in memory until
- * hash_destroy() is called on the hash table.
+ * Adds a key/value pair to a hash table.
+ *
+ * If the key you're adding is already in the hash table, it does not
+ * replace it, but it does take precedent over it.  The old key/value
+ * pair will be inaccessable but still in memory until hash_destroy()
+ * is called on the hash table.
  *
  * \param  ht    The hash table context to add the key/value pair to.
  * \param  key   The key to associate the value with.  A copy is made.
@@ -71,4 +78,34 @@ bool hash_add(struct hash_table *ht, const char *key, const 
char *value);
  */
 const char *hash_get(struct hash_table *ht, const char *key);
 
+/**
+ * Add key/value pairs to a hash table with data from a file
+ *
+ * The file should be formatted as a series of lines terminated with
+ *  newline character. Each line should contain a key/value pair
+ *  separated by a colon. If a line is empty or starts with a #
+ *  character it will be ignored.
+ *
+ * The file may be optionally gzip compressed.
+ *
+ * \param ht The hash table context to add the key/value pairs to.
+ * \param path Path to file with key/value pairs in.
+ * \return NSERROR_OK on success else error code
+ */
+nserror hash_add_file(struct hash_table *ht, const char *path);
+
+/**
+ * Add key/value pairs to a hash table with data from a memory buffer
+ *
+ * The data format is the same as in hash_add_file() but held in memory
+ *
+ * The data may optionally be gzip compressed.
+ *
+ * \param ht The hash table context to add the key/value pairs to.
+ * \param data Source of key/value pairs
+ * \param size length of \a data
+ * \return NSERROR_OK on success else error code
+ */
+nserror hash_add_inline(struct hash_table *ht, const uint8_t *data, size_t 
size);
+
 #endif
diff --git a/utils/messages.c b/utils/messages.c
index e2d45e9..e1e6120 100644
--- a/utils/messages.c
+++ b/utils/messages.c
@@ -45,66 +45,19 @@
 /** The hash table used to store the standard Messages file for the old API */
 static struct hash_table *messages_hash = NULL;
 
-/**
- * process a line of input.
- */
-static nserror
-message_process_line(struct hash_table *hash, uint8_t *ln, int lnlen)
-{
-       uint8_t *value;
-       uint8_t *colon;
-
-       /* empty or comment lines */
-       if (ln[0] == 0 || ln[0] == '#') {
-               return NSERROR_OK;
-       }
-
-       /* find first colon as key/value separator */
-       for (colon = ln; colon < (ln + lnlen); colon++) {
-               if (*colon == ':') {
-                       break;
-               }
-       }
-       if (colon == (ln + lnlen)) {
-               /* no colon found */
-               return NSERROR_INVALID;
-       }
-
-       *colon = 0;  /* terminate key */
-       value = colon + 1;
-
-       if (hash_add(hash, (char *)ln, (char *)value) == false) {
-               NSLOG(netsurf, INFO, "Unable to add %s:%s to hash table", ln,
-                     value);
-               return NSERROR_INVALID;
-       }
-       return NSERROR_OK;
-}
 
 /**
  * Read keys and values from messages file.
  *
  * \param  path  pathname of messages file
- * \param  ctx   reference of hash table to merge with.
+ * \param  ctx   reference of hash table to merge with or NULL to create one.
  * \return NSERROR_OK on sucess and ctx updated or error code on faliure.
  */
 static nserror messages_load_ctx(const char *path, struct hash_table **ctx)
 {
-       char s[400]; /* line buffer */
-       gzFile fp; /* compressed file handle */
        struct hash_table *nctx; /* new context */
-
-       assert(path != NULL);
-
-       fp = gzopen(path, "r");
-       if (!fp) {
-               NSLOG(netsurf, INFO,
-                     "Unable to open messages file \"%.100s\": %s", path,
-                     strerror(errno));
-
-               return NSERROR_NOT_FOUND;
-       }
-
+       nserror res;
+       
        if (*ctx == NULL) {
                nctx = hash_create(HASH_SIZE);
        } else {
@@ -118,40 +71,16 @@ static nserror messages_load_ctx(const char *path, struct 
hash_table **ctx)
                NSLOG(netsurf, INFO,
                      "Unable to create hash table for messages file %s",
                      path);
-               gzclose(fp);
                return NSERROR_NOMEM;
        }
 
-       while (gzgets(fp, s, sizeof s)) {
-               char *colon, *value;
-
-               if (s[0] == 0 || s[0] == '#')
-                       continue;
-
-               s[strlen(s) - 1] = 0;  /* remove \n at end */
-               colon = strchr(s, ':');
-               if (!colon)
-                       continue;
-               *colon = 0;  /* terminate key */
-               value = colon + 1;
-
-               if (hash_add(nctx, s, value) == false) {
-                       NSLOG(netsurf, INFO,
-                             "Unable to add %s:%s to hash table of %s", s,
-                             value, path);
-                       gzclose(fp);
-                       if (*ctx == NULL) {
-                               hash_destroy(nctx);
-                       }
-                       return NSERROR_INVALID;
-               }
-       }
-
-       gzclose(fp);
 
-       *ctx = nctx;
+       res = hash_add_file(nctx, path);
+       if (res == NSERROR_OK) {
+               *ctx = nctx;
+       }
 
-       return NSERROR_OK;
+       return res;
 }
 
 
@@ -203,30 +132,19 @@ static void messages_destroy_ctx(struct hash_table *ctx)
 /* exported interface documented in messages.h */
 nserror messages_add_from_file(const char *path)
 {
-       nserror err;
-
        if (path == NULL) {
                return NSERROR_BAD_PARAMETER;
        }
 
        NSLOG(netsurf, INFO, "Loading Messages from '%s'", path);
 
-       err = messages_load_ctx(path, &messages_hash);
-
-
-       return err;
+       return messages_load_ctx(path, &messages_hash);
 }
 
 
 /* exported interface documented in messages.h */
-nserror messages_add_from_inline(const uint8_t *data, size_t data_size)
+nserror messages_add_from_inline(const uint8_t *data, size_t size)
 {
-       z_stream strm;
-       int ret;
-       uint8_t s[512]; /* line buffer */
-       size_t used = 0; /* number of bytes in buffer in use */
-       uint8_t *nl;
-
        /* ensure the hash table is initialised */
        if (messages_hash == NULL) {
                messages_hash = hash_create(HASH_SIZE);
@@ -235,61 +153,7 @@ nserror messages_add_from_inline(const uint8_t *data, 
size_t data_size)
                NSLOG(netsurf, INFO, "Unable to create hash table");
                return NSERROR_NOMEM;
        }
-
-       strm.zalloc = Z_NULL;
-       strm.zfree = Z_NULL;
-       strm.opaque = Z_NULL;
-
-       strm.next_in = (uint8_t *)data;
-       strm.avail_in = data_size;
-
-       ret = inflateInit2(&strm, 32 + MAX_WBITS);
-       if (ret != Z_OK) {
-               NSLOG(netsurf, INFO, "inflateInit returned %d", ret);
-               return NSERROR_INVALID;
-       }
-
-       do {
-               strm.next_out = s + used;
-               strm.avail_out = sizeof(s) - used;
-
-               ret = inflate(&strm, Z_NO_FLUSH);
-               if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
-                       break;
-               }
-
-               used = sizeof(s) - strm.avail_out;
-               while (used > 0) {
-                       /* find nl */
-                       for (nl = &s[0]; nl < &s[used]; nl++) {
-                               if (*nl == '\n') {
-                                       break;
-                               }
-                       }
-                       if (nl == &s[used]) {
-                               /* no nl found */
-                               break;
-                       }
-                       /* found newline */
-                       *nl = 0; /* null terminate line */
-                       message_process_line(messages_hash, &s[0], nl - &s[0]);
-                       memmove(&s[0], nl + 1, used - ((nl + 1) - &s[0]) );
-                       used -= ((nl +1) - &s[0]);
-               }
-               if (used == sizeof(s)) {
-                       /* entire buffer used and no newline */
-                       NSLOG(netsurf, INFO, "Overlength line");
-                       used = 0;
-               }
-       } while (ret != Z_STREAM_END);
-
-       inflateEnd(&strm);
-
-       if (ret != Z_STREAM_END) {
-               NSLOG(netsurf, INFO, "inflate returned %d", ret);
-               return NSERROR_INVALID;
-       }
-       return NSERROR_OK;
+       return hash_add_inline(messages_hash, data, size);
 }
 
 /* exported interface documented in messages.h */


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=cfa5856eea7c0d840a19590baf1e66f6fee06b83
commit cfa5856eea7c0d840a19590baf1e66f6fee06b83
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>

    Initial conversion of GTK accelerators to separate config file

diff --git a/frontends/gtk/Makefile b/frontends/gtk/Makefile
index 6c2f06f..ec60ce7 100644
--- a/frontends/gtk/Makefile
+++ b/frontends/gtk/Makefile
@@ -165,7 +165,7 @@ endif
 
 # S_FRONTEND are sources purely for the GTK frontend
 S_FRONTEND := gui.c schedule.c layout_pango.c bitmap.c plotters.c      \
-       scaffolding.c gdk.c completion.c login.c throbber.c             \
+       scaffolding.c gdk.c completion.c login.c throbber.c accelerator.c \
        selection.c window.c fetch.c download.c menu.c print.c          \
        search.c tabs.c toolbar.c gettext.c compat.c viewdata.c         \
        viewsource.c preferences.c about.c resources.c corewindow.c     \
diff --git a/frontends/gtk/accelerator.c b/frontends/gtk/accelerator.c
new file mode 100644
index 0000000..9339de8
--- /dev/null
+++ b/frontends/gtk/accelerator.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * GTK accelerator support
+ *
+ */
+
+#include <stdint.h>
+#include <gtk/gtk.h>
+
+#include "utils/errors.h"
+#include "utils/hashtable.h"
+
+#include "gtk/resources.h"
+#include "gtk/accelerator.h"
+
+/** The hash table used to store the accelerators */
+static struct hash_table *accelerators_hash = NULL;
+
+nserror nsgtk_accelerator_init(char **respaths)
+{
+       nserror ret;
+       const uint8_t *data;
+       size_t data_size;
+
+       ret = nsgtk_data_from_resname("accelerators", &data, &data_size);
+       if (ret == NSERROR_OK) {
+               //ret = hashtable_add_from_inline(data, data_size);
+       } else {
+               const char *accelerators;
+               /* Obtain path to accelerators */
+               ret = nsgtk_path_from_resname("accelerators", &accelerators);
+               if (ret == NSERROR_OK) {
+                       //ret = hashtable_add_from_file(messages);
+               }
+       }
+       return ret;
+}
+
+const char *nsgtk_accelerator_get_desc(const char *key)
+{
+       return NULL;
+}
diff --git a/frontends/gtk/accelerator.h b/frontends/gtk/accelerator.h
new file mode 100644
index 0000000..09c253e
--- /dev/null
+++ b/frontends/gtk/accelerator.h
@@ -0,0 +1,2 @@
+nserror nsgtk_accelerator_init(char **respaths);
+const char *nsgtk_accelerator_get_desc(const char *key);
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index 0f79a1b..3163be1 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -72,6 +72,7 @@
 #include "gtk/resources.h"
 #include "gtk/login.h"
 #include "gtk/layout_pango.h"
+#include "gtk/accelerator.h"
 
 bool nsgtk_complete = false;
 
@@ -227,7 +228,11 @@ static nserror set_defaults(struct nsoption_s *defaults)
 
 
 /**
- * Initialize GTK interface.
+ * Initialize GTK specific parts of the browser.
+ *
+ * \param argc The number of arguments on the command line
+ * \param argv A string vector of command line arguments.
+ * \respath A string vector of the path elements of resources 
  */
 static nserror nsgtk_init(int argc, char** argv, char **respath)
 {
@@ -235,20 +240,29 @@ static nserror nsgtk_init(int argc, char** argv, char 
**respath)
        char *resource_filename;
        char *addr = NULL;
        nsurl *url;
-       nserror error;
+       nserror res;
+
+       /* Initialise gtk accelerator table */
+       res = nsgtk_accelerator_init(respaths);
+       if (res != NSERROR_OK) {
+               NSLOG(netsurf, INFO,
+                     "Unable to load gtk accelerator configuration");
+               /* not fatal if this does not load */
+       }
 
-       error = nsgtk_builder_new_from_resname("warning", &warning_builder);
-       if (error != NSERROR_OK) {
+       /* initialise warning dialog */
+       res = nsgtk_builder_new_from_resname("warning", &warning_builder);
+       if (res != NSERROR_OK) {
                NSLOG(netsurf, INFO, "Unable to initialise warning dialog");
-               return error;
+               return res;
        }
 
        gtk_builder_connect_signals(warning_builder, NULL);
 
        /* set default icon if its available */
-       error = nsgdk_pixbuf_new_from_resname("netsurf.xpm",
-                                             &win_default_icon_pixbuf);
-       if (error == NSERROR_OK) {
+       res = nsgdk_pixbuf_new_from_resname("netsurf.xpm",
+                                           &win_default_icon_pixbuf);
+       if (res == NSERROR_OK) {
                NSLOG(netsurf, INFO, "Seting default window icon");
                gtk_window_set_default_icon(win_default_icon_pixbuf);
        }
@@ -263,25 +277,25 @@ static nserror nsgtk_init(int argc, char** argv, char 
**respath)
        }
 
        /* Default favicon */
-       error = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf);
-       if (error != NSERROR_OK) {
+       res = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf);
+       if (res != NSERROR_OK) {
                favicon_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
                                                false, 8, 16, 16);
        }
 
        /* arrow down icon */
-       error = nsgdk_pixbuf_new_from_resname("arrow_down_8x32.png",
-                                             &arrow_down_pixbuf);
-       if (error != NSERROR_OK) {
+       res = nsgdk_pixbuf_new_from_resname("arrow_down_8x32.png",
+                                           &arrow_down_pixbuf);
+       if (res != NSERROR_OK) {
                arrow_down_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
                                                   false, 8, 8, 32);
        }
 
        /* initialise throbber */
-       error = nsgtk_throbber_init();
-       if (error != NSERROR_OK) {
+       res = nsgtk_throbber_init();
+       if (res != NSERROR_OK) {
                NSLOG(netsurf, INFO, "Unable to initialise throbber.");
-               return error;
+               return res;
        }
 
        /* Initialise completions - cannot fail */
@@ -302,13 +316,13 @@ static nserror nsgtk_init(int argc, char** argv, char 
**respath)
        urldb_load(nsoption_charp(url_file));
        urldb_load_cookies(nsoption_charp(cookie_file));
        hotlist_init(nsoption_charp(hotlist_path),
-                       nsoption_charp(hotlist_path));
+                    nsoption_charp(hotlist_path));
 
        /* Initialise top level UI elements */
-       error = nsgtk_download_init();
-       if (error != NSERROR_OK) {
+       res = nsgtk_download_init();
+       if (res != NSERROR_OK) {
                NSLOG(netsurf, INFO, "Unable to initialise download window.");
-               return error;
+               return res;
        }
 
        /* If there is a url specified on the command line use it */
@@ -338,19 +352,19 @@ static nserror nsgtk_init(int argc, char** argv, char 
**respath)
        }
 
        /* create an initial browser window */
-       error = nsurl_create(addr, &url);
-       if (error == NSERROR_OK) {
-               error = browser_window_create(BW_CREATE_HISTORY,
-                                             url,
-                                             NULL,
-                                             NULL,
-                                             NULL);
+       res = nsurl_create(addr, &url);
+       if (res == NSERROR_OK) {
+               res = browser_window_create(BW_CREATE_HISTORY,
+                                           url,
+                                           NULL,
+                                           NULL,
+                                           NULL);
                nsurl_unref(url);
        }
 
        free(addr);
 
-       return error;
+       return res;
 }
 
 
@@ -1163,7 +1177,7 @@ int main(int argc, char** argv)
                NSLOG(netsurf, INFO, "Unable to load translated messages");
                /** \todo decide if message load faliure should be fatal */
        }
-
+       
        /* Locate the correct user cache directory path */
        ret = get_cache_home(&cache_home);
        if (ret == NSERROR_NOT_FOUND) {
@@ -1183,7 +1197,7 @@ int main(int argc, char** argv)
                return 1;
        }
 
-       /* run the browser */
+       /* gtk specific initalisation and main run loop */
        ret = nsgtk_init(argc, argv, respaths);
        if (ret != NSERROR_OK) {
                fprintf(stderr, "NetSurf gtk initialise failed (%s)\n",
diff --git a/frontends/gtk/menu.c b/frontends/gtk/menu.c
index a93ef93..6a60332 100644
--- a/frontends/gtk/menu.c
+++ b/frontends/gtk/menu.c
@@ -27,6 +27,7 @@
 #include "gtk/compat.h"
 #include "gtk/menu.h"
 #include "gtk/warn.h"
+#include "gtk/accelerator.h"
 
 /**
  * Adds image menu item to a menu.
@@ -34,28 +35,37 @@
  * \param menu the menu to add the item to
  * \param item_out a pointer to the item's location in the menu struct
  * \param message the menu item I18n lookup value
- * \param messageAccel the menu item accelerator I18n lookup value
  * \param group the 'global' in a gtk sense accelerator group
  * \return true if sucessful and \a item_out updated else false.
  */
 
-static bool nsgtk_menu_add_image_item(GtkMenu *menu,
-               GtkWidget **item_out, const char *message,
-               const char *messageAccel, GtkAccelGroup *group)
+static bool
+nsgtk_menu_add_image_item(GtkMenu *menu,
+                         GtkWidget **item_out,
+                         const char *message,
+                         GtkAccelGroup *group)
 {
        unsigned int key;
        GdkModifierType mod;
        GtkWidget *item;
-
+       const char *accelerator_desc; /* accelerator key description */
+       
        item = nsgtk_image_menu_item_new_with_mnemonic(messages_get(message));
        if (item == NULL) {
                return false;
        }
-
-       gtk_accelerator_parse(messages_get(messageAccel), &key, &mod);
-       if (key > 0) {
-               gtk_widget_add_accelerator(item, "activate", group, key, mod,
-                                          GTK_ACCEL_VISIBLE);
+       
+       accelerator_desc = nsgtk_accelerator_get_desc(message);
+       if (accelerator_desc != NULL) {
+               gtk_accelerator_parse(accelerator_desc, &key, &mod);
+               if (key > 0) {
+                       gtk_widget_add_accelerator(item,
+                                                  "activate",
+                                                  group,
+                                                  key,
+                                                  mod,
+                                                  GTK_ACCEL_VISIBLE);
+               }
        }
        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
        gtk_widget_show(item);
@@ -73,8 +83,7 @@ static bool nsgtk_menu_add_image_item(GtkMenu *menu,
        n->m##_menu = GTK_MENU(gtk_menu_new())
 
 #define IMAGE_ITEM(p, q, r, s, t)\
-       nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r,\
-                       #r "Accel", t)
+       nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r, t)
 
 #define CHECK_ITEM(p, q, r, s)\
        s->q##_menuitem = GTK_CHECK_MENU_ITEM(\
@@ -130,8 +139,8 @@ static bool nsgtk_menu_add_image_item(GtkMenu *menu,
 * creates an export submenu
 * \param group the 'global' in a gtk sense accelerator reference
 */
-
-static struct nsgtk_export_submenu *nsgtk_menu_export_submenu(GtkAccelGroup 
*group)
+static struct nsgtk_export_submenu *
+nsgtk_menu_export_submenu(GtkAccelGroup *group)
 {
        struct nsgtk_export_submenu *ret = malloc(sizeof(struct
                        nsgtk_export_submenu));
@@ -157,8 +166,8 @@ static struct nsgtk_export_submenu 
*nsgtk_menu_export_submenu(GtkAccelGroup *gro
 * \param group the 'global' in a gtk sense accelerator reference
 */
 
-static struct nsgtk_scaleview_submenu *nsgtk_menu_scaleview_submenu(
-               GtkAccelGroup *group)
+static struct nsgtk_scaleview_submenu *
+nsgtk_menu_scaleview_submenu(GtkAccelGroup *group)
 {
        struct nsgtk_scaleview_submenu *ret =
                        malloc(sizeof(struct nsgtk_scaleview_submenu));
@@ -185,7 +194,8 @@ static struct nsgtk_scaleview_submenu 
*nsgtk_menu_scaleview_submenu(
 
 static struct nsgtk_tabs_submenu *nsgtk_menu_tabs_submenu(GtkAccelGroup *group)
 {
-       struct nsgtk_tabs_submenu *ret = malloc(sizeof(struct 
nsgtk_tabs_submenu));
+       struct nsgtk_tabs_submenu *ret;
+       ret = malloc(sizeof(struct nsgtk_tabs_submenu));
        if (ret == NULL) {
                nsgtk_warning(messages_get("NoMemory"), 0);
                return NULL;
diff --git a/frontends/gtk/res/accelerators b/frontends/gtk/res/accelerators
new file mode 100644
index 0000000..e4140fc
--- /dev/null
+++ b/frontends/gtk/res/accelerators
@@ -0,0 +1,40 @@
+# GTK accelerator keys for menu entries
+# The keys must match those in the menus to be applied
+#
+# These are passed to gtk_accelerator_parse and must not be translated
+# The key names are the same as those in the gdk/gdkkeysyms.h header file
+#   but without the leading “GDK_KEY_”.
+
+gtkNextTab:<Control>Right
+gtkPrevTab:<Control>Left
+gtkCloseTab:<Control>w
+gtkNewTab:<Control>t
+gtkNewWindow:<Control>n
+gtkOpenFile:<Control>o
+gtkCloseWindow:<Control><shift>w
+gtkSavePage:<Control>s
+gtkPrintPreview:<Control><shift>p
+gtkPrint:<Control>p
+gtkQuitMenu:<Control>q
+gtkCut:<Control>x
+gtkCopy:<Control>c
+gtkPaste:<Control>v
+gtkSelectAll:<Control>a
+gtkFind:<Control>f
+gtkStop:Escape
+gtkReload:F5
+gtkZoomPlus:<Control>plus
+gtkZoomMinus:<Control>minus
+gtkZoomNormal:<Control>0
+gtkFullScreen:F11
+gtkPageSource:<Control>U
+gtkDownloads:<Control>j
+gtkBack:<alt>Left
+gtkForward:<alt>Right
+gtkHome:<alt>Down
+gtkLocalHistory:<Control>h
+gtkGlobalHistory:<Control><shift>h
+gtkAddBookMarks:<Control>d
+gtkShowBookMarks:F6
+gtkShowCookies:F9
+gtkOpenLocation:<Control>l
diff --git a/frontends/gtk/res/netsurf.gresource.xml 
b/frontends/gtk/res/netsurf.gresource.xml
index 5bae777..e824325 100644
--- a/frontends/gtk/res/netsurf.gresource.xml
+++ b/frontends/gtk/res/netsurf.gresource.xml
@@ -68,5 +68,6 @@
     <file>icons/hotlist-rmv.png</file>
     <file>icons/search.png</file>
     <file>languages</file>
+    <file>accelerators</file>
   </gresource>
 </gresources>
diff --git a/frontends/gtk/resources.c b/frontends/gtk/resources.c
index ef92fef..fc3ac6f 100644
--- a/frontends/gtk/resources.c
+++ b/frontends/gtk/resources.c
@@ -129,6 +129,7 @@ static struct nsgtk_resource_s direct_resource[] = {
        RES_ENTRY("icons/hotlist-rmv.png"),
        RES_ENTRY("icons/search.png"),
        RES_ENTRY("languages"),
+       RES_ENTRY("accelerators"),
        RES_ENTRY("Messages"),
        { NULL, 0, NSGTK_RESOURCE_FILE, NULL },
 };
@@ -178,11 +179,12 @@ init_resource(char **respath, struct nsgtk_resource_s 
*resource)
 
        langv = g_get_language_names();
 
+       /* look for resource under per language paths */
        while (langv[langc] != NULL) {
+               /* allocate and fill a full resource name path buffer */
                resnamelen = snprintf(NULL, 0,
                                      "/org/netsurf/%s/%s",
                                      langv[langc], resource->name);
-
                resname = malloc(resnamelen + 1);
                if (resname == NULL) {
                        return NSERROR_NOMEM;
@@ -191,6 +193,7 @@ init_resource(char **respath, struct nsgtk_resource_s 
*resource)
                         "/org/netsurf/%s/%s",
                         langv[langc], resource->name);
 
+               /* check if resource is present */
                present = g_resources_get_info(resname,
                                               G_RESOURCE_LOOKUP_FLAGS_NONE,
                                               NULL, NULL, NULL);
@@ -208,8 +211,9 @@ init_resource(char **respath, struct nsgtk_resource_s 
*resource)
 
                langc++;
        }
-       resnamelen = snprintf(NULL, 0, "/org/netsurf/%s", resource->name);
 
+       /* allocate and fill a full resource name path buffer with no language*/
+       resnamelen = snprintf(NULL, 0, "/org/netsurf/%s", resource->name);
        resname = malloc(resnamelen + 1);
        if (resname == NULL) {
                return NSERROR_NOMEM;
@@ -232,20 +236,22 @@ init_resource(char **respath, struct nsgtk_resource_s 
*resource)
 
 #endif
 
+       /* look for file on disc */
        resname = filepath_find(respath, resource->name);
-       if (resname == NULL) {
+       if (resname != NULL) {
+               /* found an entry on the path */
+               resource->path = resname;
+               resource->type = NSGTK_RESOURCE_FILE;
+
                NSLOG(netsurf, INFO,
-                     "Unable to find resource %s on resource path",
-                     resource->name);
-               return NSERROR_NOT_FOUND;
+                     "Found file resource path %s", resource->path);
+               return NSERROR_OK;
        }
 
-       /* found an entry on the path */
-       resource->path = resname;
-       resource->type = NSGTK_RESOURCE_FILE;
+       NSLOG(netsurf, INFO, "Unable to find resource %s on resource path",
+             resource->name);
 
-       NSLOG(netsurf, INFO, "Found file resource path %s", resource->path);
-       return NSERROR_OK;
+       return NSERROR_NOT_FOUND;
 }
 
 /**
@@ -381,7 +387,7 @@ find_resource_from_name(const char *resname, struct 
nsgtk_resource_s *resource)
 
 #ifdef SHOW_GRESOURCE
 /**
- * Debug dump of all resources compile din via GResource.
+ * Debug dump of all resources compiled in via GResource.
  */
 static void list_gresource(void)
 {
diff --git a/resources/FatMessages b/resources/FatMessages
index f9a96c6..de8eed6 100644
--- a/resources/FatMessages
+++ b/resources/FatMessages
@@ -1814,51 +1814,26 @@ de.gtk.gtkNewTab:Neuer _Tab
 fr.gtk.gtkNewTab:Nouvel _Onglet
 it.gtk.gtkNewTab:Nuova _scheda
 nl.gtk.gtkNewTab:Nieuw _Tabblad
-en.gtk.gtkNewTabAccel:<ctrl>t
-de.gtk.gtkNewTabAccel:<ctrl>t
-fr.gtk.gtkNewTabAccel:<ctrl>t
-it.gtk.gtkNewTabAccel:<ctrl>t
-nl.gtk.gtkNewTabAccel:<ctrl>t
 en.gtk.gtkNewWindow:_New Window
 de.gtk.gtkNewWindow:_Neues Fenster
 fr.gtk.gtkNewWindow:_Nouvelle Fenêtre
 it.gtk.gtkNewWindow:_Nuova finestra
 nl.gtk.gtkNewWindow:_Nieuw venster
-en.gtk.gtkNewWindowAccel:<ctrl>n
-de.gtk.gtkNewWindowAccel:<ctrl>n
-fr.gtk.gtkNewWindowAccel:<ctrl>n
-it.gtk.gtkNewWindowAccel:<ctrl>n
-nl.gtk.gtkNewWindowAccel:<ctrl>n
 en.gtk.gtkOpenFile:_Open File
 de.gtk.gtkOpenFile:Datei öffnen
 fr.gtk.gtkOpenFile:_Ouvrir un fichier
 it.gtk.gtkOpenFile:_Apri file
 nl.gtk.gtkOpenFile:Bestand _openen
-en.gtk.gtkOpenFileAccel:<ctrl>o
-de.gtk.gtkOpenFileAccel:<ctrl>o
-fr.gtk.gtkOpenFileAccel:<ctrl>o
-it.gtk.gtkOpenFileAccel:<ctrl>o
-nl.gtk.gtkOpenFileAccel:<ctrl>o
 en.gtk.gtkCloseWindow:_Close Window
 de.gtk.gtkCloseWindow:Fenster schließen
 fr.gtk.gtkCloseWindow:_Fermer la fenêtre
 it.gtk.gtkCloseWindow:_Chiudi finestra
 nl.gtk.gtkCloseWindow:_Venster sluiten
-en.gtk.gtkCloseWindowAccel:<ctrl><shift>w
-de.gtk.gtkCloseWindowAccel:<ctrl><shift>w
-fr.gtk.gtkCloseWindowAccel:<ctrl><maj>w
-it.gtk.gtkCloseWindowAccel:<ctrl><shift>w
-nl.gtk.gtkCloseWindowAccel:<ctrl><shift>w
 en.gtk.gtkSavePage:Save Page…
 de.gtk.gtkSavePage:Seite speichern..
 fr.gtk.gtkSavePage:Enregistrer la Page...
 it.gtk.gtkSavePage:Salva pagina...
 nl.gtk.gtkSavePage:Pagina bewaren...
-en.gtk.gtkSavePageAccel:<ctrl>s
-de.gtk.gtkSavePageAccel:<ctrl>s
-fr.gtk.gtkSavePageAccel:<ctrl>s
-it.gtk.gtkSavePageAccel:<ctrl>s
-nl.gtk.gtkSavePageAccel:<ctrl>s
 en.gtk.gtkExport:Export
 de.gtk.gtkExport:Exportieren
 fr.gtk.gtkExport:Exporter
@@ -1889,62 +1864,32 @@ de.gtk.gtkPrintPreview:Druckvorschau...
 fr.gtk.gtkPrintPreview:Aperçu avant impression...
 it.gtk.gtkPrintPreview:Anteprima di stampa...
 nl.gtk.gtkPrintPreview:Afdruk_voorbeeld...
-en.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
-de.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
-fr.gtk.gtkPrintPreviewAccel:<ctrl><maj>p
-it.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
-nl.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
 en.gtk.gtkPrint:Print…
 de.gtk.gtkPrint:Drucken...
 fr.gtk.gtkPrint:Imprimer...
 it.gtk.gtkPrint:Stampa...
 nl.gtk.gtkPrint:Af_drukken...
-en.gtk.gtkPrintAccel:<ctrl>p
-de.gtk.gtkPrintAccel:<ctrl>p
-fr.gtk.gtkPrintAccel:<ctrl>p
-it.gtk.gtkPrintAccel:<ctrl>p
-nl.gtk.gtkPrintAccel:<ctrl>p
 en.gtk.gtkQuitMenu:_Quit
 de.gtk.gtkQuitMenu:Beenden
 fr.gtk.gtkQuitMenu:_Quitter
 it.gtk.gtkQuitMenu:_Esci
 nl.gtk.gtkQuitMenu:A_fsluiten
-en.gtk.gtkQuitMenuAccel:<ctrl>q
-de.gtk.gtkQuitMenuAccel:<ctrl>q
-fr.gtk.gtkQuitMenuAccel:<ctrl>q
-it.gtk.gtkQuitMenuAccel:<ctrl>q
-nl.gtk.gtkQuitMenuAccel:<ctrl>q
 
 en.gtk.gtkCut:Cu_t
 de.gtk.gtkCut:Ausschneiden
 fr.gtk.gtkCut:Cou_per
 it.gtk.gtkCut:Ta_glia
 nl.gtk.gtkCut:K_nippen
-en.gtk.gtkCutAccel:<ctrl>x
-de.gtk.gtkCutAccel:<ctrl>x
-fr.gtk.gtkCutAccel:<ctrl>x
-it.gtk.gtkCutAccel:<ctrl>x
-nl.gtk.gtkCutAccel:<ctrl>x
 en.gtk.gtkCopy:_Copy
 de.gtk.gtkCopy:Kopieren
 fr.gtk.gtkCopy:_Copier
 it.gtk.gtkCopy:_Copia
 nl.gtk.gtkCopy:_Kopiëren
-en.gtk.gtkCopyAccel:<ctrl>c
-de.gtk.gtkCopyAccel:<ctrl>c
-fr.gtk.gtkCopyAccel:<ctrl>c
-it.gtk.gtkCopyAccel:<ctrl>c
-nl.gtk.gtkCopyAccel:<ctrl>c
 en.gtk.gtkPaste:_Paste
 de.gtk.gtkPaste:Einfügen
 fr.gtk.gtkPaste:C_oller
 it.gtk.gtkPaste:_Incolla
 nl.gtk.gtkPaste:_Plakken
-en.gtk.gtkPasteAccel:<ctrl>v
-de.gtk.gtkPasteAccel:<ctrl>v
-fr.gtk.gtkPasteAccel:<ctrl>v
-it.gtk.gtkPasteAccel:<ctrl>v
-nl.gtk.gtkPasteAccel:<ctrl>v
 en.gtk.gtkDelete:_Delete
 de.gtk.gtkDelete:Löschen
 fr.gtk.gtkDelete:_Supprimer
@@ -1955,21 +1900,11 @@ de.gtk.gtkSelectAll:_Alles auswählen
 fr.gtk.gtkSelectAll:_Tout sélectionner
 it.gtk.gtkSelectAll:Seleziona _Tutto
 nl.gtk.gtkSelectAll:_Alles selecteren
-en.gtk.gtkSelectAllAccel:<ctrl>a
-de.gtk.gtkSelectAllAccel:<ctrl>a
-fr.gtk.gtkSelectAllAccel:<ctrl>a
-it.gtk.gtkSelectAllAccel:<ctrl>a
-nl.gtk.gtkSelectAllAccel:<ctrl>a
 en.gtk.gtkFind:_Find…
 de.gtk.gtkFind:_Finden..
 fr.gtk.gtkFind:_Rechercher...
 it.gtk.gtkFind:_Trova...
 nl.gtk.gtkFind:_Zoeken...
-en.gtk.gtkFindAccel:<ctrl>f
-de.gtk.gtkFindAccel:<ctrl>f
-fr.gtk.gtkFindAccel:<ctrl>f
-it.gtk.gtkFindAccel:<ctrl>f
-nl.gtk.gtkFindAccel:<ctrl>f
 en.gtk.gtkPreferences:P_references
 de.gtk.gtkPreferences:Einstellungen
 fr.gtk.gtkPreferences:P_références
@@ -1981,21 +1916,11 @@ de.gtk.gtkStop:_Stop
 fr.gtk.gtkStop:_Arrêter
 it.gtk.gtkStop:_Stoppa
 nl.gtk.gtkStop:_Stoppen
-en.gtk.gtkStopAccel:Escape
-de.gtk.gtkStopAccel:Escape
-fr.gtk.gtkStopAccel:Échap
-it.gtk.gtkStopAccel:Escape
-nl.gtk.gtkStopAccel:Escape
 en.gtk.gtkReload:_Reload
 de.gtk.gtkReload:Neu laden
 fr.gtk.gtkReload:_Actualiser
 it.gtk.gtkReload:_Ricarica
 nl.gtk.gtkReload:Ver_nieuwen
-en.gtk.gtkReloadAccel:F5
-de.gtk.gtkReloadAccel:F5
-fr.gtk.gtkReloadAccel:F5
-it.gtk.gtkReloadAccel:F5
-nl.gtk.gtkReloadAccel:F5
 en.gtk.gtkScaleView:_Scale View
 de.gtk.gtkScaleView:Ansicht skalieren
 fr.gtk.gtkScaleView:_Zoom
@@ -2006,51 +1931,26 @@ de.gtk.gtkZoomPlus:Here_inzoomen
 fr.gtk.gtkZoomPlus:Zoom _avant
 it.gtk.gtkZoomPlus:_Incrementa zoom
 nl.gtk.gtkZoomPlus:_Inzoomen
-en.gtk.gtkZoomPlusAccel:<ctrl>plus
-de.gtk.gtkZoomPlusAccel:<ctrl>plus
-fr.gtk.gtkZoomPlusAccel:<ctrl>+
-it.gtk.gtkZoomPlusAccel:<ctrl>più
-nl.gtk.gtkZoomPlusAccel:<ctrl>plus
 en.gtk.gtkZoomMinus:Zoom _out
 de.gtk.gtkZoomMinus:Herausz_oomen
 fr.gtk.gtkZoomMinus:Z_oom arrière
 it.gtk.gtkZoomMinus:_Diminuisci zoom
 nl.gtk.gtkZoomMinus:_Uitzoomen
-en.gtk.gtkZoomMinusAccel:<ctrl>minus
-de.gtk.gtkZoomMinusAccel:<ctrl>minus
-fr.gtk.gtkZoomMinusAccel:<ctrl>-
-it.gtk.gtkZoomMinusAccel:<ctrl>meno
-nl.gtk.gtkZoomMinusAccel:<ctrl>minus
 en.gtk.gtkZoomNormal:_Normal size
 de.gtk.gtkZoomNormal:_Normalgröße
 fr.gtk.gtkZoomNormal:_Taille Normale
 it.gtk.gtkZoomNormal:Dimensione _normale
 nl.gtk.gtkZoomNormal:_Originele grootte
-en.gtk.gtkZoomNormalAccel:<ctrl>0
-de.gtk.gtkZoomNormalAccel:<ctrl>0
-fr.gtk.gtkZoomNormalAccel:<ctrl>0
-it.gtk.gtkZoomNormalAccel:<ctrl>0
-nl.gtk.gtkZoomNormalAccel:<ctrl>0
 en.gtk.gtkFullScreen:_Fullscreen
 de.gtk.gtkFullScreen:_Vollbild
 fr.gtk.gtkFullScreen:_Plein écran
 it.gtk.gtkFullScreen:_Tutto schermo
 nl.gtk.gtkFullScreen:_Volledig scherm
-en.gtk.gtkFullScreenAccel:F11
-de.gtk.gtkFullScreenAccel:F11
-fr.gtk.gtkFullScreenAccel:F11
-it.gtk.gtkFullScreenAccel:F11
-nl.gtk.gtkFullScreenAccel:F11
 en.gtk.gtkPageSource:Page S_ource
 de.gtk.gtkPageSource: Q_uelltext anzeigen
 fr.gtk.gtkPageSource:Code s_ource de la page
 it.gtk.gtkPageSource:Mostra s_orgente
 nl.gtk.gtkPageSource:Pagina_bron
-en.gtk.gtkPageSourceAccel:<ctrl>U
-de.gtk.gtkPageSourceAccel:<ctrl>U
-fr.gtk.gtkPageSourceAccel:<ctrl>U
-it.gtk.gtkPageSourceAccel:<ctrl>U
-nl.gtk.gtkPageSourceAccel:<ctrl>U
 en.gtk.gtkImages:_Images
 de.gtk.gtkImages:B_ilder
 fr.gtk.gtkImages:_Images
@@ -2096,11 +1996,6 @@ de.gtk.gtkDownloads:_Downloads...
 fr.gtk.gtkDownloads:_Téléchargements...
 it.gtk.gtkDownloads:_Trasferimenti...
 nl.gtk.gtkDownloads:_Downloads...
-en.gtk.gtkDownloadsAccel:<ctrl>j
-de.gtk.gtkDownloadsAccel:<ctrl>j
-fr.gtk.gtkDownloadsAccel:<ctrl>j
-it.gtk.gtkDownloadsAccel:<ctrl>j
-nl.gtk.gtkDownloadsAccel:<ctrl>j
 en.gtk.gtkSaveWindowSize:S_ave Window Size
 de.gtk.gtkSaveWindowSize:Fenstergröße _speichern
 fr.gtk.gtkSaveWindowSize:E_nregistrer la taille de la fenêtre
@@ -2132,122 +2027,62 @@ de.gtk.gtkBack:_Zurück
 fr.gtk.gtkBack:_Précédent
 it.gtk.gtkBack:_Indietro
 nl.gtk.gtkBack:_Terug
-en.gtk.gtkBackAccel:<alt>Left
-de.gtk.gtkBackAccel:<alt>Left
-fr.gtk.gtkBackAccel:<alt>Gauche
-it.gtk.gtkBackAccel:<alt>Sinistra
-nl.gtk.gtkBackAccel:<alt>Linkerpijltoets
 en.gtk.gtkForward:_Forward
 de.gtk.gtkForward:_Vorwärts
 fr.gtk.gtkForward:_Suivant
 it.gtk.gtkForward:_Avanti
 nl.gtk.gtkForward:_Vooruit
-en.gtk.gtkForwardAccel:<alt>Right
-de.gtk.gtkForwardAccel:<alt>Right
-fr.gtk.gtkForwardAccel:<alt>Droit
-it.gtk.gtkForwardAccel:<alt>Destra
-nl.gtk.gtkForwardAccel:<alt>Rechterpijltoets
 en.gtk.gtkHome:_Home
 de.gtk.gtkHome:_Startseite
 fr.gtk.gtkHome:_Accueil
 it.gtk.gtkHome:_Home
 nl.gtk.gtkHome:_Beginpagina
-en.gtk.gtkHomeAccel:<alt>Down
-de.gtk.gtkHomeAccel:<alt>Down
-fr.gtk.gtkHomeAccel:<alt>Bas
-it.gtk.gtkHomeAccel:<alt>Giù
-nl.gtk.gtkHomeAccel:<alt>Pijl omlaag
 en.gtk.gtkLocalHistory:_Local History…
 de.gtk.gtkLocalHistory:_Lokaler Verlauf
 fr.gtk.gtkLocalHistory:Historique _local
 it.gtk.gtkLocalHistory:Cronologia _locale
 nl.gtk.gtkLocalHistory:Vensterge_schiedenis
-en.gtk.gtkLocalHistoryAccel:<ctrl>h
-de.gtk.gtkLocalHistoryAccel:<ctrl>h
-fr.gtk.gtkLocalHistoryAccel:<ctrl>h
-it.gtk.gtkLocalHistoryAccel:<ctrl>h
-nl.gtk.gtkLocalHistoryAccel:<ctrl>h
 en.gtk.gtkGlobalHistory:_Global History…
 de.gtk.gtkGlobalHistory:_Globaler Verlauf
 fr.gtk.gtkGlobalHistory:Historique _global
 it.gtk.gtkGlobalHistory:Cronologia _globale
 nl.gtk.gtkGlobalHistory:Browser_geschiedenis
-en.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
-de.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
-fr.gtk.gtkGlobalHistoryAccel:<ctrl><maj>h
-it.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
-nl.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
 en.gtk.gtkAddBookMarks:_Add to Bookmarks…
 de.gtk.gtkAddBookMarks:_Lesezeichen hinzufügen..
 fr.gtk.gtkAddBookMarks:_Ajouter un marque-page..
 it.gtk.gtkAddBookMarks:_Aggiungi ai segnalibri...
 nl.gtk.gtkAddBookMarks:_Aan bladwijzers toevoegen...
-en.gtk.gtkAddBookMarksAccel:<ctrl>d
-de.gtk.gtkAddBookMarksAccel:<ctrl>d
-fr.gtk.gtkAddBookMarksAccel:<ctrl>d
-it.gtk.gtkAddBookMarksAccel:<ctrl>d
-nl.gtk.gtkAddBookMarksAccel:<ctrl>d
 en.gtk.gtkShowBookMarks:_Show Bookmarks…
 de.gtk.gtkShowBookMarks:Le_sezeichen anzeigen..
 fr.gtk.gtkShowBookMarks:_Montrer les marques-pages...
 it.gtk.gtkShowBookMarks:_Mostra segnalibri...
 nl.gtk.gtkShowBookMarks:Bladwijzers _beheren...
-en.gtk.gtkShowBookMarksAccel:F6
-de.gtk.gtkShowBookMarksAccel:F6
-fr.gtk.gtkShowBookMarksAccel:F6
-it.gtk.gtkShowBookMarksAccel:F6
-nl.gtk.gtkShowBookMarksAccel:F6
 en.gtk.gtkShowCookies:Show _Cookies…
 de.gtk.gtkShowCookies:Zeige _Cookies…
 fr.gtk.gtkShowCookies:Afficher _cookies...
 it.gtk.gtkShowCookies:Mostra _cookie...
 nl.gtk.gtkShowCookies:_Cookies beheren...
-en.gtk.gtkShowCookiesAccel:F9
-de.gtk.gtkShowCookiesAccel:F9
-fr.gtk.gtkShowCookiesAccel:F9
-it.gtk.gtkShowCookiesAccel:F9
-nl.gtk.gtkShowCookiesAccel:F9
 en.gtk.gtkOpenLocation:_Open Location…
 de.gtk.gtkOpenLocation:_Ort öffnen..
 fr.gtk.gtkOpenLocation:_Ouvrir un site..
 it.gtk.gtkOpenLocation:_Apri indirizzo...
 nl.gtk.gtkOpenLocation:Locatie _openen..
-en.gtk.gtkOpenLocationAccel:<ctrl>l
-de.gtk.gtkOpenLocationAccel:<ctrl>l
-fr.gtk.gtkOpenLocationAccel:<ctrl>l
-it.gtk.gtkOpenLocationAccel:<ctrl>l
-nl.gtk.gtkOpenLocationAccel:<ctrl>l
 
 en.gtk.gtkNextTab:_Next tab
 de.gtk.gtkNextTab:_Nächster Tab
 fr.gtk.gtkNextTab:O_nglet suivant
 it.gtk.gtkNextTab:Scheda _successiva
 nl.gtk.gtkNextTab:Vol_gende tabblad
-en.gtk.gtkNextTabAccel:<ctrl>Right
-de.gtk.gtkNextTabAccel:<ctrl>Right
-fr.gtk.gtkNextTabAccel:<ctrl>Droit
-it.gtk.gtkNextTabAccel:<ctrl>Destra
-nl.gtk.gtkNextTabAccel:<ctrl>Rechterpijltoets
 en.gtk.gtkPrevTab:_Previous tab
 de.gtk.gtkPrevTab:_Vorheriger Tab
 fr.gtk.gtkPrevTab:Onglet _précédent
 it.gtk.gtkPrevTab:Scheda _precedente
 nl.gtk.gtkPrevTab:Vo_rige tabblad
-en.gtk.gtkPrevTabAccel:<ctrl>Left
-de.gtk.gtkPrevTabAccel:<ctrl>Left
-fr.gtk.gtkPrevTabAccel:<ctrl>Gauche
-it.gtk.gtkPrevTabAccel:<ctrl>Sinistra
-nl.gtk.gtkPrevTabAccel:<ctrl>Linkerpijltoets
 en.gtk.gtkCloseTab:_Close tab
 de.gtk.gtkCloseTab:Tab s_chliessen
 fr.gtk.gtkCloseTab:_Fermer l'onglet
 it.gtk.gtkCloseTab:_Chiudi scheda
 nl.gtk.gtkCloseTab:Tabblad _sluiten
-en.gtk.gtkCloseTabAccel:<ctrl>w
-de.gtk.gtkCloseTabAccel:<ctrl>w
-fr.gtk.gtkCloseTabAccel:<ctrl>w
-it.gtk.gtkCloseTabAccel:<ctrl>w
-nl.gtk.gtkCloseTabAccel:<ctrl>w
 
 en.gtk.gtkContents:_Contents…
 de.gtk.gtkContents:_Inhalt


-----------------------------------------------------------------------

Summary of changes:
 frontends/beos/filetype.cpp             |    1 +
 frontends/gtk/Makefile                  |    2 +-
 frontends/gtk/accelerator.c             |   79 +++++++++++
 frontends/gtk/accelerator.h             |    2 +
 frontends/gtk/fetch.c                   |    3 +-
 frontends/gtk/gui.c                     |   74 ++++++----
 frontends/gtk/menu.c                    |   44 +++---
 frontends/gtk/res/accelerators          |   40 ++++++
 frontends/gtk/res/netsurf.gresource.xml |    1 +
 frontends/gtk/resources.c               |   30 ++--
 frontends/monkey/filetype.c             |    1 +
 resources/FatMessages                   |  165 ----------------------
 utils/hashtable.c                       |  227 ++++++++++++++++++++++++++++++-
 utils/hashtable.h                       |   53 ++++++--
 utils/messages.c                        |  158 ++-------------------
 15 files changed, 497 insertions(+), 383 deletions(-)
 create mode 100644 frontends/gtk/accelerator.c
 create mode 100644 frontends/gtk/accelerator.h
 create mode 100644 frontends/gtk/res/accelerators

diff --git a/frontends/beos/filetype.cpp b/frontends/beos/filetype.cpp
index 7a2ca97..bc988a8 100644
--- a/frontends/beos/filetype.cpp
+++ b/frontends/beos/filetype.cpp
@@ -18,6 +18,7 @@
 
 #define __STDBOOL_H__  1
 #include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
diff --git a/frontends/gtk/Makefile b/frontends/gtk/Makefile
index 6c2f06f..ec60ce7 100644
--- a/frontends/gtk/Makefile
+++ b/frontends/gtk/Makefile
@@ -165,7 +165,7 @@ endif
 
 # S_FRONTEND are sources purely for the GTK frontend
 S_FRONTEND := gui.c schedule.c layout_pango.c bitmap.c plotters.c      \
-       scaffolding.c gdk.c completion.c login.c throbber.c             \
+       scaffolding.c gdk.c completion.c login.c throbber.c accelerator.c \
        selection.c window.c fetch.c download.c menu.c print.c          \
        search.c tabs.c toolbar.c gettext.c compat.c viewdata.c         \
        viewsource.c preferences.c about.c resources.c corewindow.c     \
diff --git a/frontends/gtk/accelerator.c b/frontends/gtk/accelerator.c
new file mode 100644
index 0000000..11b7fb1
--- /dev/null
+++ b/frontends/gtk/accelerator.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * GTK accelerator support
+ *
+ */
+
+#include <stdint.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "utils/errors.h"
+#include "utils/hashtable.h"
+
+#include "gtk/resources.h"
+#include "gtk/accelerator.h"
+
+/** acclelerators are stored in a fixed-size hash table. */
+#define HASH_SIZE 53
+
+/** The hash table used to store the accelerators */
+static struct hash_table *accelerators_hash = NULL;
+
+nserror nsgtk_accelerator_init(char **respaths)
+{
+       nserror res;
+       const uint8_t *data;
+       size_t data_size;
+
+       if (accelerators_hash == NULL) {
+               accelerators_hash = hash_create(HASH_SIZE);
+       }
+       if (accelerators_hash == NULL) {
+               NSLOG(netsurf, INFO, "Unable to create hash table");
+               return NSERROR_NOMEM;
+       }
+
+       res = nsgtk_data_from_resname("accelerators", &data, &data_size);
+       if (res == NSERROR_OK) {
+               res = hash_add_inline(accelerators_hash, data, data_size);
+       } else {
+               const char *accelerators_path;
+               /* Obtain path to accelerators */
+               res = nsgtk_path_from_resname("accelerators",
+                                             &accelerators_path);
+               if (res == NSERROR_OK) {
+                       res = hash_add_file(accelerators_hash,
+                                           accelerators_path);
+               }
+       }
+
+       return res;
+}
+
+const char *nsgtk_accelerator_get_desc(const char *key)
+{
+       if ((key == NULL) ||
+           (accelerators_hash == NULL)) {
+               return NULL;
+       }
+       return hash_get(accelerators_hash, key);
+}
diff --git a/frontends/gtk/accelerator.h b/frontends/gtk/accelerator.h
new file mode 100644
index 0000000..09c253e
--- /dev/null
+++ b/frontends/gtk/accelerator.h
@@ -0,0 +1,2 @@
+nserror nsgtk_accelerator_init(char **respaths);
+const char *nsgtk_accelerator_get_desc(const char *key);
diff --git a/frontends/gtk/fetch.c b/frontends/gtk/fetch.c
index 7286aec..b05c1bd 100644
--- a/frontends/gtk/fetch.c
+++ b/frontends/gtk/fetch.c
@@ -30,6 +30,7 @@
  * ASCII hence not using locale dependant ctype functions for parsing.
  */
 
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -39,8 +40,8 @@
 #include <strings.h>
 #include <gtk/gtk.h>
 
-#include "utils/hashtable.h"
 #include "utils/log.h"
+#include "utils/hashtable.h"
 #include "utils/filepath.h"
 #include "utils/file.h"
 #include "utils/nsurl.h"
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index 0f79a1b..3163be1 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -72,6 +72,7 @@
 #include "gtk/resources.h"
 #include "gtk/login.h"
 #include "gtk/layout_pango.h"
+#include "gtk/accelerator.h"
 
 bool nsgtk_complete = false;
 
@@ -227,7 +228,11 @@ static nserror set_defaults(struct nsoption_s *defaults)
 
 
 /**
- * Initialize GTK interface.
+ * Initialize GTK specific parts of the browser.
+ *
+ * \param argc The number of arguments on the command line
+ * \param argv A string vector of command line arguments.
+ * \respath A string vector of the path elements of resources 
  */
 static nserror nsgtk_init(int argc, char** argv, char **respath)
 {
@@ -235,20 +240,29 @@ static nserror nsgtk_init(int argc, char** argv, char 
**respath)
        char *resource_filename;
        char *addr = NULL;
        nsurl *url;
-       nserror error;
+       nserror res;
+
+       /* Initialise gtk accelerator table */
+       res = nsgtk_accelerator_init(respaths);
+       if (res != NSERROR_OK) {
+               NSLOG(netsurf, INFO,
+                     "Unable to load gtk accelerator configuration");
+               /* not fatal if this does not load */
+       }
 
-       error = nsgtk_builder_new_from_resname("warning", &warning_builder);
-       if (error != NSERROR_OK) {
+       /* initialise warning dialog */
+       res = nsgtk_builder_new_from_resname("warning", &warning_builder);
+       if (res != NSERROR_OK) {
                NSLOG(netsurf, INFO, "Unable to initialise warning dialog");
-               return error;
+               return res;
        }
 
        gtk_builder_connect_signals(warning_builder, NULL);
 
        /* set default icon if its available */
-       error = nsgdk_pixbuf_new_from_resname("netsurf.xpm",
-                                             &win_default_icon_pixbuf);
-       if (error == NSERROR_OK) {
+       res = nsgdk_pixbuf_new_from_resname("netsurf.xpm",
+                                           &win_default_icon_pixbuf);
+       if (res == NSERROR_OK) {
                NSLOG(netsurf, INFO, "Seting default window icon");
                gtk_window_set_default_icon(win_default_icon_pixbuf);
        }
@@ -263,25 +277,25 @@ static nserror nsgtk_init(int argc, char** argv, char 
**respath)
        }
 
        /* Default favicon */
-       error = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf);
-       if (error != NSERROR_OK) {
+       res = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf);
+       if (res != NSERROR_OK) {
                favicon_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
                                                false, 8, 16, 16);
        }
 
        /* arrow down icon */
-       error = nsgdk_pixbuf_new_from_resname("arrow_down_8x32.png",
-                                             &arrow_down_pixbuf);
-       if (error != NSERROR_OK) {
+       res = nsgdk_pixbuf_new_from_resname("arrow_down_8x32.png",
+                                           &arrow_down_pixbuf);
+       if (res != NSERROR_OK) {
                arrow_down_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
                                                   false, 8, 8, 32);
        }
 
        /* initialise throbber */
-       error = nsgtk_throbber_init();
-       if (error != NSERROR_OK) {
+       res = nsgtk_throbber_init();
+       if (res != NSERROR_OK) {
                NSLOG(netsurf, INFO, "Unable to initialise throbber.");
-               return error;
+               return res;
        }
 
        /* Initialise completions - cannot fail */
@@ -302,13 +316,13 @@ static nserror nsgtk_init(int argc, char** argv, char 
**respath)
        urldb_load(nsoption_charp(url_file));
        urldb_load_cookies(nsoption_charp(cookie_file));
        hotlist_init(nsoption_charp(hotlist_path),
-                       nsoption_charp(hotlist_path));
+                    nsoption_charp(hotlist_path));
 
        /* Initialise top level UI elements */
-       error = nsgtk_download_init();
-       if (error != NSERROR_OK) {
+       res = nsgtk_download_init();
+       if (res != NSERROR_OK) {
                NSLOG(netsurf, INFO, "Unable to initialise download window.");
-               return error;
+               return res;
        }
 
        /* If there is a url specified on the command line use it */
@@ -338,19 +352,19 @@ static nserror nsgtk_init(int argc, char** argv, char 
**respath)
        }
 
        /* create an initial browser window */
-       error = nsurl_create(addr, &url);
-       if (error == NSERROR_OK) {
-               error = browser_window_create(BW_CREATE_HISTORY,
-                                             url,
-                                             NULL,
-                                             NULL,
-                                             NULL);
+       res = nsurl_create(addr, &url);
+       if (res == NSERROR_OK) {
+               res = browser_window_create(BW_CREATE_HISTORY,
+                                           url,
+                                           NULL,
+                                           NULL,
+                                           NULL);
                nsurl_unref(url);
        }
 
        free(addr);
 
-       return error;
+       return res;
 }
 
 
@@ -1163,7 +1177,7 @@ int main(int argc, char** argv)
                NSLOG(netsurf, INFO, "Unable to load translated messages");
                /** \todo decide if message load faliure should be fatal */
        }
-
+       
        /* Locate the correct user cache directory path */
        ret = get_cache_home(&cache_home);
        if (ret == NSERROR_NOT_FOUND) {
@@ -1183,7 +1197,7 @@ int main(int argc, char** argv)
                return 1;
        }
 
-       /* run the browser */
+       /* gtk specific initalisation and main run loop */
        ret = nsgtk_init(argc, argv, respaths);
        if (ret != NSERROR_OK) {
                fprintf(stderr, "NetSurf gtk initialise failed (%s)\n",
diff --git a/frontends/gtk/menu.c b/frontends/gtk/menu.c
index a93ef93..6a60332 100644
--- a/frontends/gtk/menu.c
+++ b/frontends/gtk/menu.c
@@ -27,6 +27,7 @@
 #include "gtk/compat.h"
 #include "gtk/menu.h"
 #include "gtk/warn.h"
+#include "gtk/accelerator.h"
 
 /**
  * Adds image menu item to a menu.
@@ -34,28 +35,37 @@
  * \param menu the menu to add the item to
  * \param item_out a pointer to the item's location in the menu struct
  * \param message the menu item I18n lookup value
- * \param messageAccel the menu item accelerator I18n lookup value
  * \param group the 'global' in a gtk sense accelerator group
  * \return true if sucessful and \a item_out updated else false.
  */
 
-static bool nsgtk_menu_add_image_item(GtkMenu *menu,
-               GtkWidget **item_out, const char *message,
-               const char *messageAccel, GtkAccelGroup *group)
+static bool
+nsgtk_menu_add_image_item(GtkMenu *menu,
+                         GtkWidget **item_out,
+                         const char *message,
+                         GtkAccelGroup *group)
 {
        unsigned int key;
        GdkModifierType mod;
        GtkWidget *item;
-
+       const char *accelerator_desc; /* accelerator key description */
+       
        item = nsgtk_image_menu_item_new_with_mnemonic(messages_get(message));
        if (item == NULL) {
                return false;
        }
-
-       gtk_accelerator_parse(messages_get(messageAccel), &key, &mod);
-       if (key > 0) {
-               gtk_widget_add_accelerator(item, "activate", group, key, mod,
-                                          GTK_ACCEL_VISIBLE);
+       
+       accelerator_desc = nsgtk_accelerator_get_desc(message);
+       if (accelerator_desc != NULL) {
+               gtk_accelerator_parse(accelerator_desc, &key, &mod);
+               if (key > 0) {
+                       gtk_widget_add_accelerator(item,
+                                                  "activate",
+                                                  group,
+                                                  key,
+                                                  mod,
+                                                  GTK_ACCEL_VISIBLE);
+               }
        }
        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
        gtk_widget_show(item);
@@ -73,8 +83,7 @@ static bool nsgtk_menu_add_image_item(GtkMenu *menu,
        n->m##_menu = GTK_MENU(gtk_menu_new())
 
 #define IMAGE_ITEM(p, q, r, s, t)\
-       nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r,\
-                       #r "Accel", t)
+       nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r, t)
 
 #define CHECK_ITEM(p, q, r, s)\
        s->q##_menuitem = GTK_CHECK_MENU_ITEM(\
@@ -130,8 +139,8 @@ static bool nsgtk_menu_add_image_item(GtkMenu *menu,
 * creates an export submenu
 * \param group the 'global' in a gtk sense accelerator reference
 */
-
-static struct nsgtk_export_submenu *nsgtk_menu_export_submenu(GtkAccelGroup 
*group)
+static struct nsgtk_export_submenu *
+nsgtk_menu_export_submenu(GtkAccelGroup *group)
 {
        struct nsgtk_export_submenu *ret = malloc(sizeof(struct
                        nsgtk_export_submenu));
@@ -157,8 +166,8 @@ static struct nsgtk_export_submenu 
*nsgtk_menu_export_submenu(GtkAccelGroup *gro
 * \param group the 'global' in a gtk sense accelerator reference
 */
 
-static struct nsgtk_scaleview_submenu *nsgtk_menu_scaleview_submenu(
-               GtkAccelGroup *group)
+static struct nsgtk_scaleview_submenu *
+nsgtk_menu_scaleview_submenu(GtkAccelGroup *group)
 {
        struct nsgtk_scaleview_submenu *ret =
                        malloc(sizeof(struct nsgtk_scaleview_submenu));
@@ -185,7 +194,8 @@ static struct nsgtk_scaleview_submenu 
*nsgtk_menu_scaleview_submenu(
 
 static struct nsgtk_tabs_submenu *nsgtk_menu_tabs_submenu(GtkAccelGroup *group)
 {
-       struct nsgtk_tabs_submenu *ret = malloc(sizeof(struct 
nsgtk_tabs_submenu));
+       struct nsgtk_tabs_submenu *ret;
+       ret = malloc(sizeof(struct nsgtk_tabs_submenu));
        if (ret == NULL) {
                nsgtk_warning(messages_get("NoMemory"), 0);
                return NULL;
diff --git a/frontends/gtk/res/accelerators b/frontends/gtk/res/accelerators
new file mode 100644
index 0000000..2da229a
--- /dev/null
+++ b/frontends/gtk/res/accelerators
@@ -0,0 +1,40 @@
+# GTK accelerator keys for menu entries
+# The keys must match those in the menus to be applied
+#
+# These are passed to gtk_accelerator_parse and must not be translated
+# The key names are the same as those in the gdk/gdkkeysyms.h header file
+#   but without the leading “GDK_KEY_”.
+
+gtkNextTab:<Control>Page_Down
+gtkPrevTab:<Control>Page_Up
+gtkCloseTab:<Control>w
+gtkNewTab:<Control>t
+gtkNewWindow:<Control>n
+gtkOpenFile:<Control>o
+gtkCloseWindow:<Control><shift>w
+gtkSavePage:<Control>s
+gtkPrintPreview:<Control><shift>p
+gtkPrint:<Control>p
+gtkQuitMenu:<Control>q
+gtkCut:<Control>x
+gtkCopy:<Control>c
+gtkPaste:<Control>v
+gtkSelectAll:<Control>a
+gtkFind:<Control>f
+gtkStop:Escape
+gtkReload:F5
+gtkZoomPlus:<Control>plus
+gtkZoomMinus:<Control>minus
+gtkZoomNormal:<Control>0
+gtkFullScreen:F11
+gtkPageSource:<Control>U
+gtkDownloads:<Control>j
+gtkBack:<alt>Left
+gtkForward:<alt>Right
+gtkHome:<alt>Down
+gtkLocalHistory:<Control>h
+gtkGlobalHistory:<Control><shift>h
+gtkAddBookMarks:<Control>d
+gtkShowBookMarks:F6
+gtkShowCookies:F9
+gtkOpenLocation:<Control>l
diff --git a/frontends/gtk/res/netsurf.gresource.xml 
b/frontends/gtk/res/netsurf.gresource.xml
index 5bae777..e824325 100644
--- a/frontends/gtk/res/netsurf.gresource.xml
+++ b/frontends/gtk/res/netsurf.gresource.xml
@@ -68,5 +68,6 @@
     <file>icons/hotlist-rmv.png</file>
     <file>icons/search.png</file>
     <file>languages</file>
+    <file>accelerators</file>
   </gresource>
 </gresources>
diff --git a/frontends/gtk/resources.c b/frontends/gtk/resources.c
index ef92fef..fc3ac6f 100644
--- a/frontends/gtk/resources.c
+++ b/frontends/gtk/resources.c
@@ -129,6 +129,7 @@ static struct nsgtk_resource_s direct_resource[] = {
        RES_ENTRY("icons/hotlist-rmv.png"),
        RES_ENTRY("icons/search.png"),
        RES_ENTRY("languages"),
+       RES_ENTRY("accelerators"),
        RES_ENTRY("Messages"),
        { NULL, 0, NSGTK_RESOURCE_FILE, NULL },
 };
@@ -178,11 +179,12 @@ init_resource(char **respath, struct nsgtk_resource_s 
*resource)
 
        langv = g_get_language_names();
 
+       /* look for resource under per language paths */
        while (langv[langc] != NULL) {
+               /* allocate and fill a full resource name path buffer */
                resnamelen = snprintf(NULL, 0,
                                      "/org/netsurf/%s/%s",
                                      langv[langc], resource->name);
-
                resname = malloc(resnamelen + 1);
                if (resname == NULL) {
                        return NSERROR_NOMEM;
@@ -191,6 +193,7 @@ init_resource(char **respath, struct nsgtk_resource_s 
*resource)
                         "/org/netsurf/%s/%s",
                         langv[langc], resource->name);
 
+               /* check if resource is present */
                present = g_resources_get_info(resname,
                                               G_RESOURCE_LOOKUP_FLAGS_NONE,
                                               NULL, NULL, NULL);
@@ -208,8 +211,9 @@ init_resource(char **respath, struct nsgtk_resource_s 
*resource)
 
                langc++;
        }
-       resnamelen = snprintf(NULL, 0, "/org/netsurf/%s", resource->name);
 
+       /* allocate and fill a full resource name path buffer with no language*/
+       resnamelen = snprintf(NULL, 0, "/org/netsurf/%s", resource->name);
        resname = malloc(resnamelen + 1);
        if (resname == NULL) {
                return NSERROR_NOMEM;
@@ -232,20 +236,22 @@ init_resource(char **respath, struct nsgtk_resource_s 
*resource)
 
 #endif
 
+       /* look for file on disc */
        resname = filepath_find(respath, resource->name);
-       if (resname == NULL) {
+       if (resname != NULL) {
+               /* found an entry on the path */
+               resource->path = resname;
+               resource->type = NSGTK_RESOURCE_FILE;
+
                NSLOG(netsurf, INFO,
-                     "Unable to find resource %s on resource path",
-                     resource->name);
-               return NSERROR_NOT_FOUND;
+                     "Found file resource path %s", resource->path);
+               return NSERROR_OK;
        }
 
-       /* found an entry on the path */
-       resource->path = resname;
-       resource->type = NSGTK_RESOURCE_FILE;
+       NSLOG(netsurf, INFO, "Unable to find resource %s on resource path",
+             resource->name);
 
-       NSLOG(netsurf, INFO, "Found file resource path %s", resource->path);
-       return NSERROR_OK;
+       return NSERROR_NOT_FOUND;
 }
 
 /**
@@ -381,7 +387,7 @@ find_resource_from_name(const char *resname, struct 
nsgtk_resource_s *resource)
 
 #ifdef SHOW_GRESOURCE
 /**
- * Debug dump of all resources compile din via GResource.
+ * Debug dump of all resources compiled in via GResource.
  */
 static void list_gresource(void)
 {
diff --git a/frontends/monkey/filetype.c b/frontends/monkey/filetype.c
index 979796b..65c84f9 100644
--- a/frontends/monkey/filetype.c
+++ b/frontends/monkey/filetype.c
@@ -32,6 +32,7 @@
 
 #include <stdio.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <string.h>
 #include <strings.h>
 #include <stdlib.h>
diff --git a/resources/FatMessages b/resources/FatMessages
index f9a96c6..de8eed6 100644
--- a/resources/FatMessages
+++ b/resources/FatMessages
@@ -1814,51 +1814,26 @@ de.gtk.gtkNewTab:Neuer _Tab
 fr.gtk.gtkNewTab:Nouvel _Onglet
 it.gtk.gtkNewTab:Nuova _scheda
 nl.gtk.gtkNewTab:Nieuw _Tabblad
-en.gtk.gtkNewTabAccel:<ctrl>t
-de.gtk.gtkNewTabAccel:<ctrl>t
-fr.gtk.gtkNewTabAccel:<ctrl>t
-it.gtk.gtkNewTabAccel:<ctrl>t
-nl.gtk.gtkNewTabAccel:<ctrl>t
 en.gtk.gtkNewWindow:_New Window
 de.gtk.gtkNewWindow:_Neues Fenster
 fr.gtk.gtkNewWindow:_Nouvelle Fenêtre
 it.gtk.gtkNewWindow:_Nuova finestra
 nl.gtk.gtkNewWindow:_Nieuw venster
-en.gtk.gtkNewWindowAccel:<ctrl>n
-de.gtk.gtkNewWindowAccel:<ctrl>n
-fr.gtk.gtkNewWindowAccel:<ctrl>n
-it.gtk.gtkNewWindowAccel:<ctrl>n
-nl.gtk.gtkNewWindowAccel:<ctrl>n
 en.gtk.gtkOpenFile:_Open File
 de.gtk.gtkOpenFile:Datei öffnen
 fr.gtk.gtkOpenFile:_Ouvrir un fichier
 it.gtk.gtkOpenFile:_Apri file
 nl.gtk.gtkOpenFile:Bestand _openen
-en.gtk.gtkOpenFileAccel:<ctrl>o
-de.gtk.gtkOpenFileAccel:<ctrl>o
-fr.gtk.gtkOpenFileAccel:<ctrl>o
-it.gtk.gtkOpenFileAccel:<ctrl>o
-nl.gtk.gtkOpenFileAccel:<ctrl>o
 en.gtk.gtkCloseWindow:_Close Window
 de.gtk.gtkCloseWindow:Fenster schließen
 fr.gtk.gtkCloseWindow:_Fermer la fenêtre
 it.gtk.gtkCloseWindow:_Chiudi finestra
 nl.gtk.gtkCloseWindow:_Venster sluiten
-en.gtk.gtkCloseWindowAccel:<ctrl><shift>w
-de.gtk.gtkCloseWindowAccel:<ctrl><shift>w
-fr.gtk.gtkCloseWindowAccel:<ctrl><maj>w
-it.gtk.gtkCloseWindowAccel:<ctrl><shift>w
-nl.gtk.gtkCloseWindowAccel:<ctrl><shift>w
 en.gtk.gtkSavePage:Save Page…
 de.gtk.gtkSavePage:Seite speichern..
 fr.gtk.gtkSavePage:Enregistrer la Page...
 it.gtk.gtkSavePage:Salva pagina...
 nl.gtk.gtkSavePage:Pagina bewaren...
-en.gtk.gtkSavePageAccel:<ctrl>s
-de.gtk.gtkSavePageAccel:<ctrl>s
-fr.gtk.gtkSavePageAccel:<ctrl>s
-it.gtk.gtkSavePageAccel:<ctrl>s
-nl.gtk.gtkSavePageAccel:<ctrl>s
 en.gtk.gtkExport:Export
 de.gtk.gtkExport:Exportieren
 fr.gtk.gtkExport:Exporter
@@ -1889,62 +1864,32 @@ de.gtk.gtkPrintPreview:Druckvorschau...
 fr.gtk.gtkPrintPreview:Aperçu avant impression...
 it.gtk.gtkPrintPreview:Anteprima di stampa...
 nl.gtk.gtkPrintPreview:Afdruk_voorbeeld...
-en.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
-de.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
-fr.gtk.gtkPrintPreviewAccel:<ctrl><maj>p
-it.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
-nl.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
 en.gtk.gtkPrint:Print…
 de.gtk.gtkPrint:Drucken...
 fr.gtk.gtkPrint:Imprimer...
 it.gtk.gtkPrint:Stampa...
 nl.gtk.gtkPrint:Af_drukken...
-en.gtk.gtkPrintAccel:<ctrl>p
-de.gtk.gtkPrintAccel:<ctrl>p
-fr.gtk.gtkPrintAccel:<ctrl>p
-it.gtk.gtkPrintAccel:<ctrl>p
-nl.gtk.gtkPrintAccel:<ctrl>p
 en.gtk.gtkQuitMenu:_Quit
 de.gtk.gtkQuitMenu:Beenden
 fr.gtk.gtkQuitMenu:_Quitter
 it.gtk.gtkQuitMenu:_Esci
 nl.gtk.gtkQuitMenu:A_fsluiten
-en.gtk.gtkQuitMenuAccel:<ctrl>q
-de.gtk.gtkQuitMenuAccel:<ctrl>q
-fr.gtk.gtkQuitMenuAccel:<ctrl>q
-it.gtk.gtkQuitMenuAccel:<ctrl>q
-nl.gtk.gtkQuitMenuAccel:<ctrl>q
 
 en.gtk.gtkCut:Cu_t
 de.gtk.gtkCut:Ausschneiden
 fr.gtk.gtkCut:Cou_per
 it.gtk.gtkCut:Ta_glia
 nl.gtk.gtkCut:K_nippen
-en.gtk.gtkCutAccel:<ctrl>x
-de.gtk.gtkCutAccel:<ctrl>x
-fr.gtk.gtkCutAccel:<ctrl>x
-it.gtk.gtkCutAccel:<ctrl>x
-nl.gtk.gtkCutAccel:<ctrl>x
 en.gtk.gtkCopy:_Copy
 de.gtk.gtkCopy:Kopieren
 fr.gtk.gtkCopy:_Copier
 it.gtk.gtkCopy:_Copia
 nl.gtk.gtkCopy:_Kopiëren
-en.gtk.gtkCopyAccel:<ctrl>c
-de.gtk.gtkCopyAccel:<ctrl>c
-fr.gtk.gtkCopyAccel:<ctrl>c
-it.gtk.gtkCopyAccel:<ctrl>c
-nl.gtk.gtkCopyAccel:<ctrl>c
 en.gtk.gtkPaste:_Paste
 de.gtk.gtkPaste:Einfügen
 fr.gtk.gtkPaste:C_oller
 it.gtk.gtkPaste:_Incolla
 nl.gtk.gtkPaste:_Plakken
-en.gtk.gtkPasteAccel:<ctrl>v
-de.gtk.gtkPasteAccel:<ctrl>v
-fr.gtk.gtkPasteAccel:<ctrl>v
-it.gtk.gtkPasteAccel:<ctrl>v
-nl.gtk.gtkPasteAccel:<ctrl>v
 en.gtk.gtkDelete:_Delete
 de.gtk.gtkDelete:Löschen
 fr.gtk.gtkDelete:_Supprimer
@@ -1955,21 +1900,11 @@ de.gtk.gtkSelectAll:_Alles auswählen
 fr.gtk.gtkSelectAll:_Tout sélectionner
 it.gtk.gtkSelectAll:Seleziona _Tutto
 nl.gtk.gtkSelectAll:_Alles selecteren
-en.gtk.gtkSelectAllAccel:<ctrl>a
-de.gtk.gtkSelectAllAccel:<ctrl>a
-fr.gtk.gtkSelectAllAccel:<ctrl>a
-it.gtk.gtkSelectAllAccel:<ctrl>a
-nl.gtk.gtkSelectAllAccel:<ctrl>a
 en.gtk.gtkFind:_Find…
 de.gtk.gtkFind:_Finden..
 fr.gtk.gtkFind:_Rechercher...
 it.gtk.gtkFind:_Trova...
 nl.gtk.gtkFind:_Zoeken...
-en.gtk.gtkFindAccel:<ctrl>f
-de.gtk.gtkFindAccel:<ctrl>f
-fr.gtk.gtkFindAccel:<ctrl>f
-it.gtk.gtkFindAccel:<ctrl>f
-nl.gtk.gtkFindAccel:<ctrl>f
 en.gtk.gtkPreferences:P_references
 de.gtk.gtkPreferences:Einstellungen
 fr.gtk.gtkPreferences:P_références
@@ -1981,21 +1916,11 @@ de.gtk.gtkStop:_Stop
 fr.gtk.gtkStop:_Arrêter
 it.gtk.gtkStop:_Stoppa
 nl.gtk.gtkStop:_Stoppen
-en.gtk.gtkStopAccel:Escape
-de.gtk.gtkStopAccel:Escape
-fr.gtk.gtkStopAccel:Échap
-it.gtk.gtkStopAccel:Escape
-nl.gtk.gtkStopAccel:Escape
 en.gtk.gtkReload:_Reload
 de.gtk.gtkReload:Neu laden
 fr.gtk.gtkReload:_Actualiser
 it.gtk.gtkReload:_Ricarica
 nl.gtk.gtkReload:Ver_nieuwen
-en.gtk.gtkReloadAccel:F5
-de.gtk.gtkReloadAccel:F5
-fr.gtk.gtkReloadAccel:F5
-it.gtk.gtkReloadAccel:F5
-nl.gtk.gtkReloadAccel:F5
 en.gtk.gtkScaleView:_Scale View
 de.gtk.gtkScaleView:Ansicht skalieren
 fr.gtk.gtkScaleView:_Zoom
@@ -2006,51 +1931,26 @@ de.gtk.gtkZoomPlus:Here_inzoomen
 fr.gtk.gtkZoomPlus:Zoom _avant
 it.gtk.gtkZoomPlus:_Incrementa zoom
 nl.gtk.gtkZoomPlus:_Inzoomen
-en.gtk.gtkZoomPlusAccel:<ctrl>plus
-de.gtk.gtkZoomPlusAccel:<ctrl>plus
-fr.gtk.gtkZoomPlusAccel:<ctrl>+
-it.gtk.gtkZoomPlusAccel:<ctrl>più
-nl.gtk.gtkZoomPlusAccel:<ctrl>plus
 en.gtk.gtkZoomMinus:Zoom _out
 de.gtk.gtkZoomMinus:Herausz_oomen
 fr.gtk.gtkZoomMinus:Z_oom arrière
 it.gtk.gtkZoomMinus:_Diminuisci zoom
 nl.gtk.gtkZoomMinus:_Uitzoomen
-en.gtk.gtkZoomMinusAccel:<ctrl>minus
-de.gtk.gtkZoomMinusAccel:<ctrl>minus
-fr.gtk.gtkZoomMinusAccel:<ctrl>-
-it.gtk.gtkZoomMinusAccel:<ctrl>meno
-nl.gtk.gtkZoomMinusAccel:<ctrl>minus
 en.gtk.gtkZoomNormal:_Normal size
 de.gtk.gtkZoomNormal:_Normalgröße
 fr.gtk.gtkZoomNormal:_Taille Normale
 it.gtk.gtkZoomNormal:Dimensione _normale
 nl.gtk.gtkZoomNormal:_Originele grootte
-en.gtk.gtkZoomNormalAccel:<ctrl>0
-de.gtk.gtkZoomNormalAccel:<ctrl>0
-fr.gtk.gtkZoomNormalAccel:<ctrl>0
-it.gtk.gtkZoomNormalAccel:<ctrl>0
-nl.gtk.gtkZoomNormalAccel:<ctrl>0
 en.gtk.gtkFullScreen:_Fullscreen
 de.gtk.gtkFullScreen:_Vollbild
 fr.gtk.gtkFullScreen:_Plein écran
 it.gtk.gtkFullScreen:_Tutto schermo
 nl.gtk.gtkFullScreen:_Volledig scherm
-en.gtk.gtkFullScreenAccel:F11
-de.gtk.gtkFullScreenAccel:F11
-fr.gtk.gtkFullScreenAccel:F11
-it.gtk.gtkFullScreenAccel:F11
-nl.gtk.gtkFullScreenAccel:F11
 en.gtk.gtkPageSource:Page S_ource
 de.gtk.gtkPageSource: Q_uelltext anzeigen
 fr.gtk.gtkPageSource:Code s_ource de la page
 it.gtk.gtkPageSource:Mostra s_orgente
 nl.gtk.gtkPageSource:Pagina_bron
-en.gtk.gtkPageSourceAccel:<ctrl>U
-de.gtk.gtkPageSourceAccel:<ctrl>U
-fr.gtk.gtkPageSourceAccel:<ctrl>U
-it.gtk.gtkPageSourceAccel:<ctrl>U
-nl.gtk.gtkPageSourceAccel:<ctrl>U
 en.gtk.gtkImages:_Images
 de.gtk.gtkImages:B_ilder
 fr.gtk.gtkImages:_Images
@@ -2096,11 +1996,6 @@ de.gtk.gtkDownloads:_Downloads...
 fr.gtk.gtkDownloads:_Téléchargements...
 it.gtk.gtkDownloads:_Trasferimenti...
 nl.gtk.gtkDownloads:_Downloads...
-en.gtk.gtkDownloadsAccel:<ctrl>j
-de.gtk.gtkDownloadsAccel:<ctrl>j
-fr.gtk.gtkDownloadsAccel:<ctrl>j
-it.gtk.gtkDownloadsAccel:<ctrl>j
-nl.gtk.gtkDownloadsAccel:<ctrl>j
 en.gtk.gtkSaveWindowSize:S_ave Window Size
 de.gtk.gtkSaveWindowSize:Fenstergröße _speichern
 fr.gtk.gtkSaveWindowSize:E_nregistrer la taille de la fenêtre
@@ -2132,122 +2027,62 @@ de.gtk.gtkBack:_Zurück
 fr.gtk.gtkBack:_Précédent
 it.gtk.gtkBack:_Indietro
 nl.gtk.gtkBack:_Terug
-en.gtk.gtkBackAccel:<alt>Left
-de.gtk.gtkBackAccel:<alt>Left
-fr.gtk.gtkBackAccel:<alt>Gauche
-it.gtk.gtkBackAccel:<alt>Sinistra
-nl.gtk.gtkBackAccel:<alt>Linkerpijltoets
 en.gtk.gtkForward:_Forward
 de.gtk.gtkForward:_Vorwärts
 fr.gtk.gtkForward:_Suivant
 it.gtk.gtkForward:_Avanti
 nl.gtk.gtkForward:_Vooruit
-en.gtk.gtkForwardAccel:<alt>Right
-de.gtk.gtkForwardAccel:<alt>Right
-fr.gtk.gtkForwardAccel:<alt>Droit
-it.gtk.gtkForwardAccel:<alt>Destra
-nl.gtk.gtkForwardAccel:<alt>Rechterpijltoets
 en.gtk.gtkHome:_Home
 de.gtk.gtkHome:_Startseite
 fr.gtk.gtkHome:_Accueil
 it.gtk.gtkHome:_Home
 nl.gtk.gtkHome:_Beginpagina
-en.gtk.gtkHomeAccel:<alt>Down
-de.gtk.gtkHomeAccel:<alt>Down
-fr.gtk.gtkHomeAccel:<alt>Bas
-it.gtk.gtkHomeAccel:<alt>Giù
-nl.gtk.gtkHomeAccel:<alt>Pijl omlaag
 en.gtk.gtkLocalHistory:_Local History…
 de.gtk.gtkLocalHistory:_Lokaler Verlauf
 fr.gtk.gtkLocalHistory:Historique _local
 it.gtk.gtkLocalHistory:Cronologia _locale
 nl.gtk.gtkLocalHistory:Vensterge_schiedenis
-en.gtk.gtkLocalHistoryAccel:<ctrl>h
-de.gtk.gtkLocalHistoryAccel:<ctrl>h
-fr.gtk.gtkLocalHistoryAccel:<ctrl>h
-it.gtk.gtkLocalHistoryAccel:<ctrl>h
-nl.gtk.gtkLocalHistoryAccel:<ctrl>h
 en.gtk.gtkGlobalHistory:_Global History…
 de.gtk.gtkGlobalHistory:_Globaler Verlauf
 fr.gtk.gtkGlobalHistory:Historique _global
 it.gtk.gtkGlobalHistory:Cronologia _globale
 nl.gtk.gtkGlobalHistory:Browser_geschiedenis
-en.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
-de.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
-fr.gtk.gtkGlobalHistoryAccel:<ctrl><maj>h
-it.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
-nl.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
 en.gtk.gtkAddBookMarks:_Add to Bookmarks…
 de.gtk.gtkAddBookMarks:_Lesezeichen hinzufügen..
 fr.gtk.gtkAddBookMarks:_Ajouter un marque-page..
 it.gtk.gtkAddBookMarks:_Aggiungi ai segnalibri...
 nl.gtk.gtkAddBookMarks:_Aan bladwijzers toevoegen...
-en.gtk.gtkAddBookMarksAccel:<ctrl>d
-de.gtk.gtkAddBookMarksAccel:<ctrl>d
-fr.gtk.gtkAddBookMarksAccel:<ctrl>d
-it.gtk.gtkAddBookMarksAccel:<ctrl>d
-nl.gtk.gtkAddBookMarksAccel:<ctrl>d
 en.gtk.gtkShowBookMarks:_Show Bookmarks…
 de.gtk.gtkShowBookMarks:Le_sezeichen anzeigen..
 fr.gtk.gtkShowBookMarks:_Montrer les marques-pages...
 it.gtk.gtkShowBookMarks:_Mostra segnalibri...
 nl.gtk.gtkShowBookMarks:Bladwijzers _beheren...
-en.gtk.gtkShowBookMarksAccel:F6
-de.gtk.gtkShowBookMarksAccel:F6
-fr.gtk.gtkShowBookMarksAccel:F6
-it.gtk.gtkShowBookMarksAccel:F6
-nl.gtk.gtkShowBookMarksAccel:F6
 en.gtk.gtkShowCookies:Show _Cookies…
 de.gtk.gtkShowCookies:Zeige _Cookies…
 fr.gtk.gtkShowCookies:Afficher _cookies...
 it.gtk.gtkShowCookies:Mostra _cookie...
 nl.gtk.gtkShowCookies:_Cookies beheren...
-en.gtk.gtkShowCookiesAccel:F9
-de.gtk.gtkShowCookiesAccel:F9
-fr.gtk.gtkShowCookiesAccel:F9
-it.gtk.gtkShowCookiesAccel:F9
-nl.gtk.gtkShowCookiesAccel:F9
 en.gtk.gtkOpenLocation:_Open Location…
 de.gtk.gtkOpenLocation:_Ort öffnen..
 fr.gtk.gtkOpenLocation:_Ouvrir un site..
 it.gtk.gtkOpenLocation:_Apri indirizzo...
 nl.gtk.gtkOpenLocation:Locatie _openen..
-en.gtk.gtkOpenLocationAccel:<ctrl>l
-de.gtk.gtkOpenLocationAccel:<ctrl>l
-fr.gtk.gtkOpenLocationAccel:<ctrl>l
-it.gtk.gtkOpenLocationAccel:<ctrl>l
-nl.gtk.gtkOpenLocationAccel:<ctrl>l
 
 en.gtk.gtkNextTab:_Next tab
 de.gtk.gtkNextTab:_Nächster Tab
 fr.gtk.gtkNextTab:O_nglet suivant
 it.gtk.gtkNextTab:Scheda _successiva
 nl.gtk.gtkNextTab:Vol_gende tabblad
-en.gtk.gtkNextTabAccel:<ctrl>Right
-de.gtk.gtkNextTabAccel:<ctrl>Right
-fr.gtk.gtkNextTabAccel:<ctrl>Droit
-it.gtk.gtkNextTabAccel:<ctrl>Destra
-nl.gtk.gtkNextTabAccel:<ctrl>Rechterpijltoets
 en.gtk.gtkPrevTab:_Previous tab
 de.gtk.gtkPrevTab:_Vorheriger Tab
 fr.gtk.gtkPrevTab:Onglet _précédent
 it.gtk.gtkPrevTab:Scheda _precedente
 nl.gtk.gtkPrevTab:Vo_rige tabblad
-en.gtk.gtkPrevTabAccel:<ctrl>Left
-de.gtk.gtkPrevTabAccel:<ctrl>Left
-fr.gtk.gtkPrevTabAccel:<ctrl>Gauche
-it.gtk.gtkPrevTabAccel:<ctrl>Sinistra
-nl.gtk.gtkPrevTabAccel:<ctrl>Linkerpijltoets
 en.gtk.gtkCloseTab:_Close tab
 de.gtk.gtkCloseTab:Tab s_chliessen
 fr.gtk.gtkCloseTab:_Fermer l'onglet
 it.gtk.gtkCloseTab:_Chiudi scheda
 nl.gtk.gtkCloseTab:Tabblad _sluiten
-en.gtk.gtkCloseTabAccel:<ctrl>w
-de.gtk.gtkCloseTabAccel:<ctrl>w
-fr.gtk.gtkCloseTabAccel:<ctrl>w
-it.gtk.gtkCloseTabAccel:<ctrl>w
-nl.gtk.gtkCloseTabAccel:<ctrl>w
 
 en.gtk.gtkContents:_Contents…
 de.gtk.gtkContents:_Inhalt
diff --git a/utils/hashtable.c b/utils/hashtable.c
index 3a1711d..4935d6b 100644
--- a/utils/hashtable.c
+++ b/utils/hashtable.c
@@ -28,11 +28,15 @@
  * it that has good coverage along side the other tests.
  */
 
+#include <stdint.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdbool.h>
-#include "utils/hashtable.h"
+#include <zlib.h>
+#include <errno.h>
+
 #include "utils/log.h"
+#include "utils/hashtable.h"
 
 
 struct hash_entry {
@@ -46,6 +50,8 @@ struct hash_table {
        struct hash_entry **chain;
 };
 
+/** maximum length of line for file or inline add */
+#define LINE_BUFFER_SIZE 512
 
 /**
  * Hash a string, returning a 32bit value.  The hash algorithm used is
@@ -75,6 +81,175 @@ static inline unsigned int hash_string_fnv(const char 
*datum, unsigned int *len)
 }
 
 
+
+/**
+ * process a line of input.
+ *
+ * \param hash The hash table to add the line to
+ * \param ln The line to process
+ * \param lnlen The length of \ln
+ * \return NSERROR_OK on success else NSERROR_INVALID
+ */
+static nserror
+process_line(struct hash_table *hash, uint8_t *ln, int lnlen)
+{
+       uint8_t *key;
+       uint8_t *value;
+       uint8_t *colon;
+
+       key = ln; /* set key to start of line */
+       value = ln + lnlen; /* set value to end of line */
+
+       /* skip leading whitespace */
+       while ((key < value) &&
+              ((*key == ' ') || (*key == '\t'))) {
+               key++;
+       }
+
+       /* empty or comment lines */
+       if ((*key == 0) || (*key == '#')) {
+               return NSERROR_OK;
+       }
+
+       /* find first colon as key/value separator */
+       for (colon = key; colon < value; colon++) {
+               if (*colon == ':') {
+                       break;
+               }
+       }
+       if (colon == value) {
+               /* no colon found */
+               return NSERROR_INVALID;
+       }
+
+       *colon = 0;  /* terminate key */
+       value = colon + 1;
+
+       if (hash_add(hash, (char *)key, (char *)value) == false) {
+               NSLOG(netsurf, INFO,
+                     "Unable to add %s:%s to hash table", ln, value);
+               return NSERROR_INVALID;
+       }
+       return NSERROR_OK;
+}
+
+
+/**
+ * adds key/value pairs to a hash from a memory area
+ */
+static nserror
+hash_add_inline_plain(struct hash_table *ht, const uint8_t *data, size_t size)
+{
+       uint8_t s[LINE_BUFFER_SIZE]; /* line buffer */
+       unsigned int slen = 0;
+       nserror res = NSERROR_OK;
+
+       while (size > 0) {
+               s[slen] = *data;
+
+               if (s[slen] == '\n') {
+                       s[slen] = 0; /* replace newline with null termination */
+                       res = process_line(ht, s, slen);
+                       slen = 0;
+                       if (res != NSERROR_OK) {
+                               break;
+                       }
+               } else {
+                       slen++;
+                       if (slen > sizeof s) {
+                               NSLOG(netsurf, INFO, "Overlength line\n");
+                               slen = 0;
+                       }
+               }
+
+               size--;
+               data++;
+       }
+       if (slen > 0) {
+               s[slen] = 0;
+               res = process_line(ht, s, slen);
+       }
+
+       return res;
+}
+
+/**
+ * adds key/value pairs to a hash from a compressed memory area
+ */
+static nserror
+hash_add_inline_gzip(struct hash_table *ht, const uint8_t *data, size_t size)
+{
+       nserror res;
+       int ret; /* zlib return value */
+       z_stream strm;
+       uint8_t s[LINE_BUFFER_SIZE]; /* line buffer */
+       size_t used = 0; /* number of bytes in buffer in use */
+       uint8_t *nl;
+
+       strm.zalloc = Z_NULL;
+       strm.zfree = Z_NULL;
+       strm.opaque = Z_NULL;
+
+       strm.next_in = (uint8_t *)data;
+       strm.avail_in = size;
+
+       ret = inflateInit2(&strm, 32 + MAX_WBITS);
+       if (ret != Z_OK) {
+               NSLOG(netsurf, INFO, "inflateInit returned %d", ret);
+               return NSERROR_INVALID;
+       }
+
+       do {
+               strm.next_out = s + used;
+               strm.avail_out = sizeof(s) - used;
+
+               ret = inflate(&strm, Z_NO_FLUSH);
+               if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
+                       break;
+               }
+
+               used = sizeof(s) - strm.avail_out;
+               while (used > 0) {
+                       /* find nl */
+                       for (nl = &s[0]; nl < &s[used]; nl++) {
+                               if (*nl == '\n') {
+                                       break;
+                               }
+                       }
+                       if (nl == &s[used]) {
+                               /* no nl found */
+                               break;
+                       }
+                       /* found newline */
+                       *nl = 0; /* null terminate line */
+                       res = process_line(ht, &s[0], nl - &s[0]);
+                       if (res != NSERROR_OK) {
+                               inflateEnd(&strm);
+                               return res;
+                       }
+
+                       /* move data down */
+                       memmove(&s[0], nl + 1, used - ((nl + 1) - &s[0]) );
+                       used -= ((nl +1) - &s[0]);
+               }
+               if (used == sizeof(s)) {
+                       /* entire buffer used and no newline */
+                       NSLOG(netsurf, INFO, "Overlength line");
+                       used = 0;
+               }
+       } while (ret != Z_STREAM_END);
+
+       inflateEnd(&strm);
+
+       if (ret != Z_STREAM_END) {
+               NSLOG(netsurf, INFO, "inflate returned %d", ret);
+               return NSERROR_INVALID;
+       }
+       return NSERROR_OK;
+
+}
+
+
 /* exported interface documented in utils/hashtable.h */
 struct hash_table *hash_create(unsigned int chains)
 {
@@ -179,3 +354,51 @@ const char *hash_get(struct hash_table *ht, const char 
*key)
 
        return NULL;
 }
+
+
+
+/* exported interface documented in utils/hashtable.h */
+nserror hash_add_file(struct hash_table *ht, const char *path)
+{
+       nserror res = NSERROR_OK;
+       char s[LINE_BUFFER_SIZE]; /* line buffer */
+       gzFile fp; /* compressed file handle */
+
+       if (path == NULL) {
+               return NSERROR_BAD_PARAMETER;
+       }
+
+       fp = gzopen(path, "r");
+       if (!fp) {
+               NSLOG(netsurf, INFO,
+                     "Unable to open file \"%.100s\": %s", path,
+                     strerror(errno));
+
+               return NSERROR_NOT_FOUND;
+       }
+
+       while (gzgets(fp, s, sizeof s)) {
+               int slen = strlen(s);
+               s[--slen] = 0;  /* remove \n at end */
+
+               res = process_line(ht, (uint8_t *)s, slen);
+               if (res != NSERROR_OK) {
+                       break;
+               }
+       }
+
+       gzclose(fp);
+
+       return res;
+}
+
+
+/* exported interface documented in utils/hashtable.h */
+nserror hash_add_inline(struct hash_table *ht, const uint8_t *data, size_t 
size)
+{
+       if ((data[0]==0x1f) && (data[1] == 0x8b)) {
+               /* gzip header detected */
+               return hash_add_inline_gzip(ht, data, size);
+       }
+       return hash_add_inline_plain(ht, data, size);
+}
diff --git a/utils/hashtable.h b/utils/hashtable.h
index b0e7392..b1c0d5c 100644
--- a/utils/hashtable.h
+++ b/utils/hashtable.h
@@ -29,8 +29,11 @@
 struct hash_table;
 
 /**
- * Create a new hash table, and return a context for it.  The memory 
consumption
- * of a hash table is approximately 8 + (nchains * 12) bytes if it is empty.
+ * Create a new hash table
+ *
+ * Allocate a new hash table and return a context for it.  The memory
+ * consumption of a hash table is approximately 8 + (nchains * 12)
+ * bytes if it is empty.
  *
  * \param chains Number of chains/buckets this hash table will have.  This
  *               should be a prime number, and ideally a prime number just
@@ -41,18 +44,22 @@ struct hash_table;
 struct hash_table *hash_create(unsigned int chains);
 
 /**
- * Destroys a hash table, freeing all memory associated with it.
+ * Destroys a hash table
+ *
+ * Destroy a hash table freeing all memory associated with it.
  *
  * \param ht Hash table to destroy. After the function returns, this
- *            will nolonger be valid.
+ *             will no longer be valid.
  */
 void hash_destroy(struct hash_table *ht);
 
 /**
- * Adds a key/value pair to a hash table.  If the key you're adding is already
- * in the hash table, it does not replace it, but it does take precedent over
- * it.  The old key/value pair will be inaccessable but still in memory until
- * hash_destroy() is called on the hash table.
+ * Adds a key/value pair to a hash table.
+ *
+ * If the key you're adding is already in the hash table, it does not
+ * replace it, but it does take precedent over it.  The old key/value
+ * pair will be inaccessable but still in memory until hash_destroy()
+ * is called on the hash table.
  *
  * \param  ht    The hash table context to add the key/value pair to.
  * \param  key   The key to associate the value with.  A copy is made.
@@ -71,4 +78,34 @@ bool hash_add(struct hash_table *ht, const char *key, const 
char *value);
  */
 const char *hash_get(struct hash_table *ht, const char *key);
 
+/**
+ * Add key/value pairs to a hash table with data from a file
+ *
+ * The file should be formatted as a series of lines terminated with
+ *  newline character. Each line should contain a key/value pair
+ *  separated by a colon. If a line is empty or starts with a #
+ *  character it will be ignored.
+ *
+ * The file may be optionally gzip compressed.
+ *
+ * \param ht The hash table context to add the key/value pairs to.
+ * \param path Path to file with key/value pairs in.
+ * \return NSERROR_OK on success else error code
+ */
+nserror hash_add_file(struct hash_table *ht, const char *path);
+
+/**
+ * Add key/value pairs to a hash table with data from a memory buffer
+ *
+ * The data format is the same as in hash_add_file() but held in memory
+ *
+ * The data may optionally be gzip compressed.
+ *
+ * \param ht The hash table context to add the key/value pairs to.
+ * \param data Source of key/value pairs
+ * \param size length of \a data
+ * \return NSERROR_OK on success else error code
+ */
+nserror hash_add_inline(struct hash_table *ht, const uint8_t *data, size_t 
size);
+
 #endif
diff --git a/utils/messages.c b/utils/messages.c
index e2d45e9..e1e6120 100644
--- a/utils/messages.c
+++ b/utils/messages.c
@@ -45,66 +45,19 @@
 /** The hash table used to store the standard Messages file for the old API */
 static struct hash_table *messages_hash = NULL;
 
-/**
- * process a line of input.
- */
-static nserror
-message_process_line(struct hash_table *hash, uint8_t *ln, int lnlen)
-{
-       uint8_t *value;
-       uint8_t *colon;
-
-       /* empty or comment lines */
-       if (ln[0] == 0 || ln[0] == '#') {
-               return NSERROR_OK;
-       }
-
-       /* find first colon as key/value separator */
-       for (colon = ln; colon < (ln + lnlen); colon++) {
-               if (*colon == ':') {
-                       break;
-               }
-       }
-       if (colon == (ln + lnlen)) {
-               /* no colon found */
-               return NSERROR_INVALID;
-       }
-
-       *colon = 0;  /* terminate key */
-       value = colon + 1;
-
-       if (hash_add(hash, (char *)ln, (char *)value) == false) {
-               NSLOG(netsurf, INFO, "Unable to add %s:%s to hash table", ln,
-                     value);
-               return NSERROR_INVALID;
-       }
-       return NSERROR_OK;
-}
 
 /**
  * Read keys and values from messages file.
  *
  * \param  path  pathname of messages file
- * \param  ctx   reference of hash table to merge with.
+ * \param  ctx   reference of hash table to merge with or NULL to create one.
  * \return NSERROR_OK on sucess and ctx updated or error code on faliure.
  */
 static nserror messages_load_ctx(const char *path, struct hash_table **ctx)
 {
-       char s[400]; /* line buffer */
-       gzFile fp; /* compressed file handle */
        struct hash_table *nctx; /* new context */
-
-       assert(path != NULL);
-
-       fp = gzopen(path, "r");
-       if (!fp) {
-               NSLOG(netsurf, INFO,
-                     "Unable to open messages file \"%.100s\": %s", path,
-                     strerror(errno));
-
-               return NSERROR_NOT_FOUND;
-       }
-
+       nserror res;
+       
        if (*ctx == NULL) {
                nctx = hash_create(HASH_SIZE);
        } else {
@@ -118,40 +71,16 @@ static nserror messages_load_ctx(const char *path, struct 
hash_table **ctx)
                NSLOG(netsurf, INFO,
                      "Unable to create hash table for messages file %s",
                      path);
-               gzclose(fp);
                return NSERROR_NOMEM;
        }
 
-       while (gzgets(fp, s, sizeof s)) {
-               char *colon, *value;
-
-               if (s[0] == 0 || s[0] == '#')
-                       continue;
-
-               s[strlen(s) - 1] = 0;  /* remove \n at end */
-               colon = strchr(s, ':');
-               if (!colon)
-                       continue;
-               *colon = 0;  /* terminate key */
-               value = colon + 1;
-
-               if (hash_add(nctx, s, value) == false) {
-                       NSLOG(netsurf, INFO,
-                             "Unable to add %s:%s to hash table of %s", s,
-                             value, path);
-                       gzclose(fp);
-                       if (*ctx == NULL) {
-                               hash_destroy(nctx);
-                       }
-                       return NSERROR_INVALID;
-               }
-       }
-
-       gzclose(fp);
 
-       *ctx = nctx;
+       res = hash_add_file(nctx, path);
+       if (res == NSERROR_OK) {
+               *ctx = nctx;
+       }
 
-       return NSERROR_OK;
+       return res;
 }
 
 
@@ -203,30 +132,19 @@ static void messages_destroy_ctx(struct hash_table *ctx)
 /* exported interface documented in messages.h */
 nserror messages_add_from_file(const char *path)
 {
-       nserror err;
-
        if (path == NULL) {
                return NSERROR_BAD_PARAMETER;
        }
 
        NSLOG(netsurf, INFO, "Loading Messages from '%s'", path);
 
-       err = messages_load_ctx(path, &messages_hash);
-
-
-       return err;
+       return messages_load_ctx(path, &messages_hash);
 }
 
 
 /* exported interface documented in messages.h */
-nserror messages_add_from_inline(const uint8_t *data, size_t data_size)
+nserror messages_add_from_inline(const uint8_t *data, size_t size)
 {
-       z_stream strm;
-       int ret;
-       uint8_t s[512]; /* line buffer */
-       size_t used = 0; /* number of bytes in buffer in use */
-       uint8_t *nl;
-
        /* ensure the hash table is initialised */
        if (messages_hash == NULL) {
                messages_hash = hash_create(HASH_SIZE);
@@ -235,61 +153,7 @@ nserror messages_add_from_inline(const uint8_t *data, 
size_t data_size)
                NSLOG(netsurf, INFO, "Unable to create hash table");
                return NSERROR_NOMEM;
        }
-
-       strm.zalloc = Z_NULL;
-       strm.zfree = Z_NULL;
-       strm.opaque = Z_NULL;
-
-       strm.next_in = (uint8_t *)data;
-       strm.avail_in = data_size;
-
-       ret = inflateInit2(&strm, 32 + MAX_WBITS);
-       if (ret != Z_OK) {
-               NSLOG(netsurf, INFO, "inflateInit returned %d", ret);
-               return NSERROR_INVALID;
-       }
-
-       do {
-               strm.next_out = s + used;
-               strm.avail_out = sizeof(s) - used;
-
-               ret = inflate(&strm, Z_NO_FLUSH);
-               if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
-                       break;
-               }
-
-               used = sizeof(s) - strm.avail_out;
-               while (used > 0) {
-                       /* find nl */
-                       for (nl = &s[0]; nl < &s[used]; nl++) {
-                               if (*nl == '\n') {
-                                       break;
-                               }
-                       }
-                       if (nl == &s[used]) {
-                               /* no nl found */
-                               break;
-                       }
-                       /* found newline */
-                       *nl = 0; /* null terminate line */
-                       message_process_line(messages_hash, &s[0], nl - &s[0]);
-                       memmove(&s[0], nl + 1, used - ((nl + 1) - &s[0]) );
-                       used -= ((nl +1) - &s[0]);
-               }
-               if (used == sizeof(s)) {
-                       /* entire buffer used and no newline */
-                       NSLOG(netsurf, INFO, "Overlength line");
-                       used = 0;
-               }
-       } while (ret != Z_STREAM_END);
-
-       inflateEnd(&strm);
-
-       if (ret != Z_STREAM_END) {
-               NSLOG(netsurf, INFO, "inflate returned %d", ret);
-               return NSERROR_INVALID;
-       }
-       return NSERROR_OK;
+       return hash_add_inline(messages_hash, data, size);
 }
 
 /* exported interface documented in messages.h */


-- 
NetSurf Browser

_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org

Reply via email to