diff --git a/package/gluon-web/src/template_lmo.c b/package/gluon-web/src/template_lmo.c index c959f17d..6cab6274 100644 --- a/package/gluon-web/src/template_lmo.c +++ b/package/gluon-web/src/template_lmo.c @@ -19,19 +19,18 @@ #include "template_lmo.h" -#include -#include -#include -#include -#include #include #include + #include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include #include @@ -46,12 +45,10 @@ typedef struct lmo_entry lmo_entry_t; struct lmo_archive { - int fd; - int length; - uint32_t size; - lmo_entry_t *index; - char *mmap; - char *end; + size_t length; + const lmo_entry_t *index; + char *data; + const char *end; struct lmo_archive *next; }; @@ -66,14 +63,24 @@ struct lmo_catalog { typedef struct lmo_catalog lmo_catalog_t; + +static inline uint16_t get_le16(const void *data) { + const uint8_t *d = data; + return (((uint16_t)d[1]) << 8) | d[0]; +} + +static inline uint32_t get_be32(const void *data) { + const uint8_t *d = data; + return (((uint32_t)d[0]) << 24) + | (((uint32_t)d[1]) << 16) + | (((uint32_t)d[2]) << 8) + | d[3]; +} + /* * Hash function from http://www.azillionmonkeys.com/qed/hash.html * Copyright (C) 2004-2008 by Paul Hsieh */ -static inline uint16_t get_le16(const uint8_t *d) { - return (((uint16_t)d[1]) << 8) | d[0]; -} - static uint32_t sfh_hash(const void *input, size_t len) { const uint8_t *data = input; @@ -117,47 +124,40 @@ static uint32_t sfh_hash(const void *input, size_t len) static lmo_archive_t * lmo_open(const char *file) { - int in = -1; - uint32_t idx_offset = 0; + int fd = -1; + lmo_archive_t *ar = NULL; struct stat s; - lmo_archive_t *ar = NULL; - - if ((in = open(file, O_RDONLY|O_CLOEXEC)) == -1) + if ((fd = open(file, O_RDONLY|O_CLOEXEC)) == -1) goto err; - if (fstat(in, &s) == -1) + if (fstat(fd, &s) == -1) goto err; if ((ar = calloc(1, sizeof(*ar))) != NULL) { - - ar->fd = in; - ar->size = s.st_size; - - if ((ar->mmap = mmap(NULL, ar->size, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED) + if ((ar->data = mmap(NULL, s.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) goto err; - idx_offset = ntohl(*((const uint32_t *) - (ar->mmap + ar->size - sizeof(uint32_t)))); + ar->end = ar->data + s.st_size; - if (idx_offset >= ar->size) + uint32_t idx_offset = get_be32(ar->end - sizeof(uint32_t)); + ar->index = (const lmo_entry_t *)(ar->data + idx_offset); + + if ((const char *)ar->index > (ar->end - sizeof(uint32_t))) goto err; - ar->index = (lmo_entry_t *)(ar->mmap + idx_offset); - ar->length = (ar->size - idx_offset - sizeof(uint32_t)) / sizeof(lmo_entry_t); - ar->end = ar->mmap + ar->size; + ar->length = (ar->end - sizeof(uint32_t) - (const char *)ar->index) / sizeof(lmo_entry_t); return ar; } err: - if (in > -1) - close(in); + if (fd >= 0) + close(fd); - if (ar != NULL) - { - if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED)) - munmap(ar->mmap, ar->size); + if (ar != NULL) { + if ((ar->data != NULL) && (ar->data != MAP_FAILED)) + munmap(ar->data, ar->end - ar->data); free(ar); } @@ -166,10 +166,24 @@ err: } -static lmo_catalog_t *_lmo_catalogs; -static lmo_catalog_t *_lmo_active_catalog; +static lmo_catalog_t *lmo_catalogs; +static lmo_catalog_t *lmo_active_catalog; -int lmo_load_catalog(const char *lang, const char *dir) +bool lmo_change_catalog(const char *lang) +{ + lmo_catalog_t *cat; + + for (cat = lmo_catalogs; cat; cat = cat->next) { + if (!strncmp(cat->lang, lang, sizeof(cat->lang))) { + lmo_active_catalog = cat; + return true; + } + } + + return false; +} + +bool lmo_load_catalog(const char *lang, const char *dir) { DIR *dh = NULL; char pattern[16]; @@ -179,10 +193,10 @@ int lmo_load_catalog(const char *lang, const char *dir) lmo_archive_t *ar = NULL; lmo_catalog_t *cat = NULL; - if (!lmo_change_catalog(lang)) - return 0; + if (lmo_change_catalog(lang)) + return true; - if (!dir || !(dh = opendir(dir))) + if (!(dh = opendir(dir))) goto err; if (!(cat = calloc(1, sizeof(*cat)))) @@ -191,15 +205,12 @@ int lmo_load_catalog(const char *lang, const char *dir) snprintf(cat->lang, sizeof(cat->lang), "%s", lang); snprintf(pattern, sizeof(pattern), "*.%s.lmo", lang); - while ((de = readdir(dh)) != NULL) - { - if (!fnmatch(pattern, de->d_name, 0)) - { + while ((de = readdir(dh)) != NULL) { + if (!fnmatch(pattern, de->d_name, 0)) { snprintf(path, sizeof(path), "%s/%s", dir, de->d_name); ar = lmo_open(path); - if (ar) - { + if (ar) { ar->next = cat->archives; cat->archives = ar; } @@ -208,93 +219,62 @@ int lmo_load_catalog(const char *lang, const char *dir) closedir(dh); - cat->next = _lmo_catalogs; - _lmo_catalogs = cat; + cat->next = lmo_catalogs; + lmo_catalogs = cat; - if (!_lmo_active_catalog) - _lmo_active_catalog = cat; + lmo_active_catalog = cat; - return 0; + return true; err: - if (dh) closedir(dh); - if (cat) free(cat); + if (dh) + closedir(dh); + free(cat); - return -1; + return false; } -int lmo_change_catalog(const char *lang) +static int lmo_compare_entry(const void *a, const void *b) { - lmo_catalog_t *cat; + const lmo_entry_t *ea = a, *eb = b; + uint32_t ka = ntohl(ea->key_id), kb = ntohl(eb->key_id); - for (cat = _lmo_catalogs; cat; cat = cat->next) - { - if (!strncmp(cat->lang, lang, sizeof(cat->lang))) - { - _lmo_active_catalog = cat; - return 0; - } + if (ka < kb) + return -1; + else if (ka > kb) + return 1; + else + return 0; +} + +static const lmo_entry_t * lmo_find_entry(const lmo_archive_t *ar, uint32_t hash) +{ + lmo_entry_t key; + key.key_id = htonl(hash); + + return bsearch(&key, ar->index, ar->length, sizeof(lmo_entry_t), lmo_compare_entry); +} + +bool lmo_translate(const char *key, size_t keylen, char **out, size_t *outlen) +{ + if (!lmo_active_catalog) + return false; + + uint32_t hash = sfh_hash(key, keylen); + + for (const lmo_archive_t *ar = lmo_active_catalog->archives; ar; ar = ar->next) { + const lmo_entry_t *e = lmo_find_entry(ar, hash); + if (!e) + continue; + + *out = ar->data + ntohl(e->offset); + *outlen = ntohl(e->length); + + if (*out + *outlen > ar->end) + continue; + + return true; } - return -1; -} - -static lmo_entry_t * lmo_find_entry(lmo_archive_t *ar, uint32_t hash) -{ - unsigned int m, l, r; - uint32_t k; - - l = 0; - r = ar->length - 1; - - while (1) - { - m = l + ((r - l) / 2); - - if (r < l) - break; - - k = ntohl(ar->index[m].key_id); - - if (k == hash) - return &ar->index[m]; - - if (k > hash) - { - if (!m) - break; - - r = m - 1; - } - else - { - l = m + 1; - } - } - - return NULL; -} - -int lmo_translate(const char *key, size_t keylen, char **out, size_t *outlen) -{ - uint32_t hash; - lmo_entry_t *e; - lmo_archive_t *ar; - - if (!key || !_lmo_active_catalog) - return -2; - - hash = sfh_hash(key, keylen); - - for (ar = _lmo_active_catalog->archives; ar; ar = ar->next) - { - if ((e = lmo_find_entry(ar, hash)) != NULL) - { - *out = ar->mmap + ntohl(e->offset); - *outlen = ntohl(e->length); - return 0; - } - } - - return -1; + return false; } diff --git a/package/gluon-web/src/template_lmo.h b/package/gluon-web/src/template_lmo.h index bd545597..c5682509 100644 --- a/package/gluon-web/src/template_lmo.h +++ b/package/gluon-web/src/template_lmo.h @@ -20,11 +20,11 @@ #ifndef _TEMPLATE_LMO_H_ #define _TEMPLATE_LMO_H_ +#include #include -int lmo_load_catalog(const char *lang, const char *dir); -int lmo_change_catalog(const char *lang); -int lmo_translate(const char *key, size_t keylen, char **out, size_t *outlen); +bool lmo_load_catalog(const char *lang, const char *dir); +bool lmo_translate(const char *key, size_t keylen, char **out, size_t *outlen); #endif diff --git a/package/gluon-web/src/template_lualib.c b/package/gluon-web/src/template_lualib.c index 88d58cda..dc8ca666 100644 --- a/package/gluon-web/src/template_lualib.c +++ b/package/gluon-web/src/template_lualib.c @@ -92,8 +92,8 @@ static int template_L_pcdata(lua_State *L) static int template_L_load_catalog(lua_State *L) { const char *lang = luaL_optstring(L, 1, "en"); - const char *dir = luaL_optstring(L, 2, NULL); - lua_pushboolean(L, !lmo_load_catalog(lang, dir)); + const char *dir = luaL_checkstring(L, 2); + lua_pushboolean(L, lmo_load_catalog(lang, dir)); return 1; } @@ -103,19 +103,12 @@ static int template_L_translate(lua_State *L) { size_t trlen; const char *key = luaL_checklstring(L, 1, &len); - switch (lmo_translate(key, len, &tr, &trlen)) - { - case 0: - lua_pushlstring(L, tr, trlen); - return 1; + if (lmo_translate(key, len, &tr, &trlen)) + lua_pushlstring(L, tr, trlen); + else + lua_pushnil(L); - case -1: - return 0; - } - - lua_pushnil(L); - lua_pushstring(L, "no catalog loaded"); - return 2; + return 1; } diff --git a/package/gluon-web/src/template_utils.c b/package/gluon-web/src/template_utils.c index c03cfa10..5f4211fc 100644 --- a/package/gluon-web/src/template_utils.c +++ b/package/gluon-web/src/template_utils.c @@ -359,7 +359,7 @@ void luastr_translate(struct template_buffer *out, const char *s, size_t l, bool char *tr; size_t trlen; - if (!lmo_translate(s, l, &tr, &trlen)) + if (lmo_translate(s, l, &tr, &trlen)) luastr_escape(out, tr, trlen, escape_xml); else luastr_escape(out, s, l, escape_xml);