template_lmo.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /*
  2. * lmo - Lua Machine Objects - Base functions
  3. *
  4. * Copyright (C) 2009-2010 Jo-Philipp Wich <jow@openwrt.org>
  5. * Copyright (C) 2018 Matthias Schiffer <mschiffer@universe-factory.net>
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. #include "template_lmo.h"
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <stdint.h>
  23. #include <string.h>
  24. #include <fcntl.h>
  25. #include <sys/stat.h>
  26. #include <sys/mman.h>
  27. #include <arpa/inet.h>
  28. #include <unistd.h>
  29. #include <errno.h>
  30. #include <fnmatch.h>
  31. #include <dirent.h>
  32. #include <ctype.h>
  33. #include <limits.h>
  34. struct lmo_entry {
  35. uint32_t key_id;
  36. uint32_t val_id;
  37. uint32_t offset;
  38. uint32_t length;
  39. } __attribute__((packed));
  40. typedef struct lmo_entry lmo_entry_t;
  41. struct lmo_archive {
  42. int fd;
  43. int length;
  44. uint32_t size;
  45. lmo_entry_t *index;
  46. char *mmap;
  47. char *end;
  48. struct lmo_archive *next;
  49. };
  50. typedef struct lmo_archive lmo_archive_t;
  51. struct lmo_catalog {
  52. char lang[6];
  53. struct lmo_archive *archives;
  54. struct lmo_catalog *next;
  55. };
  56. typedef struct lmo_catalog lmo_catalog_t;
  57. /*
  58. * Hash function from http://www.azillionmonkeys.com/qed/hash.html
  59. * Copyright (C) 2004-2008 by Paul Hsieh
  60. */
  61. static inline uint16_t get_le16(const uint8_t *d) {
  62. return (((uint16_t)d[1]) << 8) | d[0];
  63. }
  64. static uint32_t sfh_hash(const void *input, size_t len)
  65. {
  66. const uint8_t *data = input;
  67. uint32_t hash = len, tmp;
  68. /* Main loop */
  69. for (; len > 3; len -= 4) {
  70. hash += get_le16(data);
  71. tmp = (get_le16(data+2) << 11) ^ hash;
  72. hash = (hash << 16) ^ tmp;
  73. data += 4;
  74. hash += hash >> 11;
  75. }
  76. /* Handle end cases */
  77. switch (len) {
  78. case 3: hash += get_le16(data);
  79. hash ^= hash << 16;
  80. hash ^= data[2] << 18;
  81. hash += hash >> 11;
  82. break;
  83. case 2: hash += get_le16(data);
  84. hash ^= hash << 11;
  85. hash += hash >> 17;
  86. break;
  87. case 1: hash += *data;
  88. hash ^= hash << 10;
  89. hash += hash >> 1;
  90. }
  91. /* Force "avalanching" of final 127 bits */
  92. hash ^= hash << 3;
  93. hash += hash >> 5;
  94. hash ^= hash << 4;
  95. hash += hash >> 17;
  96. hash ^= hash << 25;
  97. hash += hash >> 6;
  98. return hash;
  99. }
  100. static lmo_archive_t * lmo_open(const char *file)
  101. {
  102. int in = -1;
  103. uint32_t idx_offset = 0;
  104. struct stat s;
  105. lmo_archive_t *ar = NULL;
  106. if ((in = open(file, O_RDONLY|O_CLOEXEC)) == -1)
  107. goto err;
  108. if (fstat(in, &s) == -1)
  109. goto err;
  110. if ((ar = calloc(1, sizeof(*ar))) != NULL) {
  111. ar->fd = in;
  112. ar->size = s.st_size;
  113. if ((ar->mmap = mmap(NULL, ar->size, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED)
  114. goto err;
  115. idx_offset = ntohl(*((const uint32_t *)
  116. (ar->mmap + ar->size - sizeof(uint32_t))));
  117. if (idx_offset >= ar->size)
  118. goto err;
  119. ar->index = (lmo_entry_t *)(ar->mmap + idx_offset);
  120. ar->length = (ar->size - idx_offset - sizeof(uint32_t)) / sizeof(lmo_entry_t);
  121. ar->end = ar->mmap + ar->size;
  122. return ar;
  123. }
  124. err:
  125. if (in > -1)
  126. close(in);
  127. if (ar != NULL)
  128. {
  129. if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED))
  130. munmap(ar->mmap, ar->size);
  131. free(ar);
  132. }
  133. return NULL;
  134. }
  135. static lmo_catalog_t *_lmo_catalogs;
  136. static lmo_catalog_t *_lmo_active_catalog;
  137. int lmo_load_catalog(const char *lang, const char *dir)
  138. {
  139. DIR *dh = NULL;
  140. char pattern[16];
  141. char path[PATH_MAX];
  142. struct dirent *de = NULL;
  143. lmo_archive_t *ar = NULL;
  144. lmo_catalog_t *cat = NULL;
  145. if (!lmo_change_catalog(lang))
  146. return 0;
  147. if (!dir || !(dh = opendir(dir)))
  148. goto err;
  149. if (!(cat = calloc(1, sizeof(*cat))))
  150. goto err;
  151. snprintf(cat->lang, sizeof(cat->lang), "%s", lang);
  152. snprintf(pattern, sizeof(pattern), "*.%s.lmo", lang);
  153. while ((de = readdir(dh)) != NULL)
  154. {
  155. if (!fnmatch(pattern, de->d_name, 0))
  156. {
  157. snprintf(path, sizeof(path), "%s/%s", dir, de->d_name);
  158. ar = lmo_open(path);
  159. if (ar)
  160. {
  161. ar->next = cat->archives;
  162. cat->archives = ar;
  163. }
  164. }
  165. }
  166. closedir(dh);
  167. cat->next = _lmo_catalogs;
  168. _lmo_catalogs = cat;
  169. if (!_lmo_active_catalog)
  170. _lmo_active_catalog = cat;
  171. return 0;
  172. err:
  173. if (dh) closedir(dh);
  174. if (cat) free(cat);
  175. return -1;
  176. }
  177. int lmo_change_catalog(const char *lang)
  178. {
  179. lmo_catalog_t *cat;
  180. for (cat = _lmo_catalogs; cat; cat = cat->next)
  181. {
  182. if (!strncmp(cat->lang, lang, sizeof(cat->lang)))
  183. {
  184. _lmo_active_catalog = cat;
  185. return 0;
  186. }
  187. }
  188. return -1;
  189. }
  190. static lmo_entry_t * lmo_find_entry(lmo_archive_t *ar, uint32_t hash)
  191. {
  192. unsigned int m, l, r;
  193. uint32_t k;
  194. l = 0;
  195. r = ar->length - 1;
  196. while (1)
  197. {
  198. m = l + ((r - l) / 2);
  199. if (r < l)
  200. break;
  201. k = ntohl(ar->index[m].key_id);
  202. if (k == hash)
  203. return &ar->index[m];
  204. if (k > hash)
  205. {
  206. if (!m)
  207. break;
  208. r = m - 1;
  209. }
  210. else
  211. {
  212. l = m + 1;
  213. }
  214. }
  215. return NULL;
  216. }
  217. int lmo_translate(const char *key, size_t keylen, char **out, size_t *outlen)
  218. {
  219. uint32_t hash;
  220. lmo_entry_t *e;
  221. lmo_archive_t *ar;
  222. if (!key || !_lmo_active_catalog)
  223. return -2;
  224. hash = sfh_hash(key, keylen);
  225. for (ar = _lmo_active_catalog->archives; ar; ar = ar->next)
  226. {
  227. if ((e = lmo_find_entry(ar, hash)) != NULL)
  228. {
  229. *out = ar->mmap + ntohl(e->offset);
  230. *outlen = ntohl(e->length);
  231. return 0;
  232. }
  233. }
  234. return -1;
  235. }