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 /*
32 * helpers
33 */
bof_entry_grow(bof_t * bof)34 static int bof_entry_grow(bof_t *bof)
35 {
36 bof_t **array;
37
38 if (bof->array_size < bof->nentry)
39 return 0;
40 array = realloc(bof->array, (bof->nentry + 16) * sizeof(void*));
41 if (array == NULL)
42 return -ENOMEM;
43 bof->array = array;
44 bof->nentry += 16;
45 return 0;
46 }
47
48 /*
49 * object
50 */
bof_object(void)51 bof_t *bof_object(void)
52 {
53 bof_t *object;
54
55 object = calloc(1, sizeof(bof_t));
56 if (object == NULL)
57 return NULL;
58 object->refcount = 1;
59 object->type = BOF_TYPE_OBJECT;
60 object->size = 12;
61 return object;
62 }
63
bof_object_get(bof_t * object,const char * keyname)64 bof_t *bof_object_get(bof_t *object, const char *keyname)
65 {
66 unsigned i;
67
68 for (i = 0; i < object->array_size; i += 2) {
69 if (!strcmp(object->array[i]->value, keyname)) {
70 return object->array[i + 1];
71 }
72 }
73 return NULL;
74 }
75
bof_object_set(bof_t * object,const char * keyname,bof_t * value)76 int bof_object_set(bof_t *object, const char *keyname, bof_t *value)
77 {
78 bof_t *key;
79 int r;
80
81 if (object->type != BOF_TYPE_OBJECT)
82 return -EINVAL;
83 r = bof_entry_grow(object);
84 if (r)
85 return r;
86 key = bof_string(keyname);
87 if (key == NULL)
88 return -ENOMEM;
89 object->array[object->array_size++] = key;
90 object->array[object->array_size++] = value;
91 object->size += value->size;
92 object->size += key->size;
93 bof_incref(value);
94 return 0;
95 }
96
97 /*
98 * array
99 */
bof_array(void)100 bof_t *bof_array(void)
101 {
102 bof_t *array = bof_object();
103
104 if (array == NULL)
105 return NULL;
106 array->type = BOF_TYPE_ARRAY;
107 array->size = 12;
108 return array;
109 }
110
bof_array_append(bof_t * array,bof_t * value)111 int bof_array_append(bof_t *array, bof_t *value)
112 {
113 int r;
114 if (array->type != BOF_TYPE_ARRAY)
115 return -EINVAL;
116 r = bof_entry_grow(array);
117 if (r)
118 return r;
119 array->array[array->array_size++] = value;
120 array->size += value->size;
121 bof_incref(value);
122 return 0;
123 }
124
bof_array_get(bof_t * bof,unsigned i)125 bof_t *bof_array_get(bof_t *bof, unsigned i)
126 {
127 if (!bof_is_array(bof) || i >= bof->array_size)
128 return NULL;
129 return bof->array[i];
130 }
131
bof_array_size(bof_t * bof)132 unsigned bof_array_size(bof_t *bof)
133 {
134 if (!bof_is_array(bof))
135 return 0;
136 return bof->array_size;
137 }
138
139 /*
140 * blob
141 */
bof_blob(unsigned size,void * value)142 bof_t *bof_blob(unsigned size, void *value)
143 {
144 bof_t *blob = bof_object();
145
146 if (blob == NULL)
147 return NULL;
148 blob->type = BOF_TYPE_BLOB;
149 blob->value = calloc(1, size);
150 if (blob->value == NULL) {
151 bof_decref(blob);
152 return NULL;
153 }
154 blob->size = size;
155 memcpy(blob->value, value, size);
156 blob->size += 12;
157 return blob;
158 }
159
bof_blob_size(bof_t * bof)160 unsigned bof_blob_size(bof_t *bof)
161 {
162 if (!bof_is_blob(bof))
163 return 0;
164 return bof->size - 12;
165 }
166
bof_blob_value(bof_t * bof)167 void *bof_blob_value(bof_t *bof)
168 {
169 if (!bof_is_blob(bof))
170 return NULL;
171 return bof->value;
172 }
173
174 /*
175 * string
176 */
bof_string(const char * value)177 bof_t *bof_string(const char *value)
178 {
179 bof_t *string = bof_object();
180
181 if (string == NULL)
182 return NULL;
183 string->type = BOF_TYPE_STRING;
184 string->size = strlen(value) + 1;
185 string->value = calloc(1, string->size);
186 if (string->value == NULL) {
187 bof_decref(string);
188 return NULL;
189 }
190 strcpy(string->value, value);
191 string->size += 12;
192 return string;
193 }
194
195 /*
196 * int32
197 */
bof_int32(int32_t value)198 bof_t *bof_int32(int32_t value)
199 {
200 bof_t *int32 = bof_object();
201
202 if (int32 == NULL)
203 return NULL;
204 int32->type = BOF_TYPE_INT32;
205 int32->size = 4;
206 int32->value = calloc(1, int32->size);
207 if (int32->value == NULL) {
208 bof_decref(int32);
209 return NULL;
210 }
211 memcpy(int32->value, &value, 4);
212 int32->size += 12;
213 return int32;
214 }
215
bof_int32_value(bof_t * bof)216 int32_t bof_int32_value(bof_t *bof)
217 {
218 return *((uint32_t*)bof->value);
219 }
220
221 /*
222 * common
223 */
bof_indent(int level)224 static void bof_indent(int level)
225 {
226 int i;
227
228 for (i = 0; i < level; i++)
229 fprintf(stderr, " ");
230 }
231
bof_print_bof(bof_t * bof,int level,int entry)232 static void bof_print_bof(bof_t *bof, int level, int entry)
233 {
234 bof_indent(level);
235 if (bof == NULL) {
236 fprintf(stderr, "--NULL-- for entry %d\n", entry);
237 return;
238 }
239 switch (bof->type) {
240 case BOF_TYPE_STRING:
241 fprintf(stderr, "%p string [%s %d]\n", bof, (char*)bof->value, bof->size);
242 break;
243 case BOF_TYPE_INT32:
244 fprintf(stderr, "%p int32 [%d %d]\n", bof, *(int*)bof->value, bof->size);
245 break;
246 case BOF_TYPE_BLOB:
247 fprintf(stderr, "%p blob [%d]\n", bof, bof->size);
248 break;
249 case BOF_TYPE_NULL:
250 fprintf(stderr, "%p null [%d]\n", bof, bof->size);
251 break;
252 case BOF_TYPE_OBJECT:
253 fprintf(stderr, "%p object [%d %d]\n", bof, bof->array_size / 2, bof->size);
254 break;
255 case BOF_TYPE_ARRAY:
256 fprintf(stderr, "%p array [%d %d]\n", bof, bof->array_size, bof->size);
257 break;
258 default:
259 fprintf(stderr, "%p unknown [%d]\n", bof, bof->type);
260 return;
261 }
262 }
263
bof_print_rec(bof_t * bof,int level,int entry)264 static void bof_print_rec(bof_t *bof, int level, int entry)
265 {
266 unsigned i;
267
268 bof_print_bof(bof, level, entry);
269 for (i = 0; i < bof->array_size; i++) {
270 bof_print_rec(bof->array[i], level + 2, i);
271 }
272 }
273
bof_print(bof_t * bof)274 void bof_print(bof_t *bof)
275 {
276 bof_print_rec(bof, 0, 0);
277 }
278
bof_read(bof_t * root,FILE * file,long end,int level)279 static int bof_read(bof_t *root, FILE *file, long end, int level)
280 {
281 bof_t *bof = NULL;
282 int r;
283
284 if (ftell(file) >= end) {
285 return 0;
286 }
287 r = bof_entry_grow(root);
288 if (r)
289 return r;
290 bof = bof_object();
291 if (bof == NULL)
292 return -ENOMEM;
293 bof->offset = ftell(file);
294 r = fread(&bof->type, 4, 1, file);
295 if (r != 1)
296 goto out_err;
297 r = fread(&bof->size, 4, 1, file);
298 if (r != 1)
299 goto out_err;
300 r = fread(&bof->array_size, 4, 1, file);
301 if (r != 1)
302 goto out_err;
303 switch (bof->type) {
304 case BOF_TYPE_STRING:
305 case BOF_TYPE_INT32:
306 case BOF_TYPE_BLOB:
307 bof->value = calloc(1, bof->size - 12);
308 if (bof->value == NULL) {
309 goto out_err;
310 }
311 r = fread(bof->value, bof->size - 12, 1, file);
312 if (r != 1) {
313 fprintf(stderr, "error reading %d\n", bof->size - 12);
314 goto out_err;
315 }
316 break;
317 case BOF_TYPE_NULL:
318 return 0;
319 case BOF_TYPE_OBJECT:
320 case BOF_TYPE_ARRAY:
321 r = bof_read(bof, file, bof->offset + bof->size, level + 2);
322 if (r)
323 goto out_err;
324 break;
325 default:
326 fprintf(stderr, "invalid type %d\n", bof->type);
327 goto out_err;
328 }
329 root->array[root->centry++] = bof;
330 return bof_read(root, file, end, level);
331 out_err:
332 bof_decref(bof);
333 return -EINVAL;
334 }
335
bof_load_file(const char * filename)336 bof_t *bof_load_file(const char *filename)
337 {
338 bof_t *root = bof_object();
339 int r;
340
341 if (root == NULL) {
342 fprintf(stderr, "%s failed to create root object\n", __func__);
343 return NULL;
344 }
345 root->file = fopen(filename, "r");
346 if (root->file == NULL)
347 goto out_err;
348 r = fseek(root->file, 0L, SEEK_SET);
349 if (r) {
350 fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename);
351 goto out_err;
352 }
353 root->offset = ftell(root->file);
354 r = fread(&root->type, 4, 1, root->file);
355 if (r != 1)
356 goto out_err;
357 r = fread(&root->size, 4, 1, root->file);
358 if (r != 1)
359 goto out_err;
360 r = fread(&root->array_size, 4, 1, root->file);
361 if (r != 1)
362 goto out_err;
363 r = bof_read(root, root->file, root->offset + root->size, 2);
364 if (r)
365 goto out_err;
366 return root;
367 out_err:
368 bof_decref(root);
369 return NULL;
370 }
371
bof_incref(bof_t * bof)372 void bof_incref(bof_t *bof)
373 {
374 bof->refcount++;
375 }
376
bof_decref(bof_t * bof)377 void bof_decref(bof_t *bof)
378 {
379 unsigned i;
380
381 if (bof == NULL)
382 return;
383 if (--bof->refcount > 0)
384 return;
385 for (i = 0; i < bof->array_size; i++) {
386 bof_decref(bof->array[i]);
387 bof->array[i] = NULL;
388 }
389 bof->array_size = 0;
390 if (bof->file) {
391 fclose(bof->file);
392 bof->file = NULL;
393 }
394 free(bof->array);
395 free(bof->value);
396 free(bof);
397 }
398
bof_file_write(bof_t * bof,FILE * file)399 static int bof_file_write(bof_t *bof, FILE *file)
400 {
401 unsigned i;
402 int r;
403
404 r = fwrite(&bof->type, 4, 1, file);
405 if (r != 1)
406 return -EINVAL;
407 r = fwrite(&bof->size, 4, 1, file);
408 if (r != 1)
409 return -EINVAL;
410 r = fwrite(&bof->array_size, 4, 1, file);
411 if (r != 1)
412 return -EINVAL;
413 switch (bof->type) {
414 case BOF_TYPE_NULL:
415 if (bof->size)
416 return -EINVAL;
417 break;
418 case BOF_TYPE_STRING:
419 case BOF_TYPE_INT32:
420 case BOF_TYPE_BLOB:
421 r = fwrite(bof->value, bof->size - 12, 1, file);
422 if (r != 1)
423 return -EINVAL;
424 break;
425 case BOF_TYPE_OBJECT:
426 case BOF_TYPE_ARRAY:
427 for (i = 0; i < bof->array_size; i++) {
428 r = bof_file_write(bof->array[i], file);
429 if (r)
430 return r;
431 }
432 break;
433 default:
434 return -EINVAL;
435 }
436 return 0;
437 }
438
bof_dump_file(bof_t * bof,const char * filename)439 int bof_dump_file(bof_t *bof, const char *filename)
440 {
441 unsigned i;
442 int r = 0;
443
444 if (bof->file) {
445 fclose(bof->file);
446 bof->file = NULL;
447 }
448 bof->file = fopen(filename, "w");
449 if (bof->file == NULL) {
450 fprintf(stderr, "%s failed to open file %s\n", __func__, filename);
451 r = -EINVAL;
452 goto out_err;
453 }
454 r = fseek(bof->file, 0L, SEEK_SET);
455 if (r) {
456 fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename);
457 goto out_err;
458 }
459 r = fwrite(&bof->type, 4, 1, bof->file);
460 if (r != 1)
461 goto out_err;
462 r = fwrite(&bof->size, 4, 1, bof->file);
463 if (r != 1)
464 goto out_err;
465 r = fwrite(&bof->array_size, 4, 1, bof->file);
466 if (r != 1)
467 goto out_err;
468 for (i = 0; i < bof->array_size; i++) {
469 r = bof_file_write(bof->array[i], bof->file);
470 if (r)
471 return r;
472 }
473 out_err:
474 fclose(bof->file);
475 bof->file = NULL;
476 return r;
477 }
478