1 /* 2 * Copyright 2010 Jerome Glisse <glisse (at) 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 */ 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 } 478