changeset 28:51d826f31329

more cleanup from Arne, document 7c block format
author carl
date Sat, 25 Feb 2006 16:03:45 -0800
parents 99e6b70cdfb3
children 311e52c62f06
files configure.in package src/define.h src/libpst.c src/libpst.h src/readpst.c xml/libpst.in
diffstat 7 files changed, 251 insertions(+), 127 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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
--- 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
--- 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;
--- 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
--- 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"));
--- 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 @@
 
         <refsect1 id='readpst.description.1'>
             <title>Description</title>
-            <para><command>readpst</command> 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.
+            <para><command>readpst</command> 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.
             </para>
         </refsect1>
 
@@ -65,8 +65,9 @@
                 <varlistentry>
                     <term>-d <replaceable class="parameter">debug-file</replaceable></term>
                     <listitem><para>
-                        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 <command>readpstlog</command>.
+                        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 <command>readpstlog</command>.
                     </para></listitem>
                 </varlistentry>
                 <varlistentry>
@@ -110,20 +111,19 @@
                     <listitem><para>
                         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.
                     </para></listitem>
                 </varlistentry>
                 <varlistentry>
                     <term>-M</term>
                     <listitem><para>
                         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.
                     </para></listitem>
                 </varlistentry>
                 <varlistentry>
@@ -165,7 +165,7 @@
             <title>Copyright</title>
             <para>
                 Copyright (C) 2002 by David Smith &lt;dave.s@earthcorp.com&gt;.
-                XML version Copyright (C) 2005 by 510 Software Group &lt;carl@five-ten-sg.com&gt;.
+                XML version Copyright (C) 2006 by 510 Software Group &lt;carl@five-ten-sg.com&gt;.
             </para>
             <para>
                 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
 ]]></literallayout>
             <para>
                 We only support index type 0x0E and encryption type 0x01.
             </para>
             <para>
-                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.
             </para>
             <para>
-                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.
             </para>
         </refsect1>
@@ -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
 ]]></literallayout>
             <para>
-                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.
             </para>
             <para>
-                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.
             </para>
         </refsect1>
@@ -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
 ]]></literallayout>
             <para>
-                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.
             </para>
             <para>
@@ -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
 ]]></literallayout>
             <para>
-                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.
             </para>
             <para>
-                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.
             </para>
         </refsect1>
@@ -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
 ]]></literallayout>
             <para>
-                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.
             </para>
             <para>
@@ -848,12 +848,13 @@
         </refsect1>
 
         <refsect1 id='pst.file.desc.5'>
-            <title>Associated Descriptor Item</title>
+            <title>Associated Descriptor Item 0xbcec</title>
             <para>
-                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.
             </para>
             <literallayout class="monospaced"><![CDATA[
 0000  3c 01 ec bc  20 00 00 00  00 00 00 00  b5 02 06 00
@@ -879,23 +880,25 @@
 0140  0c 00 14 00  7c 00 8c 00  93 00 ab 00  c3 00 db 00
 0150  f3 00 0b 01  23 01 3b 01
 
-0000  index-offset    [2 bytes] 0x013c     in this case
+0000  indexOffset     [2 bytes] 0x013c     in this case
 0002  signature       [2 bytes] 0xbcec     constant
 0004  offset          [2 bytes] 0x0020     in this case
 ]]></literallayout>
             <para>
-                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.
             </para>
             <para>
                 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 @@
             <para>
                 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:
             </para>
             <literallayout class="monospaced"><![CDATA[
-0000  item-type       [2 bytes]
-0002  reference-type  [2 bytes]
+0000  itemType        [2 bytes]
+0002  referenceType   [2 bytes]
 0004  value           [4 bytes]
 ]]></literallayout>
             <para>
@@ -1167,5 +1170,125 @@
 ]]></literallayout>
         </refsect1>
 
