bof.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /*
  2. * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * on the rights to use, copy, modify, merge, publish, distribute, sub
  8. * license, and/or sell copies of the Software, and to permit persons to whom
  9. * the Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice (including the next
  12. * paragraph) shall be included in all copies or substantial portions of the
  13. * Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
  19. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  20. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  21. * USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. *
  23. * Authors:
  24. * Jerome Glisse
  25. */
  26. #include <errno.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include "bof.h"
  30. /*
  31. * helpers
  32. */
  33. static int bof_entry_grow(bof_t *bof)
  34. {
  35. bof_t **array;
  36. if (bof->array_size < bof->nentry)
  37. return 0;
  38. array = realloc(bof->array, (bof->nentry + 16) * sizeof(void*));
  39. if (array == NULL)
  40. return -ENOMEM;
  41. bof->array = array;
  42. bof->nentry += 16;
  43. return 0;
  44. }
  45. /*
  46. * object
  47. */
  48. bof_t *bof_object(void)
  49. {
  50. bof_t *object;
  51. object = calloc(1, sizeof(bof_t));
  52. if (object == NULL)
  53. return NULL;
  54. object->refcount = 1;
  55. object->type = BOF_TYPE_OBJECT;
  56. object->size = 12;
  57. return object;
  58. }
  59. bof_t *bof_object_get(bof_t *object, const char *keyname)
  60. {
  61. unsigned i;
  62. for (i = 0; i < object->array_size; i += 2) {
  63. if (!strcmp(object->array[i]->value, keyname)) {
  64. return object->array[i + 1];
  65. }
  66. }
  67. return NULL;
  68. }
  69. int bof_object_set(bof_t *object, const char *keyname, bof_t *value)
  70. {
  71. bof_t *key;
  72. int r;
  73. if (object->type != BOF_TYPE_OBJECT)
  74. return -EINVAL;
  75. r = bof_entry_grow(object);
  76. if (r)
  77. return r;
  78. key = bof_string(keyname);
  79. if (key == NULL)
  80. return -ENOMEM;
  81. object->array[object->array_size++] = key;
  82. object->array[object->array_size++] = value;
  83. object->size += value->size;
  84. object->size += key->size;
  85. bof_incref(value);
  86. return 0;
  87. }
  88. /*
  89. * array
  90. */
  91. bof_t *bof_array(void)
  92. {
  93. bof_t *array = bof_object();
  94. if (array == NULL)
  95. return NULL;
  96. array->type = BOF_TYPE_ARRAY;
  97. array->size = 12;
  98. return array;
  99. }
  100. int bof_array_append(bof_t *array, bof_t *value)
  101. {
  102. int r;
  103. if (array->type != BOF_TYPE_ARRAY)
  104. return -EINVAL;
  105. r = bof_entry_grow(array);
  106. if (r)
  107. return r;
  108. array->array[array->array_size++] = value;
  109. array->size += value->size;
  110. bof_incref(value);
  111. return 0;
  112. }
  113. bof_t *bof_array_get(bof_t *bof, unsigned i)
  114. {
  115. if (!bof_is_array(bof) || i >= bof->array_size)
  116. return NULL;
  117. return bof->array[i];
  118. }
  119. unsigned bof_array_size(bof_t *bof)
  120. {
  121. if (!bof_is_array(bof))
  122. return 0;
  123. return bof->array_size;
  124. }
  125. /*
  126. * blob
  127. */
  128. bof_t *bof_blob(unsigned size, void *value)
  129. {
  130. bof_t *blob = bof_object();
  131. if (blob == NULL)
  132. return NULL;
  133. blob->type = BOF_TYPE_BLOB;
  134. blob->value = calloc(1, size);
  135. if (blob->value == NULL) {
  136. bof_decref(blob);
  137. return NULL;
  138. }
  139. blob->size = size;
  140. memcpy(blob->value, value, size);
  141. blob->size += 12;
  142. return blob;
  143. }
  144. unsigned bof_blob_size(bof_t *bof)
  145. {
  146. if (!bof_is_blob(bof))
  147. return 0;
  148. return bof->size - 12;
  149. }
  150. void *bof_blob_value(bof_t *bof)
  151. {
  152. if (!bof_is_blob(bof))
  153. return NULL;
  154. return bof->value;
  155. }
  156. /*
  157. * string
  158. */
  159. bof_t *bof_string(const char *value)
  160. {
  161. bof_t *string = bof_object();
  162. if (string == NULL)
  163. return NULL;
  164. string->type = BOF_TYPE_STRING;
  165. string->size = strlen(value) + 1;
  166. string->value = calloc(1, string->size);
  167. if (string->value == NULL) {
  168. bof_decref(string);
  169. return NULL;
  170. }
  171. strcpy(string->value, value);
  172. string->size += 12;
  173. return string;
  174. }
  175. /*
  176. * int32
  177. */
  178. bof_t *bof_int32(int32_t value)
  179. {
  180. bof_t *int32 = bof_object();
  181. if (int32 == NULL)
  182. return NULL;
  183. int32->type = BOF_TYPE_INT32;
  184. int32->size = 4;
  185. int32->value = calloc(1, int32->size);
  186. if (int32->value == NULL) {
  187. bof_decref(int32);
  188. return NULL;
  189. }
  190. memcpy(int32->value, &value, 4);
  191. int32->size += 12;
  192. return int32;
  193. }
  194. int32_t bof_int32_value(bof_t *bof)
  195. {
  196. return *((uint32_t*)bof->value);
  197. }
  198. /*
  199. * common
  200. */
  201. static void bof_indent(int level)
  202. {
  203. int i;
  204. for (i = 0; i < level; i++)
  205. fprintf(stderr, " ");
  206. }
  207. static void bof_print_bof(bof_t *bof, int level, int entry)
  208. {
  209. bof_indent(level);
  210. if (bof == NULL) {
  211. fprintf(stderr, "--NULL-- for entry %d\n", entry);
  212. return;
  213. }
  214. switch (bof->type) {
  215. case BOF_TYPE_STRING:
  216. fprintf(stderr, "%p string [%s %d]\n", bof, (char*)bof->value, bof->size);
  217. break;
  218. case BOF_TYPE_INT32:
  219. fprintf(stderr, "%p int32 [%d %d]\n", bof, *(int*)bof->value, bof->size);
  220. break;
  221. case BOF_TYPE_BLOB:
  222. fprintf(stderr, "%p blob [%d]\n", bof, bof->size);
  223. break;
  224. case BOF_TYPE_NULL:
  225. fprintf(stderr, "%p null [%d]\n", bof, bof->size);
  226. break;
  227. case BOF_TYPE_OBJECT:
  228. fprintf(stderr, "%p object [%d %d]\n", bof, bof->array_size / 2, bof->size);
  229. break;
  230. case BOF_TYPE_ARRAY:
  231. fprintf(stderr, "%p array [%d %d]\n", bof, bof->array_size, bof->size);
  232. break;
  233. default:
  234. fprintf(stderr, "%p unknown [%d]\n", bof, bof->type);
  235. return;
  236. }
  237. }
  238. static void bof_print_rec(bof_t *bof, int level, int entry)
  239. {
  240. unsigned i;
  241. bof_print_bof(bof, level, entry);
  242. for (i = 0; i < bof->array_size; i++) {
  243. bof_print_rec(bof->array[i], level + 2, i);
  244. }
  245. }
  246. void bof_print(bof_t *bof)
  247. {
  248. bof_print_rec(bof, 0, 0);
  249. }
  250. static int bof_read(bof_t *root, FILE *file, long end, int level)
  251. {
  252. bof_t *bof = NULL;
  253. int r;
  254. if (ftell(file) >= end) {
  255. return 0;
  256. }
  257. r = bof_entry_grow(root);
  258. if (r)
  259. return r;
  260. bof = bof_object();
  261. if (bof == NULL)
  262. return -ENOMEM;
  263. bof->offset = ftell(file);
  264. r = fread(&bof->type, 4, 1, file);
  265. if (r != 1)
  266. goto out_err;
  267. r = fread(&bof->size, 4, 1, file);
  268. if (r != 1)
  269. goto out_err;
  270. r = fread(&bof->array_size, 4, 1, file);
  271. if (r != 1)
  272. goto out_err;
  273. switch (bof->type) {
  274. case BOF_TYPE_STRING:
  275. case BOF_TYPE_INT32:
  276. case BOF_TYPE_BLOB:
  277. bof->value = calloc(1, bof->size - 12);
  278. if (bof->value == NULL) {
  279. goto out_err;
  280. }
  281. r = fread(bof->value, bof->size - 12, 1, file);
  282. if (r != 1) {
  283. fprintf(stderr, "error reading %d\n", bof->size - 12);
  284. goto out_err;
  285. }
  286. break;
  287. case BOF_TYPE_NULL:
  288. return 0;
  289. case BOF_TYPE_OBJECT:
  290. case BOF_TYPE_ARRAY:
  291. r = bof_read(bof, file, bof->offset + bof->size, level + 2);
  292. if (r)
  293. goto out_err;
  294. break;
  295. default:
  296. fprintf(stderr, "invalid type %d\n", bof->type);
  297. goto out_err;
  298. }
  299. root->array[root->centry++] = bof;
  300. return bof_read(root, file, end, level);
  301. out_err:
  302. bof_decref(bof);
  303. return -EINVAL;
  304. }
  305. bof_t *bof_load_file(const char *filename)
  306. {
  307. bof_t *root = bof_object();
  308. int r;
  309. if (root == NULL) {
  310. fprintf(stderr, "%s failed to create root object\n", __func__);
  311. return NULL;
  312. }
  313. root->file = fopen(filename, "r");
  314. if (root->file == NULL)
  315. goto out_err;
  316. r = fseek(root->file, 0L, SEEK_SET);
  317. if (r) {
  318. fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename);
  319. goto out_err;
  320. }
  321. root->offset = ftell(root->file);
  322. r = fread(&root->type, 4, 1, root->file);
  323. if (r != 1)
  324. goto out_err;
  325. r = fread(&root->size, 4, 1, root->file);
  326. if (r != 1)
  327. goto out_err;
  328. r = fread(&root->array_size, 4, 1, root->file);
  329. if (r != 1)
  330. goto out_err;
  331. r = bof_read(root, root->file, root->offset + root->size, 2);
  332. if (r)
  333. goto out_err;
  334. return root;
  335. out_err:
  336. bof_decref(root);
  337. return NULL;
  338. }
  339. void bof_incref(bof_t *bof)
  340. {
  341. bof->refcount++;
  342. }
  343. void bof_decref(bof_t *bof)
  344. {
  345. unsigned i;
  346. if (bof == NULL)
  347. return;
  348. if (--bof->refcount > 0)
  349. return;
  350. for (i = 0; i < bof->array_size; i++) {
  351. bof_decref(bof->array[i]);
  352. bof->array[i] = NULL;
  353. }
  354. bof->array_size = 0;
  355. if (bof->file) {
  356. fclose(bof->file);
  357. bof->file = NULL;
  358. }
  359. free(bof->array);
  360. free(bof->value);
  361. free(bof);
  362. }
  363. static int bof_file_write(bof_t *bof, FILE *file)
  364. {
  365. unsigned i;
  366. int r;
  367. r = fwrite(&bof->type, 4, 1, file);
  368. if (r != 1)
  369. return -EINVAL;
  370. r = fwrite(&bof->size, 4, 1, file);
  371. if (r != 1)
  372. return -EINVAL;
  373. r = fwrite(&bof->array_size, 4, 1, file);
  374. if (r != 1)
  375. return -EINVAL;
  376. switch (bof->type) {
  377. case BOF_TYPE_NULL:
  378. if (bof->size)
  379. return -EINVAL;
  380. break;
  381. case BOF_TYPE_STRING:
  382. case BOF_TYPE_INT32:
  383. case BOF_TYPE_BLOB:
  384. r = fwrite(bof->value, bof->size - 12, 1, file);
  385. if (r != 1)
  386. return -EINVAL;
  387. break;
  388. case BOF_TYPE_OBJECT:
  389. case BOF_TYPE_ARRAY:
  390. for (i = 0; i < bof->array_size; i++) {
  391. r = bof_file_write(bof->array[i], file);
  392. if (r)
  393. return r;
  394. }
  395. break;
  396. default:
  397. return -EINVAL;
  398. }
  399. return 0;
  400. }
  401. int bof_dump_file(bof_t *bof, const char *filename)
  402. {
  403. unsigned i;
  404. int r = 0;
  405. if (bof->file) {
  406. fclose(bof->file);
  407. bof->file = NULL;
  408. }
  409. bof->file = fopen(filename, "w");
  410. if (bof->file == NULL) {
  411. fprintf(stderr, "%s failed to open file %s\n", __func__, filename);
  412. r = -EINVAL;
  413. goto out_err;
  414. }
  415. r = fseek(bof->file, 0L, SEEK_SET);
  416. if (r) {
  417. fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename);
  418. goto out_err;
  419. }
  420. r = fwrite(&bof->type, 4, 1, bof->file);
  421. if (r != 1)
  422. goto out_err;
  423. r = fwrite(&bof->size, 4, 1, bof->file);
  424. if (r != 1)
  425. goto out_err;
  426. r = fwrite(&bof->array_size, 4, 1, bof->file);
  427. if (r != 1)
  428. goto out_err;
  429. for (i = 0; i < bof->array_size; i++) {
  430. r = bof_file_write(bof->array[i], bof->file);
  431. if (r)
  432. return r;
  433. }
  434. out_err:
  435. fclose(bof->file);
  436. bof->file = NULL;
  437. return r;
  438. }