# HG changeset patch # User carl # Date 1140912225 28800 # Node ID 51d826f31329b8de57da744fd95b0df2b69df495 # Parent 99e6b70cdfb34d722ee555b9b4022320b74b759c more cleanup from Arne, document 7c block format diff -r 99e6b70cdfb3 -r 51d826f31329 configure.in --- a/configure.in Sat Feb 25 16:03:45 2006 -0800 +++ b/configure.in Sat Feb 25 16:03:45 2006 -0800 @@ -1,7 +1,7 @@ AC_INIT(configure.in) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(libpst,0.5.3) +AM_INIT_AUTOMAKE(libpst,0.5.4) AC_PATH_PROGS(BASH, bash) AC_LANG_CPLUSPLUS diff -r 99e6b70cdfb3 -r 51d826f31329 package --- a/package Sat Feb 25 16:03:45 2006 -0800 +++ b/package Sat Feb 25 16:03:45 2006 -0800 @@ -12,14 +12,16 @@ ./configure >/dev/null (cd xml; make; make distclean) cp -a html/*html $web -## make -## pst=/home/ldap/outlook.pst -## rm -f pst2ldif.log my.log -## src/pst2ldif -b 'o=ams-cc.com, c=US' -c 'newPerson' $pst >ams.ldif -## src/readpstlog pst2ldif.log | less >my.log -## hexdump -C -v $pst >pst.dump -## chown --recursive carl:carl * -## exit +if [ "$1" == "test" ]; then + make + pst=/home/ldap/outlook.pst + rm -f pst2ldif.log my.log + src/pst2ldif -b 'o=ams-cc.com, c=US' -c 'newPerson' $pst >ams.ldif + src/readpstlog pst2ldif.log | less >my.log + hexdump -C -v $pst >pst.dump + chown --recursive carl:carl * + exit +fi make distcheck >$distlog 2>&1 if [ $? -eq 0 ]; then diff -r 99e6b70cdfb3 -r 51d826f31329 src/define.h --- a/src/define.h Sat Feb 25 16:03:45 2006 -0800 +++ b/src/define.h Sat Feb 25 16:03:45 2006 -0800 @@ -6,8 +6,8 @@ */ // last one wins +#define DEBUG_ALL #undef DEBUG_ALL -#define DEBUG_ALL #ifndef DEFINEH_H #define DEFINEH_H diff -r 99e6b70cdfb3 -r 51d826f31329 src/libpst.c --- a/src/libpst.c Sat Feb 25 16:03:45 2006 -0800 +++ b/src/libpst.c Sat Feb 25 16:03:45 2006 -0800 @@ -1027,7 +1027,6 @@ item->attach = attach; x++; } - item->current_attach = item->attach; if (_pst_process(list, item)) { DEBUG_WARN(("ERROR _pst_process() failed with attachments\n")); @@ -1051,7 +1050,6 @@ attach = attach->next; continue; } - item->current_attach = attach; if (_pst_process(list, item)) { DEBUG_WARN(("ERROR _pst_process() failed with an attachment\n")); _pst_free_list(list); @@ -1072,7 +1070,6 @@ attach = attach->next; } } - item->current_attach = item->attach; //reset back to first } _pst_free_id2(id2_head); @@ -1087,7 +1084,7 @@ pst_block_offset block_offset; // pst_index_ll *rec = NULL; u_int32_t size = 0, t_ptr = 0, fr_ptr = 0, to_ptr = 0, ind_ptr = 0, x = 0; - u_int32_t num_recs = 0, count_rec = 0, ind2_ptr = 0, list_start = 0, num_list = 0, cur_list = 0; + u_int32_t num_recs = 0, count_rec = 0, ind2_ptr = 0, ind2_end = 0, list_start = 0, num_list = 0, cur_list = 0; int32_t block_type, rec_size; size_t read_size=0; pst_x_attrib_ll *mapptr; @@ -1164,9 +1161,9 @@ } _pst_getBlockOffset(buf, read_size, ind_ptr, table_rec.value, &block_offset); - list_start = fr_ptr = block_offset.from; - to_ptr = block_offset.to; - num_list = (to_ptr - fr_ptr)/sizeof(table_rec); + list_start = block_offset.from; + to_ptr = block_offset.to; + num_list = (to_ptr - list_start)/sizeof(table_rec); num_recs = 1; // only going to one object in these blocks rec_size = 0; // doesn't matter cause there is only one object } @@ -1204,11 +1201,10 @@ _pst_getBlockOffset(buf, read_size, ind_ptr, seven_c_blk.b_five_offset, &block_offset); fr_ptr = block_offset.from; memcpy(&table_rec, &(buf[fr_ptr]), sizeof(table_rec)); - DEBUG_EMAIL(("before convert %#x\n", table_rec.type)); LE16_CPU(table_rec.type); - DEBUG_EMAIL(("after convert %#x\n", table_rec.type)); LE16_CPU(table_rec.ref_type); LE32_CPU(table_rec.value); + DEBUG_EMAIL(("after convert %#x\n", table_rec.type)); if (table_rec.type != 0x04B5) { // different constant than a type 1 record WARN(("Unknown second block constant - %#X for id %#x\n", table_rec.type, block_id)); @@ -1229,6 +1225,7 @@ _pst_getBlockOffset(buf, read_size, ind_ptr, seven_c_blk.ind2_offset, &block_offset); ind2_ptr = block_offset.from; + ind2_end = block_offset.to; } else { WARN(("ERROR: Unknown block constant - %#X for id %#x\n", block_hdr.type, block_id)); DEBUG_HEXDUMPC(buf, read_size,0x10); @@ -1258,6 +1255,7 @@ memcpy(&table_rec, &(buf[fr_ptr]), sizeof(table_rec)); LE16_CPU(table_rec.type); LE16_CPU(table_rec.ref_type); + //LE32_CPU(table_rec.value); // done later, some may be order invariant fr_ptr += sizeof(table_rec); } else if (block_type == 2) { // we will copy the table2_rec values into a table_rec record so that we can keep the rest of the code @@ -1270,9 +1268,10 @@ // table_rec and table2_rec are arranged differently, so assign the values across table_rec.type = table2_rec.type; table_rec.ref_type = table2_rec.ref_type; - if ((ind2_ptr+table2_rec.ind2_off > 0) && - (ind2_ptr+table2_rec.ind2_off < read_size-sizeof(table_rec.value))) + if (ind2_ptr+table2_rec.ind2_off <= ind2_end) { memcpy(&(table_rec.value), &(buf[ind2_ptr+table2_rec.ind2_off]), sizeof(table_rec.value)); + //LE32_CPU(table_rec.value); // done later, some may be order invariant + } else { DEBUG_WARN (("trying to read more than blocks size. Size=%#x, Req.=%#x," " Req Size=%#x\n", read_size, ind2_ptr+table2_rec.ind2_off, @@ -1473,7 +1472,7 @@ return -1; } - attach = item->current_attach; // a working variable + attach = item->attach; // a working variable while (list) { x = 0; diff -r 99e6b70cdfb3 -r 51d826f31329 src/libpst.h --- a/src/libpst.h Sat Feb 25 16:03:45 2006 -0800 +++ b/src/libpst.h Sat Feb 25 16:03:45 2006 -0800 @@ -385,7 +385,6 @@ 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_attach *current_attach; // pointer to current attachment 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 diff -r 99e6b70cdfb3 -r 51d826f31329 src/readpst.c --- a/src/readpst.c Sat Feb 25 16:03:45 2006 -0800 +++ b/src/readpst.c Sat Feb 25 16:03:45 2006 -0800 @@ -918,8 +918,8 @@ void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char boundary[], pst_file* pst) { char *enc; // base64 encoded attachment - DEBUG_MAIN(("write_inline_attachment: Attachment Size is %i\n", item->current_attach->size)); - DEBUG_MAIN(("write_inline_attachment: Attachment Pointer is %p\n", item->current_attach->data)); + DEBUG_MAIN(("write_inline_attachment: Attachment Size is %i\n", current_attach->size)); + DEBUG_MAIN(("write_inline_attachment: Attachment Pointer is %p\n", current_attach->data)); if (current_attach->data != NULL) { if ((enc = base64_encode (current_attach->data, current_attach->size)) == NULL) { DEBUG_MAIN(("write_inline_attachment: ERROR base64_encode returned NULL. Must have failed\n")); @@ -957,6 +957,7 @@ int attach_num, base64_body = 0; time_t em_time; char *c_time; + pst_item_attach* current_attach; // convert the sent date if it exists, or set it to a fixed date if (item->email->sent_date != NULL) { @@ -1154,17 +1155,17 @@ if (item->email->rtf_compressed != NULL) { DEBUG_MAIN(("Adding RTF body as attachment\n")); - item->current_attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach)); - memset(item->current_attach, 0, sizeof(pst_item_attach)); - item->current_attach->next = item->attach; - item->attach = item->current_attach; - item->current_attach->data = lzfu_decompress(item->email->rtf_compressed); - item->current_attach->filename2 = xmalloc(strlen(RTF_ATTACH_NAME)+2); - strcpy(item->current_attach->filename2, RTF_ATTACH_NAME); - item->current_attach->mimetype = xmalloc(strlen(RTF_ATTACH_TYPE)+2); - strcpy(item->current_attach->mimetype, RTF_ATTACH_TYPE); - memcpy(&(item->current_attach->size), item->email->rtf_compressed+sizeof(int32_t), sizeof(int32_t)); - LE32_CPU(item->current_attach->size); + current_attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach)); + memset(current_attach, 0, sizeof(pst_item_attach)); + current_attach->next = item->attach; + item->attach = current_attach; + current_attach->data = lzfu_decompress(item->email->rtf_compressed); + current_attach->filename2 = xmalloc(strlen(RTF_ATTACH_NAME)+2); + strcpy(current_attach->filename2, RTF_ATTACH_NAME); + current_attach->mimetype = xmalloc(strlen(RTF_ATTACH_TYPE)+2); + strcpy(current_attach->mimetype, RTF_ATTACH_TYPE); + memcpy(&(current_attach->size), item->email->rtf_compressed+sizeof(int32_t), sizeof(int32_t)); + LE32_CPU(current_attach->size); // item->email->rtf_compressed = ; // attach_num++; } @@ -1172,42 +1173,42 @@ // if either the body or htmlbody is encrypted, add them as attachments if (item->email->encrypted_body) { DEBUG_MAIN(("Adding Encrypted Body as attachment\n")); - item->current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); - memset(item->current_attach, 0, sizeof(pst_item_attach)); - item->current_attach->next = item->attach; - item->attach = item->current_attach; + current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); + memset(current_attach, 0, sizeof(pst_item_attach)); + current_attach->next = item->attach; + item->attach = current_attach; - item->current_attach->data = item->email->encrypted_body; - item->current_attach->size = item->email->encrypted_body_size; + current_attach->data = item->email->encrypted_body; + current_attach->size = item->email->encrypted_body_size; item->email->encrypted_body = NULL; } if (item->email->encrypted_htmlbody) { DEBUG_MAIN(("Adding encrypted HTML body as attachment\n")); - item->current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); - memset(item->current_attach, 0, sizeof(pst_item_attach)); - item->current_attach->next = item->attach; - item->attach = item->current_attach; + current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); + memset(current_attach, 0, sizeof(pst_item_attach)); + current_attach->next = item->attach; + item->attach = current_attach; - item->current_attach->data = item->email->encrypted_htmlbody; - item->current_attach->size = item->email->encrypted_htmlbody_size; + current_attach->data = item->email->encrypted_htmlbody; + current_attach->size = item->email->encrypted_htmlbody_size; item->email->encrypted_htmlbody = NULL; } write_email_body(f_output, "The body of this email is encrypted. This isn't supported yet, but the body is now an attachment\n"); } // attachments attach_num = 0; - for(item->current_attach = item->attach; - item->current_attach; - item->current_attach = item->current_attach->next) { + for(current_attach = item->attach; + current_attach; + current_attach = current_attach->next) { DEBUG_MAIN(("write_normal_email: Attempting Attachment encoding\n")); - if (item->current_attach->data == NULL) { - DEBUG_MAIN(("write_normal_email: Data of attachment is NULL!. Size is supposed to be %i\n", item->current_attach->size)); + if (current_attach->data == NULL) { + DEBUG_MAIN(("write_normal_email: Data of attachment is NULL!. Size is supposed to be %i\n", current_attach->size)); } attach_num++; if (mode == MODE_SEPERATE && !mode_MH) - write_separate_attachment(f_name, item->current_attach, attach_num, pst); + write_separate_attachment(f_name, current_attach, attach_num, pst); else - write_inline_attachment(f_output, item->current_attach, boundary, pst); + write_inline_attachment(f_output, current_attach, boundary, pst); } if (mode != MODE_SEPERATE) { /* do not add a boundary after the last attachment for mode_MH */ DEBUG_MAIN(("write_normal_email: Writing buffer between emails\n")); diff -r 99e6b70cdfb3 -r 51d826f31329 xml/libpst.in --- a/xml/libpst.in Sat Feb 25 16:03:45 2006 -0800 +++ b/xml/libpst.in Sat Feb 25 16:03:45 2006 -0800 @@ -47,9 +47,9 @@ Description - readpst is a program that can read an Outlook PST (Personal Folders) file - and convert it into an mbox file, a format suitable for KMail, a recursive mbox - structure, or separate emails. + readpst is a program that can read an Outlook + PST (Personal Folders) file and convert it into an mbox file, a format + suitable for KMail, a recursive mbox structure, or separate emails. @@ -65,8 +65,9 @@ -d debug-file - Specify name of debug log file. Defaults to "readpst.log". The log - file is not an ascii file, it is a binary file readable by readpstlog. + Specify name of debug log file. Defaults to "readpst.log". The + log file is not an ascii file, it is a binary file readable + by readpstlog. @@ -110,20 +111,19 @@ Output messages into separate files. This will create folders as named in the PST file, and will put each email in its own file. These files - will be numbered from 000000000 increasing in intervals of 1 (ie - 000000000, 000000001, 0000000002). Any attachments are saved alongside - each email as 000000000-attach0, or with the name of the attachment if - one is present. + will be numbered from 1 increasing in intervals of 1 (ie 1, 2, 3, ...). + Any attachments are saved alongside each email as XXXXXXXXX-attach1, + XXXXXXXXX-attach2 and so on, or with the name of the attachment if one + is present. -M Output messages in MH format as separate files. This will create - folders as named in the PST file, and will put each email in its own - file. These files will be numbered from 1 to n with no leading zeros. - Any attachments are saved alongside each email as 000000000-attach0, or - with the name of the attachment if one is present. + folders as named in the PST file, and will put each email together with + any attachments into its own file. These files will be numbered from 1 + to n with no leading zeros. @@ -165,7 +165,7 @@ Copyright Copyright (C) 2002 by David Smith <dave.s@earthcorp.com>. - XML version Copyright (C) 2005 by 510 Software Group <carl@five-ten-sg.com>. + XML version Copyright (C) 2006 by 510 Software Group <carl@five-ten-sg.com>. This program is free software; you can redistribute it and/or modify it @@ -542,27 +542,27 @@ 01f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 signature [4 bytes] 0x4e444221 constant -000a index type [1 byte] 0x0e constant -01cd encryption type [1 byte] 0x01 constant +000a indexType [1 byte] 0x0e constant +01cd encryptionType [1 byte] 0x01 constant 00a8 total file size [4 bytes] 0x270400 in this case -00c0 back-pointer-1 [4 bytes] 0x021eb4 in this case -00c4 offset-index-1 [4 bytes] 0x005400 in this case -00b8 back-pointer-2 [4 bytes] 0x021ebc in this case -00bc offset-index-2 [4 bytes] 0x0c7e00 in this case +00c0 backPointer1 [4 bytes] 0x021eb4 in this case +00c4 offsetIndex1 [4 bytes] 0x005400 in this case +00b8 backPointer2 [4 bytes] 0x021ebc in this case +00bc offsetIndex2 [4 bytes] 0x0c7e00 in this case ]]> We only support index type 0x0E and encryption type 0x01. - offset-index-1 is the file offset of the root of the + offsetIndex1 is the file offset of the root of the index1 b-tree, which contains (ID1, offset, size, unknown) tuples - for each item in the file. back-pointer-1 is the value that should + for each item in the file. backPointer1 is the value that should appear in the parent pointer of that root node. - offset-index-2 is the file offset of the root of the + offsetIndex2 is the file offset of the root of the index2 b-tree, which contains (ID2, DESC-ID1, LIST-ID1, PARENT-ID2) - tuples for each item in the file. back-pointer-2 is the value that should + tuples for each item in the file. backPointer2 is the value that should appear in the parent pointer of that root node. @@ -617,21 +617,21 @@ 01ec 00 00 00 00 02 29 0c 02 80 80 b6 4a 01f8 b4 1e 02 00 27 9c cc 56 58 27 03 00 -01f0 item-count [1 byte] 0x02 in this case -01f1 max-item-count [1 byte] 0x29 constant -01f3 node-level [1 byte] 0x02 in this case -01f8 back-pointer [4 bytes] 0x021eb4 in this case +01f0 itemCount [1 byte] 0x02 in this case +01f1 maxItemCount [1 byte] 0x29 constant +01f3 nodeLevel [1 byte] 0x02 in this case +01f8 backPointer [4 bytes] 0x021eb4 in this case ]]> - The item-count specifies the number of 12 byte records that - are active. The node-level is non-zero for this style of nodes. - The leaf nodes have a different format. The back-pointer must - match the back-pointer from the triple that pointed to this node. + The itemCount specifies the number of 12 byte records that + are active. The nodeLevel is non-zero for this style of nodes. + The leaf nodes have a different format. The backPointer must + match the backPointer from the triple that pointed to this node. - Each item in this node is a triple of (ID, back-pointer, offset) + Each item in this node is a triple of (ID, backPointer, offset) where the offset points to the next deeper node in the tree, the - back-pointer value must match the back-pointer in that deeper node, + backPointer value must match the backPointer in that deeper node, and ID is the lowest ID value in the subtree. @@ -686,15 +686,15 @@ 01ec 00 00 00 00 1f 29 0c 00 80 80 5b b3 01f8 5a 67 01 00 4f ae 70 a7 92 06 00 00 -01f0 item-count [1 byte] 0x1f in this case -01f1 max-item-count [1 byte] 0x29 constant -01f3 node-level [1 byte] 0x00 in this case -01f8 back-pointer [4 bytes] 0x01675a in this case +01f0 itemCount [1 byte] 0x1f in this case +01f1 maxItemCount [1 byte] 0x29 constant +01f3 nodeLevel [1 byte] 0x00 in this case +01f8 backPointer [4 bytes] 0x01675a in this case ]]> - The item-count specifies the number of 12 byte records that - are active. The node-level is zero for these leaf nodes. - The back-pointer must match the back-pointer from the triple + The itemCount specifies the number of 12 byte records that + are active. The nodeLevel is zero for these leaf nodes. + The backPointer must match the backPointer from the triple that pointed to this node. @@ -752,21 +752,21 @@ 01ec 00 00 00 00 02 29 0c 02 81 81 b2 60 01f8 bc 1e 02 00 7e 70 dc e3 21 00 00 00 -01f0 item-count [1 byte] 0x02 in this case -01f1 max-item-count [1 byte] 0x29 constant -01f3 node-level [1 byte] 0x02 in this case -01f8 back-pointer [4 bytes] 0x021ebc in this case +01f0 itemCount [1 byte] 0x02 in this case +01f1 maxItemCount [1 byte] 0x29 constant +01f3 nodeLevel [1 byte] 0x02 in this case +01f8 backPointer [4 bytes] 0x021ebc in this case ]]> - The item-count specifies the number of 12 byte records that - are active. The node-level is non-zero for this style of nodes. - The leaf nodes have a different format. The back-pointer must - match the back-pointer from the triple that pointed to this node. + The itemCount specifies the number of 12 byte records that + are active. The nodeLevel is non-zero for this style of nodes. + The leaf nodes have a different format. The backPointer must + match the backPointer from the triple that pointed to this node. - Each item in this node is a triple of (ID2, back-pointer, offset) + Each item in this node is a triple of (ID2, backPointer, offset) where the offset points to the next deeper node in the tree, the - back-pointer value must match the back-pointer in that deeper node, + backPointer value must match the backPointer in that deeper node, and ID2 is the lowest ID2 value in the subtree. @@ -811,15 +811,15 @@ 01F0 10 1f 10 00 81 81 a0 9a ae 1e 02 00 89 44 6a 0f 0200 b8 b1 03 00 -01f0 item-count [1 byte] 0x10 in this case -01f1 max-item-count [1 byte] 0x1f constant -01f3 node-level [1 byte] 0x00 in this case -01f8 back-pointer [4 bytes] 0x021eae in this case +01f0 itemCount [1 byte] 0x10 in this case +01f1 maxItemCount [1 byte] 0x1f constant +01f3 nodeLevel [1 byte] 0x00 in this case +01f8 backPointer [4 bytes] 0x021eae in this case ]]> - The item-count specifies the number of 16 byte records that - are active. The node-level is zero for these leaf nodes. - The back-pointer must match the back-pointer from the triple + The itemCount specifies the number of 16 byte records that + are active. The nodeLevel is zero for these leaf nodes. + The backPointer must match the backPointer from the triple that pointed to this node. @@ -848,12 +848,13 @@ - Associated Descriptor Item + Associated Descriptor Item 0xbcec - Contains information about the item, which may be email, contact, or other outlook types. - In the above leaf node, we have a tuple of (0x21, 0x00e638, 0, 0) - 0x00e638 is the ID1 of the associated descriptor, and we can lookup that ID1 value - in the index1 b-tree to find the (offset,size) of the data in the .pst file. + Contains information about the item, which may be email, contact, or + other outlook types. In the above leaf node, we have a tuple of (0x21, + 0x00e638, 0, 0) 0x00e638 is the ID1 of the associated descriptor, and we + can lookup that ID1 value in the index1 b-tree to find the (offset,size) + of the data in the .pst file. - Note the index-offset of 0x013c - starting at that position in the + Note the signature of 0xbcec. There are other descriptor block + formats with other signatures. + Note the indexOffset of 0x013c - starting at that position in the descriptor block, we have an array of two byte integers. The first - integer (0x000b) is a count of the number of overlapping pairs + integer (0x000b) is a (count-1) of the number of overlapping pairs following the count. The first pair is (0, 0xc), the next pair is (0xc, 0x14) - and the last (11th) pair is (0x10b, 0x123). These pairs are (start,end+1) - offsets of items in this block. So we have count+1 integers following + and the last (12th) pair is (0x123, 0x13b). These pairs are (start,end+1) + offsets of items in this block. So we have count+2 integers following the count value. Note the offset of 0x0020, which needs to be right shifted by 4 bits to become 0x0002, which is then a byte offset to be added to the above - index-offset plus two (to skip the count), so it points to the (0xc, 0x14) + indexOffset plus two (to skip the count), so it points to the (0xc, 0x14) pair. 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: @@ -908,13 +911,13 @@ Note the "b5" offset of 0x0040, which needs to be right shifted by 4 bits to become 0x0004, which is then a byte offset to be added to the above - index-offset plus two (to skip the count), so it points to the (0x14, 0x7c) + indexOffset plus two (to skip the count), so it points to the (0x14, 0x7c) pair. We now have the offset 0x14 of the descriptor array, composed of 8 byte entries. Each descriptor entry has the following format: @@ -1167,5 +1170,125 @@ ]]> + + Associated Descriptor Item 0x7cec + + This style of descriptor block is similar to the BCEC format. + + + + Note the signature of 0x7cec. There are other descriptor block + formats with other signatures. + Note the indexOffset of 0x017a - starting at that position in the + descriptor block, we have an array of two byte integers. The first + integer (0x0006) is a (count-1) of the number of overlapping pairs + following the count. The first pair is (0, 0xc), the next pair is (0xc, 0x14) + and the last (7th) pair is (0x160, 0x179). These pairs are (start,end+1) + offsets of items in this block. So we have count+2 integers following + the count value. + + + Note the offset of 0x0040, which needs to be right shifted by 4 bits + to become 0x0004, which is then a byte offset to be added to the above + indexOffset plus two (to skip the count), so it points to the (0x14, 0xea) + pair. We have the offset and size of the "7c" block located at offset 0x14 + with a size of 214 bytes in this case. The "7c" block starts with + a header with the following format: + + + + Note the b5Offset of 0x0020, 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. 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: + + + + Note the "b5" offset of 0x0060, which needs to be right shifted by 4 + bits to become 0x0006, which is then a byte offset to be added to the + above indexOffset plus two (to skip the count), so it points to the + (0xea, 0xf0) pair. That gives us (0xf0 - 0xea)/6 = 1, so we have a + recordCount of one. The actual data between 0xea and 0xf0 is unknown + and unused here. + + + Note the index2Offset above of 0x0080, which needs to be right shifted + by 4 bits to become 0x0008, which is then a byte offset to be added to + the above indexOffset plus two (to skip the count), so it points to the + (0xf0, 0x155) pair. This is an array of tables of four byte integers. + We will call these the IND2 tables. The size of each of these tables is + specified by the recordSize field of the "7c" header. The number of + these tables is the above recordCount value derived from the "b5" block. + + + Now the remaining data in the "7c" block after the header starts at + offset 0x2a. There should be itemCount 8 byte items here, with the + following format: + + + + The ind2Offset is a byte offset into the current IND2 table of a four + byte integer value. Once we fetch that, we have the same triple (item + type, reference type, value) as we find in the 0xbcec style descriptor + blocks. These 8 byte descriptors are processed recordCount times, each + time using the next IND2 table. The item and reference types are as + described above for the 0xbcec format descriptor block. + + +