+        <refsect1 id='pst.file.desc2.5'>
+            <title>Associated Descriptor Item 0x7cec</title>
+            <para>
+                This style of descriptor block is similar to the BCEC format.
+            </para>
+            <literallayout class="monospaced"><![CDATA[
+0000  7a 01 ec 7c  40 00 00 00  00 00 00 00  b5 04 02 00
+0010  60 00 00 00  7c 18 60 00  60 00 62 00  65 00 20 00
+0020  00 00 80 00  00 00 00 00  00 00 03 00  20 0e 0c 00
+0030  04 03 1e 00  01 30 2c 00  04 0b 1e 00  03 37 28 00
+0040  04 0a 1e 00  04 37 14 00  04 05 03 00  05 37 10 00
+0050  04 04 1e 00  07 37 24 00  04 09 1e 00  08 37 20 00
+0060  04 08 02 01  0a 37 18 00  04 06 03 00  0b 37 08 00
+0070  04 02 1e 00  0d 37 1c 00  04 07 1e 00  0e 37 40 00
+0080  04 10 02 01  0f 37 30 00  04 0c 1e 00  11 37 34 00
+0090  04 0d 1e 00  12 37 3c 00  04 0f 1e 00  13 37 38 00
+00A0  04 0e 03 00  f2 67 00 00  04 00 03 00  f3 67 04 00
+00B0  04 01 03 00  09 69 44 00  04 11 03 00  fa 7f 5c 00
+00C0  04 15 40 00  fb 7f 4c 00  08 13 40 00  fc 7f 54 00
+00D0  08 14 03 00  fd 7f 48 00  04 12 0b 00  fe 7f 60 00
+00E0  01 16 0b 00  ff 7f 61 00  01 17 45 82  00 00 00 00
+00F0  45 82 00 00  78 3c 00 00  ff ff ff ff  49 1e 00 00
+0100  06 00 00 00  00 00 00 00  a0 00 00 00  00 00 00 00
+0110  00 00 00 00  00 00 00 00  00 00 00 00  c0 00 00 00
+0120  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00
+0130  00 00 00 00  00 00 00 00  00 00 00 00  00 40 dd a3
+0140  57 45 b3 0c  00 40 dd a3  57 45 b3 0c  02 00 00 00
+0150  00 00 fa 10  3e 2a 86 48  86 f7 14 03  0a 03 02 01
+0160  4a 2e 20 44  61 76 69 64  20 4b 61 72  61 6d 27 73
+0170  20 42 69 72  74 68 64 61  79 00 06 00  00 00 0c 00
+0180  14 00 ea 00  f0 00 55 01  60 01 79 01
+
+0000  indexOffset     [2 bytes] 0x017a     in this case
+0002  signature       [2 bytes] 0x7cec     constant
+0004  offset          [2 bytes] 0x0040     in this case
+]]></literallayout>
+            <para>
+                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.
+            </para>
+            <para>
+                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:
+            </para>
+            <literallayout class="monospaced"><![CDATA[
+0000  signature       [1 bytes] 0x7c       constant
+0001  itemCount       [1 bytes] 0x18       in this case
+0002  unknown         [2 bytes] 0x0060     in this case
+0004  unknown         [2 bytes] 0x0060     in this case
+0006  unknown         [2 bytes] 0x0062     in this case
+0008  recordSize      [2 bytes] 0x0065     in this case
+000a  b5Offset        [2 bytes] 0x0020     in this case
+000c  unknown         [2 bytes] 0x0000     in this case
+000e  index2Offset    [2 bytes] 0x0080     in this case
+0010  unknown         [2 bytes] 0x0000     in this case
+0012  unknown         [2 bytes] 0x0000     in this case
+0014  unknown         [2 bytes] 0x0000     in this case
+]]></literallayout>
+            <para>
+                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:
+            </para>
+            <literallayout class="monospaced"><![CDATA[
+0000  signature       [2 bytes] 0x04b5     constant
+0002  unknown         [2 bytes] 0x0002     in this case
+0004  offset          [4 bytes] 0x0060     in this case
+]]></literallayout>
+            <para>
+                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.
+            </para>
+            <para>
+                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.
+            </para>
+            <para>
+                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:
+            </para>
+            <literallayout class="monospaced"><![CDATA[
+0000  referenceType   [2 bytes]
+0002  itemType        [2 bytes]
+0004  ind2Offset      [2 bytes]
+0006  unknown         [2 bytes]
+]]></literallayout>
+            <para>
+                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.
+            </para>
+        </refsect1>
+
     </refentry>
 </reference>