113d1d17dSmrg/* 213d1d17dSmrg * Copyright 2010 Jerome Glisse <glisse@freedesktop.org> 313d1d17dSmrg * 413d1d17dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 513d1d17dSmrg * copy of this software and associated documentation files (the "Software"), 613d1d17dSmrg * to deal in the Software without restriction, including without limitation 713d1d17dSmrg * on the rights to use, copy, modify, merge, publish, distribute, sub 813d1d17dSmrg * license, and/or sell copies of the Software, and to permit persons to whom 913d1d17dSmrg * the Software is furnished to do so, subject to the following conditions: 1013d1d17dSmrg * 1113d1d17dSmrg * The above copyright notice and this permission notice (including the next 1213d1d17dSmrg * paragraph) shall be included in all copies or substantial portions of the 1313d1d17dSmrg * Software. 1413d1d17dSmrg * 1513d1d17dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1613d1d17dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1713d1d17dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 1813d1d17dSmrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 1913d1d17dSmrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2013d1d17dSmrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2113d1d17dSmrg * USE OR OTHER DEALINGS IN THE SOFTWARE. 2213d1d17dSmrg * 2313d1d17dSmrg * Authors: 2413d1d17dSmrg * Jerome Glisse 2513d1d17dSmrg */ 2613d1d17dSmrg#include <errno.h> 2713d1d17dSmrg#include <stdlib.h> 2813d1d17dSmrg#include <string.h> 2913d1d17dSmrg#include "bof.h" 3013d1d17dSmrg 3113d1d17dSmrg/* 3213d1d17dSmrg * helpers 3313d1d17dSmrg */ 3413d1d17dSmrgstatic int bof_entry_grow(bof_t *bof) 3513d1d17dSmrg{ 3613d1d17dSmrg bof_t **array; 3713d1d17dSmrg 3813d1d17dSmrg if (bof->array_size < bof->nentry) 3913d1d17dSmrg return 0; 4013d1d17dSmrg array = realloc(bof->array, (bof->nentry + 16) * sizeof(void*)); 4113d1d17dSmrg if (array == NULL) 4213d1d17dSmrg return -ENOMEM; 4313d1d17dSmrg bof->array = array; 4413d1d17dSmrg bof->nentry += 16; 4513d1d17dSmrg return 0; 4613d1d17dSmrg} 4713d1d17dSmrg 4813d1d17dSmrg/* 4913d1d17dSmrg * object 5013d1d17dSmrg */ 5113d1d17dSmrgbof_t *bof_object(void) 5213d1d17dSmrg{ 5313d1d17dSmrg bof_t *object; 5413d1d17dSmrg 5513d1d17dSmrg object = calloc(1, sizeof(bof_t)); 5613d1d17dSmrg if (object == NULL) 5713d1d17dSmrg return NULL; 5813d1d17dSmrg object->refcount = 1; 5913d1d17dSmrg object->type = BOF_TYPE_OBJECT; 6013d1d17dSmrg object->size = 12; 6113d1d17dSmrg return object; 6213d1d17dSmrg} 6313d1d17dSmrg 6413d1d17dSmrgbof_t *bof_object_get(bof_t *object, const char *keyname) 6513d1d17dSmrg{ 6613d1d17dSmrg unsigned i; 6713d1d17dSmrg 6813d1d17dSmrg for (i = 0; i < object->array_size; i += 2) { 6913d1d17dSmrg if (!strcmp(object->array[i]->value, keyname)) { 7013d1d17dSmrg return object->array[i + 1]; 7113d1d17dSmrg } 7213d1d17dSmrg } 7313d1d17dSmrg return NULL; 7413d1d17dSmrg} 7513d1d17dSmrg 7613d1d17dSmrgint bof_object_set(bof_t *object, const char *keyname, bof_t *value) 7713d1d17dSmrg{ 7813d1d17dSmrg bof_t *key; 7913d1d17dSmrg int r; 8013d1d17dSmrg 8113d1d17dSmrg if (object->type != BOF_TYPE_OBJECT) 8213d1d17dSmrg return -EINVAL; 8313d1d17dSmrg r = bof_entry_grow(object); 8413d1d17dSmrg if (r) 8513d1d17dSmrg return r; 8613d1d17dSmrg key = bof_string(keyname); 8713d1d17dSmrg if (key == NULL) 8813d1d17dSmrg return -ENOMEM; 8913d1d17dSmrg object->array[object->array_size++] = key; 9013d1d17dSmrg object->array[object->array_size++] = value; 9113d1d17dSmrg object->size += value->size; 9213d1d17dSmrg object->size += key->size; 9313d1d17dSmrg bof_incref(value); 9413d1d17dSmrg return 0; 9513d1d17dSmrg} 9613d1d17dSmrg 9713d1d17dSmrg/* 9813d1d17dSmrg * array 9913d1d17dSmrg */ 10013d1d17dSmrgbof_t *bof_array(void) 10113d1d17dSmrg{ 10213d1d17dSmrg bof_t *array = bof_object(); 10313d1d17dSmrg 10413d1d17dSmrg if (array == NULL) 10513d1d17dSmrg return NULL; 10613d1d17dSmrg array->type = BOF_TYPE_ARRAY; 10713d1d17dSmrg array->size = 12; 10813d1d17dSmrg return array; 10913d1d17dSmrg} 11013d1d17dSmrg 11113d1d17dSmrgint bof_array_append(bof_t *array, bof_t *value) 11213d1d17dSmrg{ 11313d1d17dSmrg int r; 11413d1d17dSmrg if (array->type != BOF_TYPE_ARRAY) 11513d1d17dSmrg return -EINVAL; 11613d1d17dSmrg r = bof_entry_grow(array); 11713d1d17dSmrg if (r) 11813d1d17dSmrg return r; 11913d1d17dSmrg array->array[array->array_size++] = value; 12013d1d17dSmrg array->size += value->size; 12113d1d17dSmrg bof_incref(value); 12213d1d17dSmrg return 0; 12313d1d17dSmrg} 12413d1d17dSmrg 12513d1d17dSmrgbof_t *bof_array_get(bof_t *bof, unsigned i) 12613d1d17dSmrg{ 12713d1d17dSmrg if (!bof_is_array(bof) || i >= bof->array_size) 12813d1d17dSmrg return NULL; 12913d1d17dSmrg return bof->array[i]; 13013d1d17dSmrg} 13113d1d17dSmrg 13213d1d17dSmrgunsigned bof_array_size(bof_t *bof) 13313d1d17dSmrg{ 13413d1d17dSmrg if (!bof_is_array(bof)) 13513d1d17dSmrg return 0; 13613d1d17dSmrg return bof->array_size; 13713d1d17dSmrg} 13813d1d17dSmrg 13913d1d17dSmrg/* 14013d1d17dSmrg * blob 14113d1d17dSmrg */ 14213d1d17dSmrgbof_t *bof_blob(unsigned size, void *value) 14313d1d17dSmrg{ 14413d1d17dSmrg bof_t *blob = bof_object(); 14513d1d17dSmrg 14613d1d17dSmrg if (blob == NULL) 14713d1d17dSmrg return NULL; 14813d1d17dSmrg blob->type = BOF_TYPE_BLOB; 14913d1d17dSmrg blob->value = calloc(1, size); 15013d1d17dSmrg if (blob->value == NULL) { 15113d1d17dSmrg bof_decref(blob); 15213d1d17dSmrg return NULL; 15313d1d17dSmrg } 15413d1d17dSmrg blob->size = size; 15513d1d17dSmrg memcpy(blob->value, value, size); 15613d1d17dSmrg blob->size += 12; 15713d1d17dSmrg return blob; 15813d1d17dSmrg} 15913d1d17dSmrg 16013d1d17dSmrgunsigned bof_blob_size(bof_t *bof) 16113d1d17dSmrg{ 16213d1d17dSmrg if (!bof_is_blob(bof)) 16313d1d17dSmrg return 0; 16413d1d17dSmrg return bof->size - 12; 16513d1d17dSmrg} 16613d1d17dSmrg 16713d1d17dSmrgvoid *bof_blob_value(bof_t *bof) 16813d1d17dSmrg{ 16913d1d17dSmrg if (!bof_is_blob(bof)) 17013d1d17dSmrg return NULL; 17113d1d17dSmrg return bof->value; 17213d1d17dSmrg} 17313d1d17dSmrg 17413d1d17dSmrg/* 17513d1d17dSmrg * string 17613d1d17dSmrg */ 17713d1d17dSmrgbof_t *bof_string(const char *value) 17813d1d17dSmrg{ 17913d1d17dSmrg bof_t *string = bof_object(); 18013d1d17dSmrg 18113d1d17dSmrg if (string == NULL) 18213d1d17dSmrg return NULL; 18313d1d17dSmrg string->type = BOF_TYPE_STRING; 18413d1d17dSmrg string->size = strlen(value) + 1; 18513d1d17dSmrg string->value = calloc(1, string->size); 18613d1d17dSmrg if (string->value == NULL) { 18713d1d17dSmrg bof_decref(string); 18813d1d17dSmrg return NULL; 18913d1d17dSmrg } 19013d1d17dSmrg strcpy(string->value, value); 19113d1d17dSmrg string->size += 12; 19213d1d17dSmrg return string; 19313d1d17dSmrg} 19413d1d17dSmrg 19513d1d17dSmrg/* 19613d1d17dSmrg * int32 19713d1d17dSmrg */ 19813d1d17dSmrgbof_t *bof_int32(int32_t value) 19913d1d17dSmrg{ 20013d1d17dSmrg bof_t *int32 = bof_object(); 20113d1d17dSmrg 20213d1d17dSmrg if (int32 == NULL) 20313d1d17dSmrg return NULL; 20413d1d17dSmrg int32->type = BOF_TYPE_INT32; 20513d1d17dSmrg int32->size = 4; 20613d1d17dSmrg int32->value = calloc(1, int32->size); 20713d1d17dSmrg if (int32->value == NULL) { 20813d1d17dSmrg bof_decref(int32); 20913d1d17dSmrg return NULL; 21013d1d17dSmrg } 21113d1d17dSmrg memcpy(int32->value, &value, 4); 21213d1d17dSmrg int32->size += 12; 21313d1d17dSmrg return int32; 21413d1d17dSmrg} 21513d1d17dSmrg 21613d1d17dSmrgint32_t bof_int32_value(bof_t *bof) 21713d1d17dSmrg{ 21813d1d17dSmrg return *((uint32_t*)bof->value); 21913d1d17dSmrg} 22013d1d17dSmrg 22113d1d17dSmrg/* 22213d1d17dSmrg * common 22313d1d17dSmrg */ 22413d1d17dSmrgstatic void bof_indent(int level) 22513d1d17dSmrg{ 22613d1d17dSmrg int i; 22713d1d17dSmrg 22813d1d17dSmrg for (i = 0; i < level; i++) 22913d1d17dSmrg fprintf(stderr, " "); 23013d1d17dSmrg} 23113d1d17dSmrg 23213d1d17dSmrgstatic void bof_print_bof(bof_t *bof, int level, int entry) 23313d1d17dSmrg{ 23413d1d17dSmrg bof_indent(level); 23513d1d17dSmrg if (bof == NULL) { 23613d1d17dSmrg fprintf(stderr, "--NULL-- for entry %d\n", entry); 23713d1d17dSmrg return; 23813d1d17dSmrg } 23913d1d17dSmrg switch (bof->type) { 24013d1d17dSmrg case BOF_TYPE_STRING: 24113d1d17dSmrg fprintf(stderr, "%p string [%s %d]\n", bof, (char*)bof->value, bof->size); 24213d1d17dSmrg break; 24313d1d17dSmrg case BOF_TYPE_INT32: 24413d1d17dSmrg fprintf(stderr, "%p int32 [%d %d]\n", bof, *(int*)bof->value, bof->size); 24513d1d17dSmrg break; 24613d1d17dSmrg case BOF_TYPE_BLOB: 24713d1d17dSmrg fprintf(stderr, "%p blob [%d]\n", bof, bof->size); 24813d1d17dSmrg break; 24913d1d17dSmrg case BOF_TYPE_NULL: 25013d1d17dSmrg fprintf(stderr, "%p null [%d]\n", bof, bof->size); 25113d1d17dSmrg break; 25213d1d17dSmrg case BOF_TYPE_OBJECT: 25313d1d17dSmrg fprintf(stderr, "%p object [%d %d]\n", bof, bof->array_size / 2, bof->size); 25413d1d17dSmrg break; 25513d1d17dSmrg case BOF_TYPE_ARRAY: 25613d1d17dSmrg fprintf(stderr, "%p array [%d %d]\n", bof, bof->array_size, bof->size); 25713d1d17dSmrg break; 25813d1d17dSmrg default: 25913d1d17dSmrg fprintf(stderr, "%p unknown [%d]\n", bof, bof->type); 26013d1d17dSmrg return; 26113d1d17dSmrg } 26213d1d17dSmrg} 26313d1d17dSmrg 26413d1d17dSmrgstatic void bof_print_rec(bof_t *bof, int level, int entry) 26513d1d17dSmrg{ 26613d1d17dSmrg unsigned i; 26713d1d17dSmrg 26813d1d17dSmrg bof_print_bof(bof, level, entry); 26913d1d17dSmrg for (i = 0; i < bof->array_size; i++) { 27013d1d17dSmrg bof_print_rec(bof->array[i], level + 2, i); 27113d1d17dSmrg } 27213d1d17dSmrg} 27313d1d17dSmrg 27413d1d17dSmrgvoid bof_print(bof_t *bof) 27513d1d17dSmrg{ 27613d1d17dSmrg bof_print_rec(bof, 0, 0); 27713d1d17dSmrg} 27813d1d17dSmrg 27913d1d17dSmrgstatic int bof_read(bof_t *root, FILE *file, long end, int level) 28013d1d17dSmrg{ 28113d1d17dSmrg bof_t *bof = NULL; 28213d1d17dSmrg int r; 28313d1d17dSmrg 28413d1d17dSmrg if (ftell(file) >= end) { 28513d1d17dSmrg return 0; 28613d1d17dSmrg } 28713d1d17dSmrg r = bof_entry_grow(root); 28813d1d17dSmrg if (r) 28913d1d17dSmrg return r; 29013d1d17dSmrg bof = bof_object(); 29113d1d17dSmrg if (bof == NULL) 29213d1d17dSmrg return -ENOMEM; 29313d1d17dSmrg bof->offset = ftell(file); 29413d1d17dSmrg r = fread(&bof->type, 4, 1, file); 29513d1d17dSmrg if (r != 1) 29613d1d17dSmrg goto out_err; 29713d1d17dSmrg r = fread(&bof->size, 4, 1, file); 29813d1d17dSmrg if (r != 1) 29913d1d17dSmrg goto out_err; 30013d1d17dSmrg r = fread(&bof->array_size, 4, 1, file); 30113d1d17dSmrg if (r != 1) 30213d1d17dSmrg goto out_err; 30313d1d17dSmrg switch (bof->type) { 30413d1d17dSmrg case BOF_TYPE_STRING: 30513d1d17dSmrg case BOF_TYPE_INT32: 30613d1d17dSmrg case BOF_TYPE_BLOB: 30713d1d17dSmrg bof->value = calloc(1, bof->size - 12); 30813d1d17dSmrg if (bof->value == NULL) { 30913d1d17dSmrg goto out_err; 31013d1d17dSmrg } 31113d1d17dSmrg r = fread(bof->value, bof->size - 12, 1, file); 31213d1d17dSmrg if (r != 1) { 31313d1d17dSmrg fprintf(stderr, "error reading %d\n", bof->size - 12); 31413d1d17dSmrg goto out_err; 31513d1d17dSmrg } 31613d1d17dSmrg break; 31713d1d17dSmrg case BOF_TYPE_NULL: 31813d1d17dSmrg return 0; 31913d1d17dSmrg case BOF_TYPE_OBJECT: 32013d1d17dSmrg case BOF_TYPE_ARRAY: 32113d1d17dSmrg r = bof_read(bof, file, bof->offset + bof->size, level + 2); 32213d1d17dSmrg if (r) 32313d1d17dSmrg goto out_err; 32413d1d17dSmrg break; 32513d1d17dSmrg default: 32613d1d17dSmrg fprintf(stderr, "invalid type %d\n", bof->type); 32713d1d17dSmrg goto out_err; 32813d1d17dSmrg } 32913d1d17dSmrg root->array[root->centry++] = bof; 33013d1d17dSmrg return bof_read(root, file, end, level); 33113d1d17dSmrgout_err: 33213d1d17dSmrg bof_decref(bof); 33313d1d17dSmrg return -EINVAL; 33413d1d17dSmrg} 33513d1d17dSmrg 33613d1d17dSmrgbof_t *bof_load_file(const char *filename) 33713d1d17dSmrg{ 33813d1d17dSmrg bof_t *root = bof_object(); 33913d1d17dSmrg int r; 34013d1d17dSmrg 34113d1d17dSmrg if (root == NULL) { 34213d1d17dSmrg fprintf(stderr, "%s failed to create root object\n", __func__); 34313d1d17dSmrg return NULL; 34413d1d17dSmrg } 34513d1d17dSmrg root->file = fopen(filename, "r"); 34613d1d17dSmrg if (root->file == NULL) 34713d1d17dSmrg goto out_err; 34813d1d17dSmrg r = fseek(root->file, 0L, SEEK_SET); 34913d1d17dSmrg if (r) { 35013d1d17dSmrg fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename); 35113d1d17dSmrg goto out_err; 35213d1d17dSmrg } 35313d1d17dSmrg root->offset = ftell(root->file); 35413d1d17dSmrg r = fread(&root->type, 4, 1, root->file); 35513d1d17dSmrg if (r != 1) 35613d1d17dSmrg goto out_err; 35713d1d17dSmrg r = fread(&root->size, 4, 1, root->file); 35813d1d17dSmrg if (r != 1) 35913d1d17dSmrg goto out_err; 36013d1d17dSmrg r = fread(&root->array_size, 4, 1, root->file); 36113d1d17dSmrg if (r != 1) 36213d1d17dSmrg goto out_err; 36313d1d17dSmrg r = bof_read(root, root->file, root->offset + root->size, 2); 36413d1d17dSmrg if (r) 36513d1d17dSmrg goto out_err; 36613d1d17dSmrg return root; 36713d1d17dSmrgout_err: 36813d1d17dSmrg bof_decref(root); 36913d1d17dSmrg return NULL; 37013d1d17dSmrg} 37113d1d17dSmrg 37213d1d17dSmrgvoid bof_incref(bof_t *bof) 37313d1d17dSmrg{ 37413d1d17dSmrg bof->refcount++; 37513d1d17dSmrg} 37613d1d17dSmrg 37713d1d17dSmrgvoid bof_decref(bof_t *bof) 37813d1d17dSmrg{ 37913d1d17dSmrg unsigned i; 38013d1d17dSmrg 38113d1d17dSmrg if (bof == NULL) 38213d1d17dSmrg return; 38313d1d17dSmrg if (--bof->refcount > 0) 38413d1d17dSmrg return; 38513d1d17dSmrg for (i = 0; i < bof->array_size; i++) { 38613d1d17dSmrg bof_decref(bof->array[i]); 38713d1d17dSmrg bof->array[i] = NULL; 38813d1d17dSmrg } 38913d1d17dSmrg bof->array_size = 0; 39013d1d17dSmrg if (bof->file) { 39113d1d17dSmrg fclose(bof->file); 39213d1d17dSmrg bof->file = NULL; 39313d1d17dSmrg } 39413d1d17dSmrg free(bof->array); 39513d1d17dSmrg free(bof->value); 39613d1d17dSmrg free(bof); 39713d1d17dSmrg} 39813d1d17dSmrg 39913d1d17dSmrgstatic int bof_file_write(bof_t *bof, FILE *file) 40013d1d17dSmrg{ 40113d1d17dSmrg unsigned i; 40213d1d17dSmrg int r; 40313d1d17dSmrg 40413d1d17dSmrg r = fwrite(&bof->type, 4, 1, file); 40513d1d17dSmrg if (r != 1) 40613d1d17dSmrg return -EINVAL; 40713d1d17dSmrg r = fwrite(&bof->size, 4, 1, file); 40813d1d17dSmrg if (r != 1) 40913d1d17dSmrg return -EINVAL; 41013d1d17dSmrg r = fwrite(&bof->array_size, 4, 1, file); 41113d1d17dSmrg if (r != 1) 41213d1d17dSmrg return -EINVAL; 41313d1d17dSmrg switch (bof->type) { 41413d1d17dSmrg case BOF_TYPE_NULL: 41513d1d17dSmrg if (bof->size) 41613d1d17dSmrg return -EINVAL; 41713d1d17dSmrg break; 41813d1d17dSmrg case BOF_TYPE_STRING: 41913d1d17dSmrg case BOF_TYPE_INT32: 42013d1d17dSmrg case BOF_TYPE_BLOB: 42113d1d17dSmrg r = fwrite(bof->value, bof->size - 12, 1, file); 42213d1d17dSmrg if (r != 1) 42313d1d17dSmrg return -EINVAL; 42413d1d17dSmrg break; 42513d1d17dSmrg case BOF_TYPE_OBJECT: 42613d1d17dSmrg case BOF_TYPE_ARRAY: 42713d1d17dSmrg for (i = 0; i < bof->array_size; i++) { 42813d1d17dSmrg r = bof_file_write(bof->array[i], file); 42913d1d17dSmrg if (r) 43013d1d17dSmrg return r; 43113d1d17dSmrg } 43213d1d17dSmrg break; 43313d1d17dSmrg default: 43413d1d17dSmrg return -EINVAL; 43513d1d17dSmrg } 43613d1d17dSmrg return 0; 43713d1d17dSmrg} 43813d1d17dSmrg 43913d1d17dSmrgint bof_dump_file(bof_t *bof, const char *filename) 44013d1d17dSmrg{ 44113d1d17dSmrg unsigned i; 44213d1d17dSmrg int r = 0; 44313d1d17dSmrg 44413d1d17dSmrg if (bof->file) { 44513d1d17dSmrg fclose(bof->file); 44613d1d17dSmrg bof->file = NULL; 44713d1d17dSmrg } 44813d1d17dSmrg bof->file = fopen(filename, "w"); 44913d1d17dSmrg if (bof->file == NULL) { 45013d1d17dSmrg fprintf(stderr, "%s failed to open file %s\n", __func__, filename); 45113d1d17dSmrg r = -EINVAL; 45213d1d17dSmrg goto out_err; 45313d1d17dSmrg } 45413d1d17dSmrg r = fseek(bof->file, 0L, SEEK_SET); 45513d1d17dSmrg if (r) { 45613d1d17dSmrg fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename); 45713d1d17dSmrg goto out_err; 45813d1d17dSmrg } 45913d1d17dSmrg r = fwrite(&bof->type, 4, 1, bof->file); 46013d1d17dSmrg if (r != 1) 46113d1d17dSmrg goto out_err; 46213d1d17dSmrg r = fwrite(&bof->size, 4, 1, bof->file); 46313d1d17dSmrg if (r != 1) 46413d1d17dSmrg goto out_err; 46513d1d17dSmrg r = fwrite(&bof->array_size, 4, 1, bof->file); 46613d1d17dSmrg if (r != 1) 46713d1d17dSmrg goto out_err; 46813d1d17dSmrg for (i = 0; i < bof->array_size; i++) { 46913d1d17dSmrg r = bof_file_write(bof->array[i], bof->file); 47013d1d17dSmrg if (r) 47113d1d17dSmrg return r; 47213d1d17dSmrg } 47313d1d17dSmrgout_err: 47413d1d17dSmrg fclose(bof->file); 47513d1d17dSmrg bof->file = NULL; 47613d1d17dSmrg return r; 47713d1d17dSmrg} 478