Source
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
+
27
+
28
+
29
+
30
+
31
+
/*
32
+
* helpers
33
+
*/
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
+
*/
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
+
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
+
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
+
*/
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
+
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
+
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
+
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
+
*/
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
+
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
+
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
+
*/
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
+
*/
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
+
216
+
int32_t bof_int32_value(bof_t *bof)
217
+
{
218
+
return *((uint32_t*)bof->value);
219
+
}
220
+
221
+
/*
222
+
* common
223
+
*/
224
+
static void bof_indent(int level)
225
+
{
226
+
int i;
227
+
228
+
for (i = 0; i < level; i++)
229
+
fprintf(stderr, " ");
230
+
}
231
+
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
+
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
+
274
+
void bof_print(bof_t *bof)
275
+
{
276
+
bof_print_rec(bof, 0, 0);
277
+
}
278
+
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
+
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
+
372
+
void bof_incref(bof_t *bof)
373
+
{
374
+
bof->refcount++;
375
+
}
376
+
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
+
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
+
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
+
}