Mercurial > libpst
changeset 49:17654fbdf76b
more fixes for 64 bit format
author | carl |
---|---|
date | Sat, 19 Jan 2008 10:47:16 -0800 |
parents | f66078abed38 |
children | fb3818370dd6 |
files | ChangeLog regression/regression-tests.bash src/libpst.c src/libpst.h xml/libpst.in |
diffstat | 5 files changed, 513 insertions(+), 428 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Fri Jan 18 15:07:12 2008 -0800 +++ b/ChangeLog Sat Jan 19 10:47:16 2008 -0800 @@ -1,10 +1,9 @@ -LibPST 0.6.4 (2008-01-18) +LibPST 0.6.4 (2008-01-19) =============================== * More fixes for Outlook 2003 64 bit parsing. We observed cases of compressed RTF bodies (type 0x1009) with zero length. - * Document type 0x0101 descriptor blocks and try to process them. - This is still not correct. + * Document type 0x0101 descriptor blocks and process them. * Fix large file support - we need to include config.h before any standard headers.
--- a/regression/regression-tests.bash Fri Jan 18 15:07:12 2008 -0800 +++ b/regression/regression-tests.bash Sat Jan 19 10:47:16 2008 -0800 @@ -8,25 +8,26 @@ done -#$val ../src/pst2ldif -b 'o=ams-cc.com, c=US' -c 'newPerson' ams.pst >ams.err 2>&1 -#$val ../src/readpst -cv -o output1 ams.pst >out1.err 2>&1 -#$val ../src/readpst -cl -r -o output2 ams.pst >out2.err 2>&1 -#$val ../src/readpst -S -o output3 ams.pst >out3.err 2>&1 -#$val ../src/readpst -M -o output4 ams.pst >out4.err 2>&1 -#$val ../src/readpst -o output5 mbmg.archive.pst >out5.err 2>&1 +$val ../src/pst2ldif -b 'o=ams-cc.com, c=US' -c 'newPerson' ams.pst >ams.err 2>&1 +$val ../src/readpst -cv -o output1 ams.pst >out1.err 2>&1 +$val ../src/readpst -cl -r -o output2 ams.pst >out2.err 2>&1 +$val ../src/readpst -S -o output3 ams.pst >out3.err 2>&1 +$val ../src/readpst -M -o output4 ams.pst >out4.err 2>&1 -#$val ../src/readpst -o output6 -d dumper test.pst >out6.err 2>&1 -# ../src/readpstlog -f I dumper >dumpertest.log +$val ../src/readpst -o output5 -d dumper mbmg.archive.pst >out5.err 2>&1 + ../src/readpstlog -f I dumper >mbmg.archive.log -#$val ../src/readpst -cv -o output7 -d dumper sample_64.pst >out7.err 2>&1 -# ../src/readpstlog -f I dumper >sample_64.log -# hexdump -C dumper >dumper.hex +$val ../src/readpst -o output6 -d dumper test.pst >out6.err 2>&1 + ../src/readpstlog -f I dumper >dumpertest.log + +$val ../src/readpst -cv -o output7 -d dumper sample_64.pst >out7.err 2>&1 + ../src/readpstlog -f I dumper >sample_64.log $val ../src/readpst -cv -o output8 -d dumper big_mail.pst >out8.err 2>&1 ../src/readpstlog -f I dumper >big_mail.log -#$val ../src/lspst ams.pst >out8.err 2>&1 -# ../src/readpstlog -f I lspst.debug >lspst.log +$val ../src/lspst ams.pst >out8.err 2>&1 + ../src/readpstlog -f I lspst.debug >lspst.log -#rm -f dumper lspst.debug +rm -f dumper lspst.debug
--- a/src/libpst.c Fri Jan 18 15:07:12 2008 -0800 +++ b/src/libpst.c Sat Jan 19 10:47:16 2008 -0800 @@ -30,8 +30,7 @@ #include "libpst.h" #include "timeconv.h" -//efine INDEX_DEPTH 0x4C -//efine SECOND_DEPTH 0x5C + #define INDEX_TYPE32 0x0E #define INDEX_TYPE64 0x17 #define INDEX_TYPE_OFFSET (off_t)0x0A @@ -254,7 +253,7 @@ size_t pst_attach_to_mem(pst_file *pf, pst_item_attach *attach, unsigned char **b){ size_t size=0; pst_index_ll *ptr; - struct holder h = {b, NULL, 0, "", 0}; + pst_holder h = {b, NULL, 0, "", 0}; DEBUG_ENT("pst_attach_to_mem"); if (attach->id_val != (uint64_t)-1) { ptr = pst_getID(pf, attach->id_val); @@ -275,7 +274,7 @@ size_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp) { pst_index_ll *ptr; - struct holder h = {NULL, fp, 0, "", 0}; + pst_holder h = {NULL, fp, 0, "", 0}; size_t size; DEBUG_ENT("pst_attach_to_file"); if (attach->id_val != (uint64_t)-1) { @@ -299,7 +298,7 @@ size_t pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE* fp) { pst_index_ll *ptr; - struct holder h = {NULL, fp, 1, "", 0}; + pst_holder h = {NULL, fp, 1, "", 0}; size_t size; char *c; DEBUG_ENT("pst_attach_to_file_base64"); @@ -1253,21 +1252,25 @@ } -static void freeall(unsigned char *buf, pst_block_offset_pointer *p1, - pst_block_offset_pointer *p2, - pst_block_offset_pointer *p3, - pst_block_offset_pointer *p4, - pst_block_offset_pointer *p5, - pst_block_offset_pointer *p6, - pst_block_offset_pointer *p7); -static void freeall(unsigned char *buf, pst_block_offset_pointer *p1, - pst_block_offset_pointer *p2, - pst_block_offset_pointer *p3, - pst_block_offset_pointer *p4, - pst_block_offset_pointer *p5, - pst_block_offset_pointer *p6, - pst_block_offset_pointer *p7) { - if (buf) free(buf); +static void freeall(pst_subblocks *subs, pst_block_offset_pointer *p1, + pst_block_offset_pointer *p2, + pst_block_offset_pointer *p3, + pst_block_offset_pointer *p4, + pst_block_offset_pointer *p5, + pst_block_offset_pointer *p6, + pst_block_offset_pointer *p7); +static void freeall(pst_subblocks *subs, pst_block_offset_pointer *p1, + pst_block_offset_pointer *p2, + pst_block_offset_pointer *p3, + pst_block_offset_pointer *p4, + pst_block_offset_pointer *p5, + pst_block_offset_pointer *p6, + pst_block_offset_pointer *p7) { + size_t i; + for (i=0; i<subs->subblock_count; i++) { + if (subs->subs[i].buf) free(subs->subs[i].buf); + } + free(subs->subs); if (p1->needfree) free(p1->from); if (p2->needfree) free(p2->from); if (p3->needfree) free(p3->from); @@ -1280,6 +1283,8 @@ pst_num_array * pst_parse_block(pst_file *pf, uint64_t block_id, pst_index2_ll *i2_head, pst_num_array *na_head) { unsigned char *buf = NULL; + size_t read_size = 0; + pst_subblocks subblocks; pst_num_array *na_ptr = NULL; pst_block_offset_pointer block_offset1; pst_block_offset_pointer block_offset2; @@ -1295,13 +1300,11 @@ int32_t cur_list; int block_type; uint32_t rec_size = 0; - uint32_t ind_ptr; unsigned char* list_start; unsigned char* fr_ptr; unsigned char* to_ptr; unsigned char* ind2_end = NULL; unsigned char* ind2_ptr = NULL; - size_t read_size=0; pst_x_attrib_ll *mapptr; struct { @@ -1366,14 +1369,47 @@ LE32_CPU(block_hdr.offset); DEBUG_EMAIL(("block header (index_offset=%#hx, type=%#hx, offset=%#hx)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset)); - ind_ptr = block_hdr.index_offset; + if (block_hdr.index_offset == (uint16_t)0x0101) { //type 3 + subblocks.subblock_count = block_hdr.type; + subblocks.subs = malloc(sizeof(pst_subblock) * subblocks.subblock_count); + size_t i; + char *b_ptr = buf + 8; + for (i=0; i<subblocks.subblock_count; i++) { + b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr); + subblocks.subs[i].buf = NULL; + subblocks.subs[i].read_size = pst_ff_getIDblock_dec(pf, table3_rec.id, &subblocks.subs[i].buf); + if (subblocks.subs[i].buf) { + memcpy(&block_hdr, subblocks.subs[i].buf, sizeof(block_hdr)); + LE16_CPU(block_hdr.index_offset); + subblocks.subs[i].i_offset = block_hdr.index_offset; + } + else { + subblocks.subs[i].read_size = 0; + subblocks.subs[i].i_offset = 0; + } + } + free(buf); + memcpy(&block_hdr, subblocks.subs[0].buf, sizeof(block_hdr)); + LE16_CPU(block_hdr.index_offset); + LE16_CPU(block_hdr.type); + LE32_CPU(block_hdr.offset); + DEBUG_EMAIL(("block header (index_offset=%#hx, type=%#hx, offset=%#hx)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset)); + } + else { + // setup the subblock descriptors, but we only have one block + subblocks.subblock_count = 1; + subblocks.subs = malloc(sizeof(pst_subblock)); + subblocks.subs[0].buf = buf; + subblocks.subs[0].read_size = read_size; + subblocks.subs[0].i_offset = block_hdr.index_offset; + } if (block_hdr.type == (uint16_t)0xBCEC) { //type 1 block_type = 1; - if (pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, block_hdr.offset, &block_offset1)) { + if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, block_hdr.offset, &block_offset1)) { DEBUG_WARN(("internal error (bc.b5 offset %#x) in reading block id %#x\n", block_hdr.offset, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return NULL; } @@ -1386,14 +1422,14 @@ if (table_rec.type != (uint16_t)0x02B5) { WARN(("Unknown second block constant - %#hx for id %#llx\n", table_rec.type, block_id)); DEBUG_HEXDUMPC(buf, sizeof(table_rec), 0x10); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return NULL; } - if (pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset2)) { + if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset2)) { DEBUG_WARN(("internal error (bc.b5.desc offset) in reading block id %#x\n", table_rec.value, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return NULL; } @@ -1405,9 +1441,9 @@ else if (block_hdr.type == (uint16_t)0x7CEC) { //type 2 block_type = 2; - if (pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, block_hdr.offset, &block_offset3)) { + if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, block_hdr.offset, &block_offset3)) { DEBUG_WARN(("internal error (7c.7c offset %#x) in reading block id %#x\n", block_hdr.offset, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return NULL; } @@ -1427,7 +1463,7 @@ if (seven_c_blk.seven_c != 0x7C) { // this would mean it isn't a 7C block! WARN(("Error. There isn't a 7C where I want to see 7C!\n")); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return NULL; } @@ -1435,9 +1471,9 @@ rec_size = seven_c_blk.rec_size; num_list = (int32_t)(unsigned)seven_c_blk.item_count; - if (pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, seven_c_blk.b_five_offset, &block_offset4)) { + if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, seven_c_blk.b_five_offset, &block_offset4)) { DEBUG_WARN(("internal error (7c.b5 offset %#x) in reading block id %#x\n", seven_c_blk.b_five_offset, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return NULL; } @@ -1448,48 +1484,32 @@ if (table_rec.type != (uint16_t)0x04B5) { // different constant than a type 1 record WARN(("Unknown second block constant - %#hx for id %#llx\n", table_rec.type, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return NULL; } - if (pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset5)) { + if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset5)) { DEBUG_WARN(("internal error (7c.5b.desc offset %#x) in reading block id %#llx\n", table_rec.value, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return NULL; } num_recs = (block_offset5.to - block_offset5.from) / 6; // this will give the number of records in this block - if (pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, seven_c_blk.ind2_offset, &block_offset6)) { + if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, seven_c_blk.ind2_offset, &block_offset6)) { DEBUG_WARN(("internal error (7c.ind2 offset %#x) in reading block id %#x\n", seven_c_blk.ind2_offset, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return NULL; } ind2_ptr = block_offset6.from; ind2_end = block_offset6.to; } - else if (block_hdr.index_offset == (uint16_t)0x0101) { //type 3 - unsigned char *buf2 = NULL; - uint16_t n = block_hdr.type; // count - uint16_t i; - block_type = 3; - char *b_ptr = buf + 8; - for (i=0; i<n; i++) { - b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr); - //(void)pst_ff_getIDblock_dec(pf, table3_rec.id, &buf2); - //if (buf2) free(buf2); - //buf2 = NULL; - na_head = pst_parse_block(pf, table3_rec.id, i2_head, na_head); // !! this is still not correct - } - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return na_head; - } else { + else { WARN(("ERROR: Unknown block constant - %#hx for id %#llx\n", block_hdr.type, block_id)); DEBUG_HEXDUMPC(buf, read_size,0x10); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return NULL; } @@ -1500,8 +1520,8 @@ memset(na_ptr, 0, sizeof(pst_num_array)); na_ptr->next = na_head; na_head = na_ptr; - // allocate an array of count num_recs to contain sizeof(struct pst_num_item) - na_ptr->items = (struct pst_num_item**) xmalloc(sizeof(struct pst_num_item)*num_list); + // allocate an array of count num_recs to contain sizeof(pst_num_item) + na_ptr->items = (pst_num_item**) xmalloc(sizeof(pst_num_item)*num_list); na_ptr->count_item = num_list; na_ptr->orig_count = num_list; na_ptr->count_array = (int32_t)num_recs; // each record will have a record of the total number of records @@ -1550,7 +1570,7 @@ fr_ptr += sizeof(table2_rec); } else { WARN(("Missing code for block_type %i\n", block_type)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); if (na_head) pst_free_list(na_head); DEBUG_RET(); return NULL; @@ -1559,9 +1579,9 @@ x, table_rec.type, table_rec.ref_type, table_rec.value)); if (!na_ptr->items[x]) { - na_ptr->items[x] = (struct pst_num_item*) xmalloc(sizeof(struct pst_num_item)); + na_ptr->items[x] = (pst_num_item*) xmalloc(sizeof(pst_num_item)); } - memset(na_ptr->items[x], 0, sizeof(struct pst_num_item)); //init it + memset(na_ptr->items[x], 0, sizeof(pst_num_item)); //init it // check here to see if the id of the attribute is a mapped one mapptr = pf->x_head; @@ -1635,7 +1655,7 @@ na_ptr->items[x]->data = xmalloc(value_size); memcpy(na_ptr->items[x]->data, value_pointer, value_size); } - else if (pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset7)) { + else if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset7)) { if ((table_rec.value & 0xf) == (uint32_t)0xf) { DEBUG_WARN(("failed to get block offset for table_rec.value of %#x to be read later.\n", table_rec.value)); na_ptr->items[x]->size = 0; @@ -1697,7 +1717,7 @@ if (na_ptr->items[x]->type == 0) na_ptr->items[x]->type = table_rec.ref_type; } else { WARN(("ERROR Unknown ref_type %#hx\n", table_rec.ref_type)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); if (na_head) pst_free_list(na_head); DEBUG_RET(); return NULL; @@ -1707,7 +1727,7 @@ DEBUG_EMAIL(("increasing ind2_ptr by %i [%#x] bytes. Was %#x, Now %#x\n", rec_size, rec_size, ind2_ptr, ind2_ptr+rec_size)); ind2_ptr += rec_size; } - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); DEBUG_RET(); return na_head; } @@ -1781,14 +1801,19 @@ switch (list->items[x]->id) { case PST_ATTRIB_HEADER: // CUSTOM attribute for saying the Extra Headers DEBUG_EMAIL(("Extra Field - ")); - ef = (pst_item_extra_field*) xmalloc(sizeof(pst_item_extra_field)); - memset(ef, 0, sizeof(pst_item_extra_field)); - ef->field_name = (char*) xmalloc(strlen(list->items[x]->extra)+1); - strcpy(ef->field_name, list->items[x]->extra); - LIST_COPY(ef->value, (char*)); - ef->next = item->extra_fields; - item->extra_fields = ef; - DEBUG_EMAIL(("\"%s\" = \"%s\"\n", ef->field_name, ef->value)); + if (list->items[x]->extra) { + ef = (pst_item_extra_field*) xmalloc(sizeof(pst_item_extra_field)); + memset(ef, 0, sizeof(pst_item_extra_field)); + ef->field_name = (char*) xmalloc(strlen(list->items[x]->extra)+1); + strcpy(ef->field_name, list->items[x]->extra); + LIST_COPY(ef->value, (char*)); + ef->next = item->extra_fields; + item->extra_fields = ef; + DEBUG_EMAIL(("\"%s\" = \"%s\"\n", ef->field_name, ef->value)); + } + else { + DEBUG_EMAIL(("NULL extra field\n")); + } break; case 0x0002: // PR_ALTERNATE_RECIPIENT_ALLOWED // If set to true, the sender allows this email to be autoforwarded @@ -3722,19 +3747,23 @@ /** * The offset might be zero, in which case we have no data, so return a pair of null pointers. * Or, the offset might end in 0xf, so it is an id2 pointer, in which case we read the id2 block. - * Otherwise, the offset>>4 is an index into the table of offsets in the buffer. + * Otherwise, the high order 16 bits of offset is the index into the subblocks, and + * the (low order 16 bits of offset)>>4 is an index into the table of offsets in the subblock. */ -int pst_getBlockOffsetPointer(pst_file *pf, pst_index2_ll *i2_head, unsigned char *buf, size_t read_size, uint32_t i_offset, uint32_t offset, pst_block_offset_pointer *p) { +int pst_getBlockOffsetPointer(pst_file *pf, pst_index2_ll *i2_head, pst_subblocks *subblocks, uint32_t offset, pst_block_offset_pointer *p) { size_t size; pst_block_offset block_offset; DEBUG_ENT("pst_getBlockOffsetPointer"); if (p->needfree) free(p->from); - p->from = NULL; + p->from = NULL; + p->to = NULL; p->needfree = 0; if (!offset) { + // no data p->from = p->to = NULL; } else if ((offset & 0xf) == (uint32_t)0xf) { + // external index reference DEBUG_WARN(("Found id2 %#x value. Will follow it\n", offset)); size = pst_ff_getID2block(pf, offset, i2_head, &(p->from)); if (size) { @@ -3745,12 +3774,19 @@ p->from = p->to = NULL; } } - else if (pst_getBlockOffset(buf, read_size, i_offset, offset, &block_offset)) { - p->from = p->to = NULL; - } else { - p->from = buf + block_offset.from; - p->to = buf + block_offset.to; + // internal index reference + size_t subindex = offset >> 16; + size_t suboffset = offset & 0xffff; + if (subindex < subblocks->subblock_count) { + if (pst_getBlockOffset(subblocks->subs[subindex].buf, + subblocks->subs[subindex].read_size, + subblocks->subs[subindex].i_offset, + suboffset, &block_offset)) { + p->from = subblocks->subs[subindex].buf + block_offset.from; + p->to = subblocks->subs[subindex].buf + block_offset.to; + } + } } DEBUG_RET(); return (p->from) ? 0 : 1; @@ -3764,7 +3800,7 @@ if (!p || !buf || !i_offset || low || (i_offset+2+of1+sizeof(*p) > read_size)) { DEBUG_WARN(("p is NULL or buf is NULL or offset is 0 or offset has low bits or beyond read size (%p, %p, %#x, %i, %i)\n", p, buf, offset, read_size, i_offset)); DEBUG_RET(); - return -1; + return 0; } memcpy(&(p->from), &(buf[(i_offset+2)+of1]), sizeof(p->from)); memcpy(&(p->to), &(buf[(i_offset+2)+of1+sizeof(p->from)]), sizeof(p->to)); @@ -3773,10 +3809,10 @@ DEBUG_WARN(("get block offset finds from=%i(%#x), to=%i(%#x)\n", p->from, p->from, p->to, p->to)); if (p->from > p->to) { DEBUG_WARN(("get block offset from > to")); - return -1; + return 0; } DEBUG_RET(); - return 0; + return 1; } @@ -4138,8 +4174,7 @@ #define PST_PTR_BLOCK_SIZE 0x120 size_t pst_ff_getID2block(pst_file *pf, uint64_t id2, pst_index2_ll *id2_head, unsigned char** buf) { pst_index_ll* ptr; - // size_t ret; - struct holder h = {buf, NULL, 0, "", 0}; + pst_holder h = {buf, NULL, 0, "", 0}; DEBUG_ENT("pst_ff_getID2block"); ptr = pst_getID2(id2_head, id2); @@ -4153,7 +4188,7 @@ } -size_t pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, struct holder *h) { +size_t pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, pst_holder *h) { size_t ret; unsigned char *b = NULL, *t; DEBUG_ENT("pst_ff_getID2data"); @@ -4187,7 +4222,7 @@ } -size_t pst_ff_compile_ID(pst_file *pf, uint64_t id, struct holder *h, size_t size) { +size_t pst_ff_compile_ID(pst_file *pf, uint64_t id, pst_holder *h, size_t size) { size_t z, a; uint16_t count, y; uint32_t x, b;
--- a/src/libpst.h Fri Jan 18 15:07:12 2008 -0800 +++ b/src/libpst.h Sat Jan 19 10:47:16 2008 -0800 @@ -111,383 +111,424 @@ #define PST_APP_LABEL_ANNIVERSARY 9 // Anniversary #define PST_APP_LABEL_PHONE_CALL 10// Phone Call + typedef struct pst_misc_6_struct { - int32_t i1; - int32_t i2; - int32_t i3; - int32_t i4; - int32_t i5; - int32_t i6; + int32_t i1; + int32_t i2; + int32_t i3; + int32_t i4; + int32_t i5; + int32_t i6; } pst_misc_6; + typedef struct pst_entryid_struct { - int32_t u1; - char entryid[16]; - uint32_t id; + int32_t u1; + char entryid[16]; + uint32_t id; } pst_entryid; + typedef struct pst_desc_struct32 { - uint32_t d_id; - uint32_t desc_id; - uint32_t list_id; - uint32_t parent_id; + uint32_t d_id; + uint32_t desc_id; + uint32_t list_id; + uint32_t parent_id; } pst_desc32; + typedef struct pst_desc_structn { - uint64_t d_id; - uint64_t desc_id; - uint64_t list_id; - uint32_t parent_id; // not 64 bit ?? - uint32_t u1; // padding + uint64_t d_id; + uint64_t desc_id; + uint64_t list_id; + uint32_t parent_id; // not 64 bit ?? + uint32_t u1; // padding } pst_descn; + typedef struct pst_index_struct32 { - uint32_t id; - uint32_t offset; - uint16_t size; - int16_t u1; + uint32_t id; + uint32_t offset; + uint16_t size; + int16_t u1; } pst_index32; + typedef struct pst_index_struct { - uint64_t id; - uint64_t offset; - uint16_t size; - int16_t u0; - int32_t u1; + uint64_t id; + uint64_t offset; + uint16_t size; + int16_t u0; + int32_t u1; } pst_index; + typedef struct pst_index_tree32 { - uint32_t id; - uint32_t offset; - uint32_t size; - int32_t u1; - struct pst_index_tree * next; + uint32_t id; + uint32_t offset; + uint32_t size; + int32_t u1; + struct pst_index_tree * next; } pst_index_ll32; + typedef struct pst_index_tree { - uint64_t id; - uint64_t offset; - uint64_t size; - int64_t u1; - struct pst_index_tree * next; + uint64_t id; + uint64_t offset; + uint64_t size; + int64_t u1; + struct pst_index_tree * next; } pst_index_ll; + typedef struct pst_index2_tree { - uint64_t id2; - pst_index_ll *id; - struct pst_index2_tree * next; + uint64_t id2; + pst_index_ll *id; + struct pst_index2_tree * next; } pst_index2_ll; + typedef struct pst_desc_tree { - uint64_t id; - pst_index_ll * list_index; - pst_index_ll * desc; - int32_t no_child; - struct pst_desc_tree * prev; - struct pst_desc_tree * next; - struct pst_desc_tree * parent; - struct pst_desc_tree * child; - struct pst_desc_tree * child_tail; + uint64_t id; + pst_index_ll * list_index; + pst_index_ll * desc; + int32_t no_child; + struct pst_desc_tree * prev; + struct pst_desc_tree * next; + struct pst_desc_tree * parent; + struct pst_desc_tree * child; + struct pst_desc_tree * child_tail; } pst_desc_ll; + typedef struct pst_item_email_subject { - int off1; - int off2; - char *subj; + int off1; + int off2; + char *subj; } pst_item_email_subject; + typedef struct pst_item_email { - FILETIME *arrival_date; - int autoforward; // 1 = true, 0 = not set, -1 = false - char *body; - char *cc_address; - char *common_name; - int32_t conv_index; - int conversion_prohib; // 1 = true, 0 = false - int delete_after_submit; // 1 = true, 0 = false - int delivery_report; // 1 = true, 0 = false - char *encrypted_body; - int32_t encrypted_body_size; - char *encrypted_htmlbody; - int32_t encrypted_htmlbody_size; - int32_t flag; - char *header; - char *htmlbody; - int32_t importance; - char *in_reply_to; - int message_cc_me; // 1 = true, 0 = false - int message_recip_me; // 1 = true, 0 = false - int message_to_me; // 1 = true, 0 = false - char *messageid; - int32_t orig_sensitivity; - char *outlook_recipient; - char *outlook_recipient2; - char *outlook_sender; - char *outlook_sender_name; - char *outlook_sender2; - int32_t priority; - char *proc_subject; - int read_receipt; // 1 = true, 0 = false - char *recip_access; - char *recip_address; - char *recip2_access; - char *recip2_address; - int reply_requested; // 1 = true, 0 = false - char *reply_to; - char *return_path_address; - int32_t rtf_body_char_count; - int32_t rtf_body_crc; - char *rtf_body_tag; - char *rtf_compressed; - uint32_t rtf_compressed_size; - int rtf_in_sync; // 1 = true, 0 = doesn't exist, -1 = false - int32_t rtf_ws_prefix_count; - int32_t rtf_ws_trailing_count; - char *sender_access; - char *sender_address; - char *sender2_access; - char *sender2_address; - int32_t sensitivity; - FILETIME *sent_date; - pst_entryid *sentmail_folder; - char *sentto_address; - pst_item_email_subject *subject; + FILETIME *arrival_date; + int autoforward; // 1 = true, 0 = not set, -1 = false + char *body; + char *cc_address; + char *common_name; + int32_t conv_index; + int conversion_prohib; // 1 = true, 0 = false + int delete_after_submit; // 1 = true, 0 = false + int delivery_report; // 1 = true, 0 = false + char *encrypted_body; + int32_t encrypted_body_size; + char *encrypted_htmlbody; + int32_t encrypted_htmlbody_size; + int32_t flag; + char *header; + char *htmlbody; + int32_t importance; + char *in_reply_to; + int message_cc_me; // 1 = true, 0 = false + int message_recip_me; // 1 = true, 0 = false + int message_to_me; // 1 = true, 0 = false + char *messageid; + int32_t orig_sensitivity; + char *outlook_recipient; + char *outlook_recipient2; + char *outlook_sender; + char *outlook_sender_name; + char *outlook_sender2; + int32_t priority; + char *proc_subject; + int read_receipt; // 1 = true, 0 = false + char *recip_access; + char *recip_address; + char *recip2_access; + char *recip2_address; + int reply_requested; // 1 = true, 0 = false + char *reply_to; + char *return_path_address; + int32_t rtf_body_char_count; + int32_t rtf_body_crc; + char *rtf_body_tag; + char *rtf_compressed; + uint32_t rtf_compressed_size; + int rtf_in_sync; // 1 = true, 0 = doesn't exist, -1 = false + int32_t rtf_ws_prefix_count; + int32_t rtf_ws_trailing_count; + char *sender_access; + char *sender_address; + char *sender2_access; + char *sender2_address; + int32_t sensitivity; + FILETIME *sent_date; + pst_entryid *sentmail_folder; + char *sentto_address; + pst_item_email_subject *subject; } pst_item_email; + typedef struct pst_item_folder { - int32_t email_count; - int32_t unseen_email_count; - int32_t assoc_count; - int subfolder; // 1 = true, 0 = false + int32_t email_count; + int32_t unseen_email_count; + int32_t assoc_count; + int subfolder; // 1 = true, 0 = false } pst_item_folder; + typedef struct pst_item_message_store { - pst_entryid *deleted_items_folder; - pst_entryid *search_root_folder; - pst_entryid *top_of_personal_folder; - pst_entryid *top_of_folder; - int32_t valid_mask; // what folders the message store contains - int32_t pwd_chksum; + pst_entryid *deleted_items_folder; + pst_entryid *search_root_folder; + pst_entryid *top_of_personal_folder; + pst_entryid *top_of_folder; + int32_t valid_mask; // what folders the message store contains + int32_t pwd_chksum; } pst_item_message_store; + typedef struct pst_item_contact { - char *access_method; - char *account_name; - char *address1; - char *address1a; - char *address1_desc; - char *address1_transport; - char *address2; - char *address2a; - char *address2_desc; - char *address2_transport; - char *address3; - char *address3a; - char *address3_desc; - char *address3_transport; - char *assistant_name; - char *assistant_phone; - char *billing_information; - FILETIME *birthday; - char *business_address; - char *business_city; - char *business_country; - char *business_fax; - char *business_homepage; - char *business_phone; - char *business_phone2; - char *business_po_box; - char *business_postal_code; - char *business_state; - char *business_street; - char *callback_phone; - char *car_phone; - char *company_main_phone; - char *company_name; - char *computer_name; - char *customer_id; - char *def_postal_address; - char *department; - char *display_name_prefix; - char *first_name; - char *followup; - char *free_busy_address; - char *ftp_site; - char *fullname; - int32_t gender; - char *gov_id; - char *hobbies; - char *home_address; - char *home_city; - char *home_country; - char *home_fax; - char *home_phone; - char *home_phone2; - char *home_po_box; - char *home_postal_code; - char *home_state; - char *home_street; - char *initials; - char *isdn_phone; - char *job_title; - char *keyword; - char *language; - char *location; - int mail_permission; // 1 = true, 0 = false - char *manager_name; - char *middle_name; - char *mileage; - char *mobile_phone; - char *nickname; - char *office_loc; - char *org_id; - char *other_address; - char *other_city; - char *other_country; - char *other_phone; - char *other_po_box; - char *other_postal_code; - char *other_state; - char *other_street; - char *pager_phone; - char *personal_homepage; - char *pref_name; - char *primary_fax; - char *primary_phone; - char *profession; - char *radio_phone; - int rich_text; // 1 = true, 0 = false - char *spouse_name; - char *suffix; - char *surname; - char *telex; - char *transmittable_display_name; - char *ttytdd_phone; - FILETIME *wedding_anniversary; + char *access_method; + char *account_name; + char *address1; + char *address1a; + char *address1_desc; + char *address1_transport; + char *address2; + char *address2a; + char *address2_desc; + char *address2_transport; + char *address3; + char *address3a; + char *address3_desc; + char *address3_transport; + char *assistant_name; + char *assistant_phone; + char *billing_information; + FILETIME *birthday; + char *business_address; + char *business_city; + char *business_country; + char *business_fax; + char *business_homepage; + char *business_phone; + char *business_phone2; + char *business_po_box; + char *business_postal_code; + char *business_state; + char *business_street; + char *callback_phone; + char *car_phone; + char *company_main_phone; + char *company_name; + char *computer_name; + char *customer_id; + char *def_postal_address; + char *department; + char *display_name_prefix; + char *first_name; + char *followup; + char *free_busy_address; + char *ftp_site; + char *fullname; + int32_t gender; + char *gov_id; + char *hobbies; + char *home_address; + char *home_city; + char *home_country; + char *home_fax; + char *home_phone; + char *home_phone2; + char *home_po_box; + char *home_postal_code; + char *home_state; + char *home_street; + char *initials; + char *isdn_phone; + char *job_title; + char *keyword; + char *language; + char *location; + int mail_permission; // 1 = true, 0 = false + char *manager_name; + char *middle_name; + char *mileage; + char *mobile_phone; + char *nickname; + char *office_loc; + char *org_id; + char *other_address; + char *other_city; + char *other_country; + char *other_phone; + char *other_po_box; + char *other_postal_code; + char *other_state; + char *other_street; + char *pager_phone; + char *personal_homepage; + char *pref_name; + char *primary_fax; + char *primary_phone; + char *profession; + char *radio_phone; + int rich_text; // 1 = true, 0 = false + char *spouse_name; + char *suffix; + char *surname; + char *telex; + char *transmittable_display_name; + char *ttytdd_phone; + FILETIME *wedding_anniversary; } pst_item_contact; + typedef struct pst_item_attach { - char *filename1; - char *filename2; - char *mimetype; - char *data; - size_t size; - uint64_t id2_val; - uint64_t id_val; // calculated from id2_val during creation of record - int32_t method; - int32_t position; - int32_t sequence; - struct pst_item_attach *next; + char *filename1; + char *filename2; + char *mimetype; + char *data; + size_t size; + uint64_t id2_val; + uint64_t id_val; // calculated from id2_val during creation of record + int32_t method; + int32_t position; + int32_t sequence; + struct pst_item_attach *next; } pst_item_attach; + typedef struct pst_item_extra_field { - char *field_name; - char *value; - struct pst_item_extra_field *next; + char *field_name; + char *value; + struct pst_item_extra_field *next; } pst_item_extra_field; + typedef struct pst_item_journal { - FILETIME *end; - FILETIME *start; - char *type; + FILETIME *end; + FILETIME *start; + char *type; } pst_item_journal; + typedef struct pst_item_appointment { - FILETIME *end; - char *location; - FILETIME *reminder; - FILETIME *start; - char *timezonestring; - int32_t showas; - int32_t label; - int all_day; // 1 = true, 0 = false + FILETIME *end; + char *location; + FILETIME *reminder; + FILETIME *start; + char *timezonestring; + int32_t showas; + int32_t label; + int all_day; // 1 = true, 0 = false } pst_item_appointment; + typedef struct pst_item { - struct pst_item_email *email; // data reffering to email - struct pst_item_folder *folder; // data reffering to folder - struct pst_item_contact *contact; // data reffering to contact - struct pst_item_attach *attach; // linked list of attachments - struct pst_item_message_store *message_store; // data referring to the message store - struct pst_item_extra_field *extra_fields; // linked list of extra headers and such - struct pst_item_journal *journal; // data reffering to a journal entry - struct pst_item_appointment *appointment; // data reffering to a calendar entry - int type; - char *ascii_type; - char *file_as; - char *comment; - int32_t message_size; - char *outlook_version; - char *record_key; // probably 16 bytes long. - size_t record_key_size; - int response_requested; // 1 = true, 0 = false - FILETIME *create_date; - FILETIME *modify_date; - int private_member; // 1 = true, 0 = false + struct pst_item_email *email; // data reffering to email + struct pst_item_folder *folder; // data reffering to folder + struct pst_item_contact *contact; // data reffering to contact + struct pst_item_attach *attach; // linked list of attachments + struct pst_item_message_store *message_store; // data referring to the message store + struct pst_item_extra_field *extra_fields; // linked list of extra headers and such + struct pst_item_journal *journal; // data reffering to a journal entry + struct pst_item_appointment *appointment; // data reffering to a calendar entry + int type; + char *ascii_type; + char *file_as; + char *comment; + int32_t message_size; + char *outlook_version; + char *record_key; // probably 16 bytes long. + size_t record_key_size; + int response_requested; // 1 = true, 0 = false + FILETIME *create_date; + FILETIME *modify_date; + int private_member; // 1 = true, 0 = false } pst_item; + typedef struct pst_x_attrib_ll { - uint32_t type; - uint32_t mytype; - uint32_t map; - void *data; - struct pst_x_attrib_ll *next; + uint32_t type; + uint32_t mytype; + uint32_t map; + void *data; + struct pst_x_attrib_ll *next; } pst_x_attrib_ll; + typedef struct pst_file { - pst_index_ll *i_head, *i_tail; - pst_index2_ll *i2_head; - pst_desc_ll *d_head, *d_tail; - pst_x_attrib_ll *x_head; + pst_index_ll *i_head, *i_tail; + pst_index2_ll *i2_head; + pst_desc_ll *d_head, *d_tail; + pst_x_attrib_ll *x_head; - //set this to 0 to read 32-bit pst files (pre Outlook 2003) - //set this to 1 to read 64-bit pst files (Outlook 2003 and later) - int do_read64; + //set this to 0 to read 32-bit pst files (pre Outlook 2003) + //set this to 1 to read 64-bit pst files (Outlook 2003 and later) + int do_read64; - uint64_t index1; - uint64_t index1_back; - uint64_t index2; - uint64_t index2_back; - FILE * fp; // file pointer to opened PST file - uint64_t size; // pst file size - unsigned char encryption; // pst encryption setting - unsigned char ind_type; // pst index type + uint64_t index1; + uint64_t index1_back; + uint64_t index2; + uint64_t index2_back; + FILE * fp; // file pointer to opened PST file + uint64_t size; // pst file size + unsigned char encryption; // pst encryption setting + unsigned char ind_type; // pst index type } pst_file; + typedef struct pst_block_offset { - int16_t from; - int16_t to; + int16_t from; + int16_t to; } pst_block_offset; + typedef struct pst_block_offset_pointer { - unsigned char *from; - unsigned char *to; - int needfree; + unsigned char *from; + unsigned char *to; + int needfree; } pst_block_offset_pointer; -struct pst_num_item { - uint32_t id; - unsigned char *data; - uint32_t type; - size_t size; - char *extra; -}; + +typedef struct pst_num_item { + uint32_t id; // not an id1 or id2, this is actually some sort of type code + unsigned char *data; + uint32_t type; + size_t size; + char *extra; +} pst_num_item; + typedef struct pst_num_array { - int32_t count_item; - int32_t orig_count; - int32_t count_array; - struct pst_num_item ** items; - struct pst_num_array *next; + int32_t count_item; + int32_t orig_count; + int32_t count_array; + struct pst_num_item ** items; + struct pst_num_array *next; } pst_num_array; -struct holder { - unsigned char **buf; - FILE * fp; - int base64; - char base64_extra_chars[3]; - uint32_t base64_extra; -}; + +typedef struct pst_holder { + unsigned char **buf; + FILE * fp; + int base64; + char base64_extra_chars[3]; + uint32_t base64_extra; +} pst_holder; + + +typedef struct pst_subblock { + unsigned char *buf; + size_t read_size; + size_t i_offset; +} pst_subblock; + + +typedef struct pst_subblocks { + size_t subblock_count; + pst_subblock *subs; +} pst_subblocks; + // prototypes int pst_open(pst_file *pf, char *name, char *mode); @@ -512,7 +553,7 @@ void pst_free_id (pst_index_ll *head); void pst_free_desc (pst_desc_ll *head); void pst_free_xattrib(pst_x_attrib_ll *x); -int pst_getBlockOffsetPointer(pst_file *pf, pst_index2_ll *i2_head, unsigned char *buf, size_t read_size, uint32_t i_offset, uint32_t offset, pst_block_offset_pointer *p); +int pst_getBlockOffsetPointer(pst_file *pf, pst_index2_ll *i2_head, pst_subblocks *subblocks, uint32_t offset, pst_block_offset_pointer *p); int pst_getBlockOffset(unsigned char *buf, size_t read_size, uint32_t i_offset, uint32_t offset, pst_block_offset *p); pst_index2_ll* pst_build_id2(pst_file *pf, pst_index_ll* list, pst_index2_ll* head_ptr); pst_index_ll* pst_getID(pst_file* pf, uint64_t id); @@ -527,8 +568,8 @@ size_t pst_ff_getIDblock_dec(pst_file *pf, uint64_t id, unsigned char **b); size_t pst_ff_getIDblock(pst_file *pf, uint64_t id, unsigned char** b); size_t pst_ff_getID2block(pst_file *pf, uint64_t id2, pst_index2_ll *id2_head, unsigned char** buf); -size_t pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, struct holder *h); -size_t pst_ff_compile_ID(pst_file *pf, uint64_t id, struct holder *h, size_t size); +size_t pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, pst_holder *h); +size_t pst_ff_compile_ID(pst_file *pf, uint64_t id, pst_holder *h, size_t size); int pst_strincmp(char *a, char *b, size_t x); int pst_stricmp(char *a, char *b);
--- a/xml/libpst.in Fri Jan 18 15:07:12 2008 -0800 +++ b/xml/libpst.in Sat Jan 19 10:47:16 2008 -0800 @@ -1367,16 +1367,26 @@ </para> <para> Note the b5offset of 0x0020, which is a type that I will call an index - reference. Such index references have at least two different forms, and - may point to data either in this block, or in some other block. + reference. Such index references have at least two different forms, + and may point to data either in this block, or in some other block. External pointer references have the low order 4 bits all set, and are ID2 values that can be used to fetch data. This value of 0x0020 is an - internal pointer reference, which needs to be right shifted by 4 bits to - become 0x0002, which is then a byte offset to be added to the above + internal pointer reference, which needs to be right shifted by 4 bits + to become 0x0002, which is then a byte offset to be added to the above indexOffset plus two (to skip the count), so it points to the (0xc, 0x14) pair. </para> <para> + So far we have only described internal index references where the high + order 16 bits are zero. That suffices for single descriptor + blocks. But in the case of the type 0x0101 descriptor block, we have + an array of subblocks. In this case, the high order 16 bits of an + internal index reference are used to select the subblock. Each + subblock starts with a 16 bit indexOffset which points to the count + and array of 16 bit integer pairs which are offsets in the current + subblock. + </para> + <para> Finally, we have the offset and size of the "b5" block located at offset 0xc with a size of 8 bytes in this descriptor block. The "b5" block has the following format: @@ -1433,10 +1443,6 @@ <para> The following item types are known, but not all of these are implemented in the code yet. - Note: it appears that some types can have a IPOS value or a ID2 value - depending on the size of the field in question. It is safer to check - every field than for me to say what the "usually" contain. Absolute - values though, are generally going to be constant. </para> <literallayout class="monospaced"><![CDATA[ 0002 AutoForward allowed @@ -1778,24 +1784,27 @@ <refsect1 id='pst.file.desc3.32.5'> <title>32 bit Associated Descriptor Item 0x0101</title> <para> - This descriptor block contains a list of ID1 values. It is used when an - ID1 (that would normally point to a type 0x7cec or 0xbcec descriptor block) - contains more data than can fit in any single descriptor of those types. - In this case, it points to a type 0x0101 block, which contains a list - of ID1 values that themselves point to the actual descriptor blocks. - The descriptor blocks that are pointed to by this list of ID1 values - are almost but not quite the same as the standard 0xbcec blocks. Decoding - these blocks is still incomplete. + This descriptor block contains a list of ID1 values. It is used when + an ID1 (that would normally point to a type 0x7cec or 0xbcec + descriptor block) contains more data than can fit in any single + descriptor of those types. In this case, it points to a type 0x0101 + block, which contains a list of ID1 values that themselves point to + the actual descriptor blocks. The total length value in the 0x0101 + header is the sum of the lengths of the blocks pointed to by the list + of ID1 values. The result is an array of subblocks, that may contain + index references where the high order 16 bits specify which descriptor + subblock to use. Only the first descriptor subblock contains the + signature (0xbcec or 0x7cec). </para> <literallayout class="monospaced"><![CDATA[ 0000 01 01 02 00 26 28 00 00 18 77 0c 00 b8 04 00 00 0000 signature [2 bytes] 0x0101 constant 0002 count [2 bytes] 0x0002 in this case -0004 unknown [4 bytes] 0x002826 in this case +0004 total length [4 bytes] 0x002826 in this case repeating -0008 id [4 bytes] 0x0c7718 in this case -000c id [4 bytes] 0x0004b8 in this case +0008 id1 [4 bytes] 0x0c7718 in this case +000c id1 [4 bytes] 0x0004b8 in this case ]]></literallayout> </refsect1> @@ -1810,10 +1819,10 @@ 0000 signature [2 bytes] 0x0101 constant 0002 count [2 bytes] 0x0002 in this case -0004 unknown [4 bytes] 0x0029ea in this case +0004 total length [4 bytes] 0x0029ea in this case repeating -0008 id [8 bytes] 0x008310 in this case -0010 id [8 bytes] 0x00831c in this case +0008 id1 [8 bytes] 0x008310 in this case +0010 id1 [8 bytes] 0x00831c in this case ]]></literallayout> </refsect1>