diff options
| author | 2015-02-05 14:42:00 +0100 | |
|---|---|---|
| committer | 2015-02-05 14:42:00 +0100 | |
| commit | 40cf910a621445bf5c2638f39d245fc7c3c8f72a (patch) | |
| tree | 66e3dad973a0677c29783d79d8e0978c0a8e3ae3 | |
| parent | 6a781e6f69cb820347bae02a1f947e6b01ccaa47 (diff) | |
| download | libplist-40cf910a621445bf5c2638f39d245fc7c3c8f72a.tar.gz libplist-40cf910a621445bf5c2638f39d245fc7c3c8f72a.tar.bz2 | |
bplist: Refactor binary plist parsing in a recursive way
| -rw-r--r-- | src/bplist.c | 376 |
1 files changed, 167 insertions, 209 deletions
diff --git a/src/bplist.c b/src/bplist.c index 5ddca26..3ba46a2 100644 --- a/src/bplist.c +++ b/src/bplist.c | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * plist.c | 2 | * bplist.c |
| 3 | * Binary plist implementation | 3 | * Binary plist implementation |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2008 Jonathan Beck All Rights Reserved. | 5 | * Copyright (c) 2011-2015 Nikias Bassen, All Rights Reserved. |
| 6 | * Copyright (c) 2008-2010 Jonathan Beck, All Rights Reserved. | ||
| 6 | * | 7 | * |
| 7 | * This library is free software; you can redistribute it and/or | 8 | * This library is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU Lesser General Public | 9 | * modify it under the terms of the GNU Lesser General Public |
| @@ -95,7 +96,7 @@ static void float_byte_convert(uint8_t * address, size_t size) | |||
| 95 | 96 | ||
| 96 | union plist_uint_ptr | 97 | union plist_uint_ptr |
| 97 | { | 98 | { |
| 98 | void *src; | 99 | const void *src; |
| 99 | uint8_t *u8ptr; | 100 | uint8_t *u8ptr; |
| 100 | uint16_t *u16ptr; | 101 | uint16_t *u16ptr; |
| 101 | uint32_t *u32ptr; | 102 | uint32_t *u32ptr; |
| @@ -202,7 +203,20 @@ static uint32_t uint24_from_be(union plist_uint_ptr buf) | |||
| 202 | 203 | ||
| 203 | #define NODE_IS_ROOT(x) (((node_t*)x)->isRoot) | 204 | #define NODE_IS_ROOT(x) (((node_t*)x)->isRoot) |
| 204 | 205 | ||
| 205 | static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object) | 206 | struct bplist_data { |
| 207 | const char* data; | ||
| 208 | uint64_t size; | ||
| 209 | uint64_t num_objects; | ||
| 210 | uint8_t dict_size; | ||
| 211 | uint8_t offset_size; | ||
| 212 | const char* offset_table; | ||
| 213 | uint32_t level; | ||
| 214 | uint32_t *used_indexes; | ||
| 215 | }; | ||
| 216 | |||
| 217 | static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node_index); | ||
| 218 | |||
| 219 | static plist_t parse_uint_node(const char **bnode, uint8_t size) | ||
| 206 | { | 220 | { |
| 207 | plist_data_t data = plist_new_plist_data(); | 221 | plist_data_t data = plist_new_plist_data(); |
| 208 | 222 | ||
| @@ -213,12 +227,12 @@ static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object) | |||
| 213 | case sizeof(uint16_t): | 227 | case sizeof(uint16_t): |
| 214 | case sizeof(uint32_t): | 228 | case sizeof(uint32_t): |
| 215 | case sizeof(uint64_t): | 229 | case sizeof(uint64_t): |
| 216 | memcpy(&data->intval, bnode, size); | 230 | memcpy(&data->intval, *bnode, size); |
| 217 | data->intval = UINT_TO_HOST(&data->intval, size); | 231 | data->intval = UINT_TO_HOST(&data->intval, size); |
| 218 | data->length = sizeof(uint64_t); | 232 | data->length = sizeof(uint64_t); |
| 219 | break; | 233 | break; |
| 220 | case 16: | 234 | case 16: |
| 221 | memcpy(&data->intval, bnode+8, sizeof(uint64_t)); | 235 | memcpy(&data->intval, (*bnode)+8, sizeof(uint64_t)); |
| 222 | data->intval = UINT_TO_HOST(&data->intval, sizeof(uint64_t)); | 236 | data->intval = UINT_TO_HOST(&data->intval, sizeof(uint64_t)); |
| 223 | data->length = size; | 237 | data->length = size; |
| 224 | break; | 238 | break; |
| @@ -227,13 +241,13 @@ static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object) | |||
| 227 | return NULL; | 241 | return NULL; |
| 228 | }; | 242 | }; |
| 229 | 243 | ||
| 230 | *next_object = bnode + size; | 244 | (*bnode) += size; |
| 231 | data->type = PLIST_UINT; | 245 | data->type = PLIST_UINT; |
| 232 | 246 | ||
| 233 | return node_create(NULL, data); | 247 | return node_create(NULL, data); |
| 234 | } | 248 | } |
| 235 | 249 | ||
| 236 | static plist_t parse_real_node(char *bnode, uint8_t size) | 250 | static plist_t parse_real_node(const char **bnode, uint8_t size) |
| 237 | { | 251 | { |
| 238 | plist_data_t data = plist_new_plist_data(); | 252 | plist_data_t data = plist_new_plist_data(); |
| 239 | float floatval = 0.0; | 253 | float floatval = 0.0; |
| @@ -241,7 +255,7 @@ static plist_t parse_real_node(char *bnode, uint8_t size) | |||
| 241 | 255 | ||
| 242 | size = 1 << size; // make length less misleading | 256 | size = 1 << size; // make length less misleading |
| 243 | buf = malloc (size); | 257 | buf = malloc (size); |
| 244 | memcpy (buf, bnode, size); | 258 | memcpy (buf, *bnode, size); |
| 245 | switch (size) | 259 | switch (size) |
| 246 | { | 260 | { |
| 247 | case sizeof(float): | 261 | case sizeof(float): |
| @@ -265,7 +279,7 @@ static plist_t parse_real_node(char *bnode, uint8_t size) | |||
| 265 | return node_create(NULL, data); | 279 | return node_create(NULL, data); |
| 266 | } | 280 | } |
| 267 | 281 | ||
| 268 | static plist_t parse_date_node(char *bnode, uint8_t size) | 282 | static plist_t parse_date_node(const char **bnode, uint8_t size) |
| 269 | { | 283 | { |
| 270 | plist_t node = parse_real_node(bnode, size); | 284 | plist_t node = parse_real_node(bnode, size); |
| 271 | plist_data_t data = plist_get_data(node); | 285 | plist_data_t data = plist_get_data(node); |
| @@ -279,13 +293,13 @@ static plist_t parse_date_node(char *bnode, uint8_t size) | |||
| 279 | return node; | 293 | return node; |
| 280 | } | 294 | } |
| 281 | 295 | ||
| 282 | static plist_t parse_string_node(char *bnode, uint64_t size) | 296 | static plist_t parse_string_node(const char **bnode, uint64_t size) |
| 283 | { | 297 | { |
| 284 | plist_data_t data = plist_new_plist_data(); | 298 | plist_data_t data = plist_new_plist_data(); |
| 285 | 299 | ||
| 286 | data->type = PLIST_STRING; | 300 | data->type = PLIST_STRING; |
| 287 | data->strval = (char *) malloc(sizeof(char) * (size + 1)); | 301 | data->strval = (char *) malloc(sizeof(char) * (size + 1)); |
| 288 | memcpy(data->strval, bnode, size); | 302 | memcpy(data->strval, *bnode, size); |
| 289 | data->strval[size] = '\0'; | 303 | data->strval[size] = '\0'; |
| 290 | data->length = strlen(data->strval); | 304 | data->length = strlen(data->strval); |
| 291 | 305 | ||
| @@ -348,7 +362,7 @@ static char *plist_utf16_to_utf8(uint16_t *unistr, long len, long *items_read, l | |||
| 348 | return outbuf; | 362 | return outbuf; |
| 349 | } | 363 | } |
| 350 | 364 | ||
| 351 | static plist_t parse_unicode_node(char *bnode, uint64_t size) | 365 | static plist_t parse_unicode_node(const char **bnode, uint64_t size) |
| 352 | { | 366 | { |
| 353 | plist_data_t data = plist_new_plist_data(); | 367 | plist_data_t data = plist_new_plist_data(); |
| 354 | uint64_t i = 0; | 368 | uint64_t i = 0; |
| @@ -359,7 +373,7 @@ static plist_t parse_unicode_node(char *bnode, uint64_t size) | |||
| 359 | 373 | ||
| 360 | data->type = PLIST_STRING; | 374 | data->type = PLIST_STRING; |
| 361 | unicodestr = (uint16_t*) malloc(sizeof(uint16_t) * size); | 375 | unicodestr = (uint16_t*) malloc(sizeof(uint16_t) * size); |
| 362 | memcpy(unicodestr, bnode, sizeof(uint16_t) * size); | 376 | memcpy(unicodestr, *bnode, sizeof(uint16_t) * size); |
| 363 | for (i = 0; i < size; i++) | 377 | for (i = 0; i < size; i++) |
| 364 | byte_convert((uint8_t *) (unicodestr + i), sizeof(uint16_t)); | 378 | byte_convert((uint8_t *) (unicodestr + i), sizeof(uint16_t)); |
| 365 | 379 | ||
| @@ -375,43 +389,112 @@ static plist_t parse_unicode_node(char *bnode, uint64_t size) | |||
| 375 | return node_create(NULL, data); | 389 | return node_create(NULL, data); |
| 376 | } | 390 | } |
| 377 | 391 | ||
| 378 | static plist_t parse_data_node(char *bnode, uint64_t size) | 392 | static plist_t parse_data_node(const char **bnode, uint64_t size) |
| 379 | { | 393 | { |
| 380 | plist_data_t data = plist_new_plist_data(); | 394 | plist_data_t data = plist_new_plist_data(); |
| 381 | 395 | ||
| 382 | data->type = PLIST_DATA; | 396 | data->type = PLIST_DATA; |
| 383 | data->length = size; | 397 | data->length = size; |
| 384 | data->buff = (uint8_t *) malloc(sizeof(uint8_t) * size); | 398 | data->buff = (uint8_t *) malloc(sizeof(uint8_t) * size); |
| 385 | memcpy(data->buff, bnode, sizeof(uint8_t) * size); | 399 | memcpy(data->buff, *bnode, sizeof(uint8_t) * size); |
| 386 | 400 | ||
| 387 | return node_create(NULL, data); | 401 | return node_create(NULL, data); |
| 388 | } | 402 | } |
| 389 | 403 | ||
| 390 | static plist_t parse_dict_node(char *bnode, uint64_t size, uint32_t ref_size) | 404 | static plist_t parse_dict_node(struct bplist_data *bplist, const char** bnode, uint64_t size) |
| 391 | { | 405 | { |
| 406 | uint64_t j; | ||
| 407 | uint64_t str_i = 0, str_j = 0; | ||
| 408 | uint64_t index1, index2; | ||
| 392 | plist_data_t data = plist_new_plist_data(); | 409 | plist_data_t data = plist_new_plist_data(); |
| 393 | 410 | ||
| 394 | data->type = PLIST_DICT; | 411 | data->type = PLIST_DICT; |
| 395 | data->length = size; | 412 | data->length = size; |
| 396 | data->buff = (uint8_t *) malloc(sizeof(uint8_t) * size * ref_size * 2); | ||
| 397 | memcpy(data->buff, bnode, sizeof(uint8_t) * size * ref_size * 2); | ||
| 398 | 413 | ||
| 399 | return node_create(NULL, data); | 414 | plist_t node = node_create(NULL, data); |
| 415 | |||
| 416 | for (j = 0; j < data->length; j++) { | ||
| 417 | str_i = j * bplist->dict_size; | ||
| 418 | str_j = (j + size) * bplist->dict_size; | ||
| 419 | |||
| 420 | index1 = UINT_TO_HOST((*bnode) + str_i, bplist->dict_size); | ||
| 421 | index2 = UINT_TO_HOST((*bnode) + str_j, bplist->dict_size); | ||
| 422 | |||
| 423 | if (index1 >= bplist->num_objects) { | ||
| 424 | plist_free(node); | ||
| 425 | return NULL; | ||
| 426 | } | ||
| 427 | if (index2 >= bplist->num_objects) { | ||
| 428 | plist_free(node); | ||
| 429 | return NULL; | ||
| 430 | } | ||
| 431 | |||
| 432 | /* process key node */ | ||
| 433 | plist_t key = parse_bin_node_at_index(bplist, index1); | ||
| 434 | if (!key) { | ||
| 435 | plist_free(node); | ||
| 436 | return NULL; | ||
| 437 | } | ||
| 438 | /* enforce key type */ | ||
| 439 | plist_get_data(key)->type = PLIST_KEY; | ||
| 440 | if (!plist_get_data(key)->strval) { | ||
| 441 | fprintf(stderr, "ERROR: Malformed binary plist dict, invalid key node encountered!\n"); | ||
| 442 | plist_free(key); | ||
| 443 | plist_free(node); | ||
| 444 | return NULL; | ||
| 445 | } | ||
| 446 | |||
| 447 | /* process value node */ | ||
| 448 | plist_t val = parse_bin_node_at_index(bplist, index2); | ||
| 449 | if (!val) { | ||
| 450 | plist_free(key); | ||
| 451 | plist_free(node); | ||
| 452 | return NULL; | ||
| 453 | } | ||
| 454 | |||
| 455 | node_attach(node, key); | ||
| 456 | node_attach(node, val); | ||
| 457 | } | ||
| 458 | |||
| 459 | return node; | ||
| 400 | } | 460 | } |
| 401 | 461 | ||
| 402 | static plist_t parse_array_node(char *bnode, uint64_t size, uint32_t ref_size) | 462 | static plist_t parse_array_node(struct bplist_data *bplist, const char** bnode, uint64_t size) |
| 403 | { | 463 | { |
| 464 | uint64_t j; | ||
| 465 | uint32_t str_j = 0; | ||
| 466 | uint32_t index1; | ||
| 467 | |||
| 404 | plist_data_t data = plist_new_plist_data(); | 468 | plist_data_t data = plist_new_plist_data(); |
| 405 | 469 | ||
| 406 | data->type = PLIST_ARRAY; | 470 | data->type = PLIST_ARRAY; |
| 407 | data->length = size; | 471 | data->length = size; |
| 408 | data->buff = (uint8_t *) malloc(sizeof(uint8_t) * size * ref_size); | ||
| 409 | memcpy(data->buff, bnode, sizeof(uint8_t) * size * ref_size); | ||
| 410 | 472 | ||
| 411 | return node_create(NULL, data); | 473 | plist_t node = node_create(NULL, data); |
| 474 | |||
| 475 | for (j = 0; j < data->length; j++) { | ||
| 476 | str_j = j * bplist->dict_size; | ||
| 477 | index1 = UINT_TO_HOST((*bnode) + str_j, bplist->dict_size); | ||
| 478 | |||
| 479 | if (index1 >= bplist->num_objects) { | ||
| 480 | plist_free(node); | ||
| 481 | return NULL; | ||
| 482 | } | ||
| 483 | |||
| 484 | /* process value node */ | ||
| 485 | plist_t val = parse_bin_node_at_index(bplist, index1); | ||
| 486 | if (!val) { | ||
| 487 | plist_free(node); | ||
| 488 | return NULL; | ||
| 489 | } | ||
| 490 | |||
| 491 | node_attach(node, val); | ||
| 492 | } | ||
| 493 | |||
| 494 | return node; | ||
| 412 | } | 495 | } |
| 413 | 496 | ||
| 414 | static plist_t parse_uid_node(char *bnode, uint8_t size, char **next_object) | 497 | static plist_t parse_uid_node(const char **bnode, uint8_t size) |
| 415 | { | 498 | { |
| 416 | plist_data_t data = plist_new_plist_data(); | 499 | plist_data_t data = plist_new_plist_data(); |
| 417 | 500 | ||
| @@ -422,7 +505,7 @@ static plist_t parse_uid_node(char *bnode, uint8_t size, char **next_object) | |||
| 422 | case sizeof(uint16_t): | 505 | case sizeof(uint16_t): |
| 423 | case sizeof(uint32_t): | 506 | case sizeof(uint32_t): |
| 424 | case sizeof(uint64_t): | 507 | case sizeof(uint64_t): |
| 425 | memcpy(&data->intval, bnode, size); | 508 | memcpy(&data->intval, *bnode, size); |
| 426 | data->intval = UINT_TO_HOST(&data->intval, size); | 509 | data->intval = UINT_TO_HOST(&data->intval, size); |
| 427 | break; | 510 | break; |
| 428 | default: | 511 | default: |
| @@ -430,15 +513,13 @@ static plist_t parse_uid_node(char *bnode, uint8_t size, char **next_object) | |||
| 430 | return NULL; | 513 | return NULL; |
| 431 | }; | 514 | }; |
| 432 | 515 | ||
| 433 | *next_object = bnode + size; | ||
| 434 | data->type = PLIST_UID; | 516 | data->type = PLIST_UID; |
| 435 | data->length = sizeof(uint64_t); | 517 | data->length = sizeof(uint64_t); |
| 436 | 518 | ||
| 437 | return node_create(NULL, data); | 519 | return node_create(NULL, data); |
| 438 | } | 520 | } |
| 439 | 521 | ||
| 440 | 522 | static plist_t parse_bin_node(struct bplist_data *bplist, const char** object) | |
| 441 | static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_object) | ||
| 442 | { | 523 | { |
| 443 | uint16_t type = 0; | 524 | uint16_t type = 0; |
| 444 | uint64_t size = 0; | 525 | uint64_t size = 0; |
| @@ -446,9 +527,9 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec | |||
| 446 | if (!object) | 527 | if (!object) |
| 447 | return NULL; | 528 | return NULL; |
| 448 | 529 | ||
| 449 | type = (*object) & 0xF0; | 530 | type = (**object) & BPLIST_MASK; |
| 450 | size = (*object) & 0x0F; | 531 | size = (**object) & BPLIST_FILL; |
| 451 | object++; | 532 | (*object)++; |
| 452 | 533 | ||
| 453 | switch (type) | 534 | switch (type) |
| 454 | { | 535 | { |
| @@ -481,7 +562,7 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec | |||
| 481 | } | 562 | } |
| 482 | 563 | ||
| 483 | case BPLIST_UINT: | 564 | case BPLIST_UINT: |
| 484 | return parse_uint_node(object, size, next_object); | 565 | return parse_uint_node(object, size); |
| 485 | 566 | ||
| 486 | case BPLIST_REAL: | 567 | case BPLIST_REAL: |
| 487 | return parse_real_node(object, size); | 568 | return parse_real_node(object, size); |
| @@ -493,9 +574,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec | |||
| 493 | return parse_date_node(object, size); | 574 | return parse_date_node(object, size); |
| 494 | 575 | ||
| 495 | case BPLIST_DATA: | 576 | case BPLIST_DATA: |
| 496 | if (0x0F == size) | 577 | if (BPLIST_FILL == size) { |
| 497 | { | 578 | plist_t size_node = parse_bin_node(bplist, object); |
| 498 | plist_t size_node = parse_bin_node(object, dict_size, &object); | ||
| 499 | if (plist_get_node_type(size_node) != PLIST_UINT) | 579 | if (plist_get_node_type(size_node) != PLIST_UINT) |
| 500 | return NULL; | 580 | return NULL; |
| 501 | plist_get_uint_val(size_node, &size); | 581 | plist_get_uint_val(size_node, &size); |
| @@ -504,9 +584,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec | |||
| 504 | return parse_data_node(object, size); | 584 | return parse_data_node(object, size); |
| 505 | 585 | ||
| 506 | case BPLIST_STRING: | 586 | case BPLIST_STRING: |
| 507 | if (0x0F == size) | 587 | if (BPLIST_FILL == size) { |
| 508 | { | 588 | plist_t size_node = parse_bin_node(bplist, object); |
| 509 | plist_t size_node = parse_bin_node(object, dict_size, &object); | ||
| 510 | if (plist_get_node_type(size_node) != PLIST_UINT) | 589 | if (plist_get_node_type(size_node) != PLIST_UINT) |
| 511 | return NULL; | 590 | return NULL; |
| 512 | plist_get_uint_val(size_node, &size); | 591 | plist_get_uint_val(size_node, &size); |
| @@ -515,9 +594,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec | |||
| 515 | return parse_string_node(object, size); | 594 | return parse_string_node(object, size); |
| 516 | 595 | ||
| 517 | case BPLIST_UNICODE: | 596 | case BPLIST_UNICODE: |
| 518 | if (0x0F == size) | 597 | if (BPLIST_FILL == size) { |
| 519 | { | 598 | plist_t size_node = parse_bin_node(bplist, object); |
| 520 | plist_t size_node = parse_bin_node(object, dict_size, &object); | ||
| 521 | if (plist_get_node_type(size_node) != PLIST_UINT) | 599 | if (plist_get_node_type(size_node) != PLIST_UINT) |
| 522 | return NULL; | 600 | return NULL; |
| 523 | plist_get_uint_val(size_node, &size); | 601 | plist_get_uint_val(size_node, &size); |
| @@ -525,76 +603,64 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec | |||
| 525 | } | 603 | } |
| 526 | return parse_unicode_node(object, size); | 604 | return parse_unicode_node(object, size); |
| 527 | 605 | ||
| 528 | case BPLIST_UNK_0x70: | 606 | case BPLIST_SET: |
| 529 | case BPLIST_ARRAY: | 607 | case BPLIST_ARRAY: |
| 530 | if (0x0F == size) | 608 | if (BPLIST_FILL == size) { |
| 531 | { | 609 | plist_t size_node = parse_bin_node(bplist, object); |
| 532 | plist_t size_node = parse_bin_node(object, dict_size, &object); | ||
| 533 | if (plist_get_node_type(size_node) != PLIST_UINT) | 610 | if (plist_get_node_type(size_node) != PLIST_UINT) |
| 534 | return NULL; | 611 | return NULL; |
| 535 | plist_get_uint_val(size_node, &size); | 612 | plist_get_uint_val(size_node, &size); |
| 536 | plist_free(size_node); | 613 | plist_free(size_node); |
| 537 | } | 614 | } |
| 538 | return parse_array_node(object, size, dict_size); | 615 | return parse_array_node(bplist, object, size); |
| 539 | 616 | ||
| 540 | case BPLIST_UID: | 617 | case BPLIST_UID: |
| 541 | return parse_uid_node(object, size, next_object); | 618 | return parse_uid_node(object, size); |
| 542 | 619 | ||
| 543 | case BPLIST_SET: | ||
| 544 | case BPLIST_DICT: | 620 | case BPLIST_DICT: |
| 545 | if (0x0F == size) | 621 | if (BPLIST_FILL == size) { |
| 546 | { | 622 | plist_t size_node = parse_bin_node(bplist, object); |
| 547 | plist_t size_node = parse_bin_node(object, dict_size, &object); | ||
| 548 | if (plist_get_node_type(size_node) != PLIST_UINT) | 623 | if (plist_get_node_type(size_node) != PLIST_UINT) |
| 549 | return NULL; | 624 | return NULL; |
| 550 | plist_get_uint_val(size_node, &size); | 625 | plist_get_uint_val(size_node, &size); |
| 551 | plist_free(size_node); | 626 | plist_free(size_node); |
| 552 | } | 627 | } |
| 553 | return parse_dict_node(object, size, dict_size); | 628 | return parse_dict_node(bplist, object, size); |
| 554 | default: | 629 | default: |
| 555 | return NULL; | 630 | return NULL; |
| 556 | } | 631 | } |
| 557 | return NULL; | 632 | return NULL; |
| 558 | } | 633 | } |
| 559 | 634 | ||
| 560 | static void* copy_plist_data(const void* src) | 635 | static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node_index) |
| 561 | { | 636 | { |
| 562 | plist_data_t srcdata = (plist_data_t) src; | 637 | int i; |
| 563 | plist_data_t dstdata = plist_new_plist_data(); | 638 | const char* ptr; |
| 639 | plist_t plist; | ||
| 564 | 640 | ||
| 565 | dstdata->type = srcdata->type; | 641 | ptr = bplist->data + UINT_TO_HOST(bplist->offset_table + node_index * bplist->offset_size, bplist->offset_size); |
| 566 | dstdata->length = srcdata->length; | 642 | /* make sure the node offset is in a sane range */ |
| 567 | switch (dstdata->type) | 643 | if ((ptr < bplist->data) || (ptr >= bplist->offset_table)) { |
| 568 | { | 644 | return NULL; |
| 569 | case PLIST_BOOLEAN: | ||
| 570 | dstdata->boolval = srcdata->boolval; | ||
| 571 | break; | ||
| 572 | case PLIST_UINT: | ||
| 573 | dstdata->intval = srcdata->intval; | ||
| 574 | break; | ||
| 575 | case PLIST_DATE: | ||
| 576 | dstdata->timeval.tv_sec = srcdata->timeval.tv_sec; | ||
| 577 | dstdata->timeval.tv_usec = srcdata->timeval.tv_usec; | ||
| 578 | break; | ||
| 579 | case PLIST_REAL: | ||
| 580 | dstdata->realval = srcdata->realval; | ||
| 581 | break; | ||
| 582 | case PLIST_KEY: | ||
| 583 | case PLIST_STRING: | ||
| 584 | dstdata->strval = strdup(srcdata->strval); | ||
| 585 | break; | ||
| 586 | case PLIST_DATA: | ||
| 587 | dstdata->buff = (uint8_t*) malloc(sizeof(uint8_t) * srcdata->length); | ||
| 588 | memcpy(dstdata->buff, srcdata->buff, sizeof(uint8_t) * srcdata->length); | ||
| 589 | break; | ||
| 590 | case PLIST_UID: | ||
| 591 | dstdata->intval = srcdata->intval; | ||
| 592 | break; | ||
| 593 | default: | ||
| 594 | break; | ||
| 595 | } | 645 | } |
| 596 | 646 | ||
| 597 | return dstdata; | 647 | /* store node_index for current recursion level */ |
| 648 | bplist->used_indexes[bplist->level] = node_index; | ||
| 649 | /* recursion check */ | ||
| 650 | if (bplist->level > 0) { | ||
| 651 | for (i = bplist->level-1; i >= 0; i--) { | ||
| 652 | if (bplist->used_indexes[i] == bplist->used_indexes[bplist->level]) { | ||
| 653 | fprintf(stderr, "Recursion detected in binary plist. Aborting.\n"); | ||
| 654 | return NULL; | ||
| 655 | } | ||
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 659 | /* finally parse node */ | ||
| 660 | bplist->level++; | ||
| 661 | plist = parse_bin_node(bplist, &ptr); | ||
| 662 | bplist->level--; | ||
| 663 | return plist; | ||
| 598 | } | 664 | } |
| 599 | 665 | ||
| 600 | PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist) | 666 | PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist) |
| @@ -602,19 +668,11 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * | |||
| 602 | char *trailer = NULL; | 668 | char *trailer = NULL; |
| 603 | 669 | ||
| 604 | uint8_t offset_size = 0; | 670 | uint8_t offset_size = 0; |
| 605 | uint8_t dict_param_size = 0; | 671 | uint8_t dict_size = 0; |
| 606 | uint64_t num_objects = 0; | 672 | uint64_t num_objects = 0; |
| 607 | uint64_t root_object = 0; | 673 | uint64_t root_object = 0; |
| 608 | uint64_t offset_table_index = 0; | 674 | uint64_t offset_table_index = 0; |
| 609 | 675 | ||
| 610 | plist_t *nodeslist = NULL; | ||
| 611 | uint64_t i = 0; | ||
| 612 | uint64_t current_offset = 0; | ||
| 613 | char *offset_table = NULL; | ||
| 614 | uint32_t j = 0, str_i = 0, str_j = 0; | ||
| 615 | uint32_t index1 = 0, index2 = 0; | ||
| 616 | |||
| 617 | |||
| 618 | //first check we have enough data | 676 | //first check we have enough data |
| 619 | if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE)) | 677 | if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE)) |
| 620 | return; | 678 | return; |
| @@ -629,7 +687,7 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * | |||
| 629 | trailer = (char *) (plist_bin + (length - BPLIST_TRL_SIZE)); | 687 | trailer = (char *) (plist_bin + (length - BPLIST_TRL_SIZE)); |
| 630 | 688 | ||
| 631 | offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX]; | 689 | offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX]; |
| 632 | dict_param_size = trailer[BPLIST_TRL_PARMSIZE_IDX]; | 690 | dict_size = trailer[BPLIST_TRL_PARMSIZE_IDX]; |
| 633 | num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX); | 691 | num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX); |
| 634 | root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX); | 692 | root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX); |
| 635 | offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX); | 693 | offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX); |
| @@ -637,122 +695,22 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * | |||
| 637 | if (num_objects == 0) | 695 | if (num_objects == 0) |
| 638 | return; | 696 | return; |
| 639 | 697 | ||
| 640 | //allocate serialized array of nodes | 698 | if (root_object >= num_objects) |
| 641 | nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects); | ||
| 642 | |||
| 643 | if (!nodeslist) | ||
| 644 | return; | 699 | return; |
| 645 | 700 | ||
| 646 | //parse serialized nodes | 701 | struct bplist_data bplist; |
| 647 | offset_table = (char *) (plist_bin + offset_table_index); | 702 | bplist.data = plist_bin; |
| 648 | for (i = 0; i < num_objects; i++) | 703 | bplist.size = length; |
| 649 | { | 704 | bplist.num_objects = num_objects; |
| 650 | char *obj = NULL; | 705 | bplist.dict_size = dict_size; |
| 651 | current_offset = UINT_TO_HOST(offset_table + i * offset_size, offset_size); | 706 | bplist.offset_size = offset_size; |
| 652 | 707 | bplist.offset_table = (char *) (plist_bin + offset_table_index); | |
| 653 | obj = (char *) (plist_bin + current_offset); | 708 | bplist.level = 0; |
| 654 | nodeslist[i] = parse_bin_node(obj, dict_param_size, &obj); | 709 | bplist.used_indexes = (uint32_t*)malloc(sizeof(uint32_t) * num_objects); |
| 655 | } | ||
| 656 | |||
| 657 | //setup children for structured types | ||
| 658 | for (i = 0; i < num_objects; i++) | ||
| 659 | { | ||
| 660 | |||
| 661 | plist_data_t data = plist_get_data(nodeslist[i]); | ||
| 662 | if (!data) { | ||
| 663 | break; | ||
| 664 | } | ||
| 665 | 710 | ||
| 666 | switch (data->type) | 711 | *plist = parse_bin_node_at_index(&bplist, root_object); |
| 667 | { | ||
| 668 | case PLIST_DICT: | ||
| 669 | for (j = 0; j < data->length; j++) | ||
| 670 | { | ||
| 671 | node_t* n = NULL; | ||
| 672 | str_i = j * dict_param_size; | ||
| 673 | str_j = (j + data->length) * dict_param_size; | ||
| 674 | |||
| 675 | index1 = UINT_TO_HOST(data->buff + str_i, dict_param_size); | ||
| 676 | index2 = UINT_TO_HOST(data->buff + str_j, dict_param_size); | ||
| 677 | |||
| 678 | // process key node | ||
| 679 | if (index1 < num_objects) | ||
| 680 | { | ||
| 681 | // is node already attached? | ||
| 682 | if (NODE_IS_ROOT(nodeslist[index1])) { | ||
| 683 | // use original | ||
| 684 | n = nodeslist[index1]; | ||
| 685 | } else { | ||
| 686 | // use a copy, because this node is already attached elsewhere | ||
| 687 | n = node_copy_deep(nodeslist[index1], copy_plist_data); | ||
| 688 | } | ||
| 689 | |||
| 690 | // enforce key type | ||
| 691 | plist_get_data(n)->type = PLIST_KEY; | ||
| 692 | |||
| 693 | // attach key node | ||
| 694 | node_attach(nodeslist[i], n); | ||
| 695 | } | ||
| 696 | |||
| 697 | // process value node | ||
| 698 | if (index2 < num_objects) | ||
| 699 | { | ||
| 700 | // is node already attached? | ||
| 701 | if (NODE_IS_ROOT(nodeslist[index2])) { | ||
| 702 | // use original | ||
| 703 | n = nodeslist[index2]; | ||
| 704 | } else { | ||
| 705 | // use a copy, because this node is already attached elsewhere | ||
| 706 | n = node_copy_deep(nodeslist[index2], copy_plist_data); | ||
| 707 | |||
| 708 | // ensure key type is never used for values, especially if we copy a key node | ||
| 709 | if (plist_get_data(n)->type == PLIST_KEY) { | ||
| 710 | plist_get_data(n)->type = PLIST_STRING; | ||
| 711 | } | ||
| 712 | } | ||
| 713 | |||
| 714 | // attach value node | ||
| 715 | node_attach(nodeslist[i], n); | ||
| 716 | } | ||
| 717 | } | ||
| 718 | break; | ||
| 719 | 712 | ||
| 720 | case PLIST_ARRAY: | 713 | free(bplist.used_indexes); |
| 721 | for (j = 0; j < data->length; j++) | ||
| 722 | { | ||
| 723 | str_j = j * dict_param_size; | ||
| 724 | index1 = UINT_TO_HOST(data->buff + str_j, dict_param_size); | ||
| 725 | |||
| 726 | if (index1 < num_objects) | ||
| 727 | { | ||
| 728 | if (NODE_IS_ROOT(nodeslist[index1])) | ||
| 729 | node_attach(nodeslist[i], nodeslist[index1]); | ||
| 730 | else | ||
| 731 | node_attach(nodeslist[i], node_copy_deep(nodeslist[index1], copy_plist_data)); | ||
| 732 | } | ||
| 733 | } | ||
| 734 | break; | ||
| 735 | default: | ||
| 736 | break; | ||
| 737 | } | ||
| 738 | } | ||
| 739 | |||
| 740 | *plist = nodeslist[root_object]; | ||
| 741 | |||
| 742 | // free unreferenced nodes that would otherwise leak memory | ||
| 743 | for (i = 0; i < num_objects; i++) { | ||
| 744 | plist_data_t data = plist_get_data(nodeslist[i]); | ||
| 745 | if ((data->type == PLIST_DICT) || (data->type == PLIST_ARRAY)) { | ||
| 746 | free(data->buff); | ||
| 747 | data->buff = NULL; | ||
| 748 | } | ||
| 749 | if (i == root_object) continue; | ||
| 750 | node_t* node = (node_t*)nodeslist[i]; | ||
| 751 | if (node && NODE_IS_ROOT(node)) { | ||
| 752 | plist_free(node); | ||
| 753 | } | ||
| 754 | } | ||
| 755 | free(nodeslist); | ||
| 756 | } | 714 | } |
| 757 | 715 | ||
| 758 | static unsigned int plist_data_hash(const void* key) | 716 | static unsigned int plist_data_hash(const void* key) |
