diff options
Diffstat (limited to 'src/bplist.c')
| -rw-r--r-- | src/bplist.c | 127 |
1 files changed, 83 insertions, 44 deletions
diff --git a/src/bplist.c b/src/bplist.c index 6e00f39..fb24a1e 100644 --- a/src/bplist.c +++ b/src/bplist.c | |||
| @@ -75,6 +75,7 @@ static void byte_convert(uint8_t * address, size_t size) | |||
| 75 | #endif | 75 | #endif |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | |||
| 78 | #define UINT_TO_HOST(x, n) \ | 79 | #define UINT_TO_HOST(x, n) \ |
| 79 | (n == 8 ? GUINT64_FROM_BE( *(uint64_t *)(x) ) : \ | 80 | (n == 8 ? GUINT64_FROM_BE( *(uint64_t *)(x) ) : \ |
| 80 | (n == 4 ? GUINT32_FROM_BE( *(uint32_t *)(x) ) : \ | 81 | (n == 4 ? GUINT32_FROM_BE( *(uint32_t *)(x) ) : \ |
| @@ -220,11 +221,14 @@ static plist_t parse_array_node(char *bnode, uint64_t size, uint32_t ref_size) | |||
| 220 | 221 | ||
| 221 | static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_object) | 222 | static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_object) |
| 222 | { | 223 | { |
| 224 | uint16_t type = 0; | ||
| 225 | uint64_t size = 0; | ||
| 226 | |||
| 223 | if (!object) | 227 | if (!object) |
| 224 | return NULL; | 228 | return NULL; |
| 225 | 229 | ||
| 226 | uint16_t type = *object & 0xF0; | 230 | type = (*object) & 0xF0; |
| 227 | uint64_t size = *object & 0x0F; | 231 | size = (*object) & 0x0F; |
| 228 | object++; | 232 | object++; |
| 229 | 233 | ||
| 230 | switch (type) { | 234 | switch (type) { |
| @@ -364,6 +368,22 @@ static gpointer copy_plist_data(gconstpointer src, gpointer data) | |||
| 364 | 368 | ||
| 365 | void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist) | 369 | void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist) |
| 366 | { | 370 | { |
| 371 | char *trailer = NULL; | ||
| 372 | |||
| 373 | uint8_t offset_size = 0; | ||
| 374 | uint8_t dict_param_size = 0; | ||
| 375 | uint64_t num_objects = 0; | ||
| 376 | uint64_t root_object = 0; | ||
| 377 | uint64_t offset_table_index = 0; | ||
| 378 | |||
| 379 | plist_t *nodeslist = NULL; | ||
| 380 | uint64_t i = 0; | ||
| 381 | uint64_t current_offset = 0; | ||
| 382 | char *offset_table = NULL; | ||
| 383 | uint32_t j = 0, str_i = 0, str_j = 0; | ||
| 384 | uint32_t index1 = 0, index2 = 0; | ||
| 385 | |||
| 386 | |||
| 367 | //first check we have enough data | 387 | //first check we have enough data |
| 368 | if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE)) | 388 | if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE)) |
| 369 | return; | 389 | return; |
| @@ -375,39 +395,34 @@ void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist) | |||
| 375 | return; | 395 | return; |
| 376 | 396 | ||
| 377 | //now parse trailer | 397 | //now parse trailer |
| 378 | const char *trailer = plist_bin + (length - BPLIST_TRL_SIZE); | 398 | trailer = plist_bin + (length - BPLIST_TRL_SIZE); |
| 379 | 399 | ||
| 380 | uint8_t offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX]; | 400 | offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX]; |
| 381 | uint8_t dict_param_size = trailer[BPLIST_TRL_PARMSIZE_IDX]; | 401 | dict_param_size = trailer[BPLIST_TRL_PARMSIZE_IDX]; |
| 382 | uint64_t num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX); | 402 | num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX); |
| 383 | uint64_t root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX); | 403 | root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX); |
| 384 | uint64_t offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX); | 404 | offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX); |
| 385 | 405 | ||
| 386 | if (num_objects == 0) | 406 | if (num_objects == 0) |
| 387 | return; | 407 | return; |
| 388 | 408 | ||
| 389 | //allocate serialized array of nodes | 409 | //allocate serialized array of nodes |
| 390 | plist_t *nodeslist = NULL; | ||
| 391 | nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects); | 410 | nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects); |
| 392 | 411 | ||
| 393 | if (!nodeslist) | 412 | if (!nodeslist) |
| 394 | return; | 413 | return; |
| 395 | 414 | ||
| 396 | //parse serialized nodes | 415 | //parse serialized nodes |
| 397 | uint64_t i = 0; | 416 | offset_table = plist_bin + offset_table_index; |
| 398 | uint64_t current_offset = 0; | ||
| 399 | const char *offset_table = plist_bin + offset_table_index; | ||
| 400 | for (i = 0; i < num_objects; i++) { | 417 | for (i = 0; i < num_objects; i++) { |
| 418 | char *obj = NULL; | ||
| 401 | current_offset = UINT_TO_HOST(offset_table + i * offset_size, offset_size); | 419 | current_offset = UINT_TO_HOST(offset_table + i * offset_size, offset_size); |
| 402 | 420 | ||
| 403 | char *obj = plist_bin + current_offset; | 421 | obj = plist_bin + current_offset; |
| 404 | nodeslist[i] = parse_bin_node(obj, dict_param_size, &obj); | 422 | nodeslist[i] = parse_bin_node(obj, dict_param_size, &obj); |
| 405 | } | 423 | } |
| 406 | 424 | ||
| 407 | //setup children for structured types | 425 | //setup children for structured types |
| 408 | uint32_t j = 0, str_i = 0, str_j = 0; | ||
| 409 | uint32_t index1 = 0, index2 = 0; | ||
| 410 | |||
| 411 | for (i = 0; i < num_objects; i++) { | 426 | for (i = 0; i < num_objects; i++) { |
| 412 | 427 | ||
| 413 | plist_data_t data = plist_get_data(nodeslist[i]); | 428 | plist_data_t data = plist_get_data(nodeslist[i]); |
| @@ -514,14 +529,17 @@ static guint plist_data_hash(gconstpointer key) | |||
| 514 | 529 | ||
| 515 | static gboolean plist_data_compare(gconstpointer a, gconstpointer b) | 530 | static gboolean plist_data_compare(gconstpointer a, gconstpointer b) |
| 516 | { | 531 | { |
| 532 | plist_data_t val_a = NULL; | ||
| 533 | plist_data_t val_b = NULL; | ||
| 534 | |||
| 517 | if (!a || !b) | 535 | if (!a || !b) |
| 518 | return FALSE; | 536 | return FALSE; |
| 519 | 537 | ||
| 520 | if (!((GNode *) a)->data || !((GNode *) b)->data) | 538 | if (!((GNode *) a)->data || !((GNode *) b)->data) |
| 521 | return FALSE; | 539 | return FALSE; |
| 522 | 540 | ||
| 523 | plist_data_t val_a = plist_get_data((plist_t) a); | 541 | val_a = plist_get_data((plist_t) a); |
| 524 | plist_data_t val_b = plist_get_data((plist_t) b); | 542 | val_b = plist_get_data((plist_t) b); |
| 525 | 543 | ||
| 526 | if (val_a->type != val_b->type) | 544 | if (val_a->type != val_b->type) |
| 527 | return FALSE; | 545 | return FALSE; |
| @@ -574,6 +592,7 @@ struct serialize_s { | |||
| 574 | 592 | ||
| 575 | static void serialize_plist(GNode * node, gpointer data) | 593 | static void serialize_plist(GNode * node, gpointer data) |
| 576 | { | 594 | { |
| 595 | uint64_t *index_val = NULL; | ||
| 577 | struct serialize_s *ser = (struct serialize_s *) data; | 596 | struct serialize_s *ser = (struct serialize_s *) data; |
| 578 | uint64_t current_index = ser->objects->len; | 597 | uint64_t current_index = ser->objects->len; |
| 579 | 598 | ||
| @@ -584,7 +603,7 @@ static void serialize_plist(GNode * node, gpointer data) | |||
| 584 | return; | 603 | return; |
| 585 | } | 604 | } |
| 586 | //insert new ref | 605 | //insert new ref |
| 587 | uint64_t *index_val = (uint64_t *) malloc(sizeof(uint64_t)); | 606 | index_val = (uint64_t *) malloc(sizeof(uint64_t)); |
| 588 | *index_val = current_index; | 607 | *index_val = current_index; |
| 589 | g_hash_table_insert(ser->ref_table, node, index_val); | 608 | g_hash_table_insert(ser->ref_table, node, index_val); |
| 590 | 609 | ||
| @@ -639,6 +658,7 @@ static void write_date(GByteArray * bplist, double val) | |||
| 639 | 658 | ||
| 640 | static void write_raw_data(GByteArray * bplist, uint8_t mark, uint8_t * val, uint64_t size) | 659 | static void write_raw_data(GByteArray * bplist, uint8_t mark, uint8_t * val, uint64_t size) |
| 641 | { | 660 | { |
| 661 | uint8_t *buff = NULL; | ||
| 642 | uint8_t marker = mark | (size < 15 ? size : 0xf); | 662 | uint8_t marker = mark | (size < 15 ? size : 0xf); |
| 643 | g_byte_array_append(bplist, &marker, sizeof(uint8_t)); | 663 | g_byte_array_append(bplist, &marker, sizeof(uint8_t)); |
| 644 | if (size >= 15) { | 664 | if (size >= 15) { |
| @@ -647,7 +667,7 @@ static void write_raw_data(GByteArray * bplist, uint8_t mark, uint8_t * val, uin | |||
| 647 | g_byte_array_append(bplist, int_buff->data, int_buff->len); | 667 | g_byte_array_append(bplist, int_buff->data, int_buff->len); |
| 648 | g_byte_array_free(int_buff, TRUE); | 668 | g_byte_array_free(int_buff, TRUE); |
| 649 | } | 669 | } |
| 650 | uint8_t *buff = (uint8_t *) malloc(size); | 670 | buff = (uint8_t *) malloc(size); |
| 651 | memcpy(buff, val, size); | 671 | memcpy(buff, val, size); |
| 652 | g_byte_array_append(bplist, buff, size); | 672 | g_byte_array_append(bplist, buff, size); |
| 653 | free(buff); | 673 | free(buff); |
| @@ -677,6 +697,12 @@ static void write_unicode(GByteArray * bplist, gunichar2 * val, uint64_t size) | |||
| 677 | 697 | ||
| 678 | static void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) | 698 | static void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) |
| 679 | { | 699 | { |
| 700 | uint64_t idx = 0; | ||
| 701 | uint8_t *buff = NULL; | ||
| 702 | |||
| 703 | GNode *cur = NULL; | ||
| 704 | uint64_t i = 0; | ||
| 705 | |||
| 680 | uint64_t size = g_node_n_children(node); | 706 | uint64_t size = g_node_n_children(node); |
| 681 | uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); | 707 | uint8_t marker = BPLIST_ARRAY | (size < 15 ? size : 0xf); |
| 682 | g_byte_array_append(bplist, &marker, sizeof(uint8_t)); | 708 | g_byte_array_append(bplist, &marker, sizeof(uint8_t)); |
| @@ -687,11 +713,8 @@ static void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_tabl | |||
| 687 | g_byte_array_free(int_buff, TRUE); | 713 | g_byte_array_free(int_buff, TRUE); |
| 688 | } | 714 | } |
| 689 | 715 | ||
| 690 | uint64_t idx = 0; | 716 | buff = (uint8_t *) malloc(size * dict_param_size); |
| 691 | uint8_t *buff = (uint8_t *) malloc(size * dict_param_size); | ||
| 692 | 717 | ||
| 693 | GNode *cur = NULL; | ||
| 694 | uint64_t i = 0; | ||
| 695 | for (i = 0, cur = node->children; cur && i < size; cur = cur->next, i++) { | 718 | for (i = 0, cur = node->children; cur && i < size; cur = cur->next, i++) { |
| 696 | idx = *(uint64_t *) (g_hash_table_lookup(ref_table, cur)); | 719 | idx = *(uint64_t *) (g_hash_table_lookup(ref_table, cur)); |
| 697 | memcpy(buff + i * dict_param_size, &idx, dict_param_size); | 720 | memcpy(buff + i * dict_param_size, &idx, dict_param_size); |
| @@ -706,6 +729,13 @@ static void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_tabl | |||
| 706 | 729 | ||
| 707 | static void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) | 730 | static void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table, uint8_t dict_param_size) |
| 708 | { | 731 | { |
| 732 | uint64_t idx1 = 0; | ||
| 733 | uint64_t idx2 = 0; | ||
| 734 | uint8_t *buff = NULL; | ||
| 735 | |||
| 736 | GNode *cur = NULL; | ||
| 737 | uint64_t i = 0; | ||
| 738 | |||
| 709 | uint64_t size = g_node_n_children(node) / 2; | 739 | uint64_t size = g_node_n_children(node) / 2; |
| 710 | uint8_t marker = BPLIST_DICT | (size < 15 ? size : 0xf); | 740 | uint8_t marker = BPLIST_DICT | (size < 15 ? size : 0xf); |
| 711 | g_byte_array_append(bplist, &marker, sizeof(uint8_t)); | 741 | g_byte_array_append(bplist, &marker, sizeof(uint8_t)); |
| @@ -716,12 +746,8 @@ static void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table | |||
| 716 | g_byte_array_free(int_buff, TRUE); | 746 | g_byte_array_free(int_buff, TRUE); |
| 717 | } | 747 | } |
| 718 | 748 | ||
| 719 | uint64_t idx1 = 0; | 749 | buff = (uint8_t *) malloc(size * 2 * dict_param_size); |
| 720 | uint64_t idx2 = 0; | ||
| 721 | uint8_t *buff = (uint8_t *) malloc(size * 2 * dict_param_size); | ||
| 722 | 750 | ||
| 723 | GNode *cur = NULL; | ||
| 724 | uint64_t i = 0; | ||
| 725 | for (i = 0, cur = node->children; cur && i < size; cur = cur->next->next, i++) { | 751 | for (i = 0, cur = node->children; cur && i < size; cur = cur->next->next, i++) { |
| 726 | idx1 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); | 752 | idx1 = GPOINTER_TO_UINT(g_hash_table_lookup(ref_table, cur)); |
| 727 | memcpy(buff + i * dict_param_size, &idx1, dict_param_size); | 753 | memcpy(buff + i * dict_param_size, &idx1, dict_param_size); |
| @@ -740,41 +766,55 @@ static void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table | |||
| 740 | 766 | ||
| 741 | void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | 767 | void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) |
| 742 | { | 768 | { |
| 769 | GPtrArray *objects = NULL; | ||
| 770 | GHashTable *ref_table = NULL; | ||
| 771 | struct serialize_s ser_s; | ||
| 772 | uint8_t offset_size = 0; | ||
| 773 | uint8_t dict_param_size = 0; | ||
| 774 | uint64_t num_objects = 0; | ||
| 775 | uint64_t root_object = 0; | ||
| 776 | uint64_t offset_table_index = 0; | ||
| 777 | GByteArray *bplist_buff = NULL; | ||
| 778 | uint64_t i = 0; | ||
| 779 | uint8_t *buff = NULL; | ||
| 780 | uint64_t *offsets = NULL; | ||
| 781 | uint8_t pad[6] = { 0, 0, 0, 0, 0, 0 }; | ||
| 782 | uint8_t trailer[BPLIST_TRL_SIZE]; | ||
| 783 | |||
| 743 | //check for valid input | 784 | //check for valid input |
| 744 | if (!plist || !plist_bin || *plist_bin || !length) | 785 | if (!plist || !plist_bin || *plist_bin || !length) |
| 745 | return; | 786 | return; |
| 746 | 787 | ||
| 747 | //list of objects | 788 | //list of objects |
| 748 | GPtrArray *objects = g_ptr_array_new(); | 789 | objects = g_ptr_array_new(); |
| 749 | //hashtable to write only once same nodes | 790 | //hashtable to write only once same nodes |
| 750 | GHashTable *ref_table = g_hash_table_new(plist_data_hash, plist_data_compare); | 791 | ref_table = g_hash_table_new(plist_data_hash, plist_data_compare); |
| 751 | 792 | ||
| 752 | //serialize plist | 793 | //serialize plist |
| 753 | struct serialize_s ser_s = { objects, ref_table }; | 794 | ser_s.objects = objects; |
| 795 | ser_s.ref_table = ref_table; | ||
| 754 | serialize_plist(plist, &ser_s); | 796 | serialize_plist(plist, &ser_s); |
| 755 | 797 | ||
| 756 | //now stream to output buffer | 798 | //now stream to output buffer |
| 757 | uint8_t offset_size = 0; //unknown yet | 799 | offset_size = 0; //unknown yet |
| 758 | uint8_t dict_param_size = get_needed_bytes(objects->len); | 800 | dict_param_size = get_needed_bytes(objects->len); |
| 759 | uint64_t num_objects = objects->len; | 801 | num_objects = objects->len; |
| 760 | uint64_t root_object = 0; //root is first in list | 802 | root_object = 0; //root is first in list |
| 761 | uint64_t offset_table_index = 0; //unknown yet | 803 | offset_table_index = 0; //unknown yet |
| 762 | 804 | ||
| 763 | //setup a dynamic bytes array to store bplist in | 805 | //setup a dynamic bytes array to store bplist in |
| 764 | GByteArray *bplist_buff = g_byte_array_new(); | 806 | bplist_buff = g_byte_array_new(); |
| 765 | 807 | ||
| 766 | //set magic number and version | 808 | //set magic number and version |
| 767 | g_byte_array_append(bplist_buff, BPLIST_MAGIC, BPLIST_MAGIC_SIZE); | 809 | g_byte_array_append(bplist_buff, BPLIST_MAGIC, BPLIST_MAGIC_SIZE); |
| 768 | g_byte_array_append(bplist_buff, BPLIST_VERSION, BPLIST_VERSION_SIZE); | 810 | g_byte_array_append(bplist_buff, BPLIST_VERSION, BPLIST_VERSION_SIZE); |
| 769 | 811 | ||
| 770 | //write objects and table | 812 | //write objects and table |
| 771 | uint64_t i = 0; | 813 | offsets = (uint64_t *) malloc(num_objects * sizeof(uint64_t)); |
| 772 | uint8_t *buff = NULL; | ||
| 773 | uint64_t offsets[num_objects]; | ||
| 774 | for (i = 0; i < num_objects; i++) { | 814 | for (i = 0; i < num_objects; i++) { |
| 775 | 815 | ||
| 776 | offsets[i] = bplist_buff->len; | ||
| 777 | plist_data_t data = plist_get_data(g_ptr_array_index(objects, i)); | 816 | plist_data_t data = plist_get_data(g_ptr_array_index(objects, i)); |
| 817 | offsets[i] = bplist_buff->len; | ||
| 778 | 818 | ||
| 779 | switch (data->type) { | 819 | switch (data->type) { |
| 780 | case PLIST_BOOLEAN: | 820 | case PLIST_BOOLEAN: |
| @@ -830,7 +870,6 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | |||
| 830 | } | 870 | } |
| 831 | 871 | ||
| 832 | //experimental pad to reflect apple's files | 872 | //experimental pad to reflect apple's files |
| 833 | uint8_t pad[6] = { 0, 0, 0, 0, 0, 0 }; | ||
| 834 | g_byte_array_append(bplist_buff, pad, 6); | 873 | g_byte_array_append(bplist_buff, pad, 6); |
| 835 | 874 | ||
| 836 | //setup trailer | 875 | //setup trailer |
| @@ -838,7 +877,6 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | |||
| 838 | root_object = GUINT64_FROM_BE(root_object); | 877 | root_object = GUINT64_FROM_BE(root_object); |
| 839 | offset_table_index = GUINT64_FROM_BE(offset_table_index); | 878 | offset_table_index = GUINT64_FROM_BE(offset_table_index); |
| 840 | 879 | ||
| 841 | uint8_t trailer[BPLIST_TRL_SIZE]; | ||
| 842 | memcpy(trailer + BPLIST_TRL_OFFSIZE_IDX, &offset_size, sizeof(uint8_t)); | 880 | memcpy(trailer + BPLIST_TRL_OFFSIZE_IDX, &offset_size, sizeof(uint8_t)); |
| 843 | memcpy(trailer + BPLIST_TRL_PARMSIZE_IDX, &dict_param_size, sizeof(uint8_t)); | 881 | memcpy(trailer + BPLIST_TRL_PARMSIZE_IDX, &dict_param_size, sizeof(uint8_t)); |
| 844 | memcpy(trailer + BPLIST_TRL_NUMOBJ_IDX, &num_objects, sizeof(uint64_t)); | 882 | memcpy(trailer + BPLIST_TRL_NUMOBJ_IDX, &num_objects, sizeof(uint64_t)); |
| @@ -853,4 +891,5 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | |||
| 853 | *length = bplist_buff->len; | 891 | *length = bplist_buff->len; |
| 854 | 892 | ||
| 855 | g_byte_array_free(bplist_buff, TRUE); | 893 | g_byte_array_free(bplist_buff, TRUE); |
| 894 | free(offsets); | ||
| 856 | } | 895 | } |
