changeset 48:f66078abed38

more fixes for 64 bit format
author carl
date Fri, 18 Jan 2008 15:07:12 -0800
parents 5fb8d997feed
children 17654fbdf76b
files AUTHORS ChangeLog configure.in regression/regression-tests.bash src/debug.c src/define.h src/dumpblocks.c src/getidblock.c src/libpst.c src/libpst.h src/lspst.c src/lzfu.c src/readpst.c src/readpstlog.c src/testdebug.c xml/libpst.in
diffstat 16 files changed, 208 insertions(+), 117 deletions(-) [+]
line wrap: on
line diff
--- a/AUTHORS	Sun Jan 13 12:55:59 2008 -0800
+++ b/AUTHORS	Fri Jan 18 15:07:12 2008 -0800
@@ -13,3 +13,4 @@
     Alexander Grau <alexandergrau@gmx.de>
     Antonio Palama <palama@inwind.it>
     Sean Loaring <sloaring@tec-man.com>
+    James Woodcock
--- a/ChangeLog	Sun Jan 13 12:55:59 2008 -0800
+++ b/ChangeLog	Fri Jan 18 15:07:12 2008 -0800
@@ -1,3 +1,13 @@
+LibPST 0.6.4 (2008-01-18)
+===============================
+
+	* 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.
+	* Fix large file support - we need to include config.h before any
+	standard headers.
+
 LibPST 0.6.3 (2008-01-13)
 ===============================
 
--- a/configure.in	Sun Jan 13 12:55:59 2008 -0800
+++ b/configure.in	Fri Jan 18 15:07:12 2008 -0800
@@ -1,7 +1,7 @@
 AC_INIT(configure.in)
 
 AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(libpst,0.6.3)
+AM_INIT_AUTOMAKE(libpst,0.6.4)
 AC_PATH_PROGS(BASH, bash)
 
 AC_LANG_CPLUSPLUS
--- a/regression/regression-tests.bash	Sun Jan 13 12:55:59 2008 -0800
+++ b/regression/regression-tests.bash	Fri Jan 18 15:07:12 2008 -0800
@@ -2,27 +2,31 @@
 
 val="valgrind --leak-check=full"
 
-for i in {1..7}; do
+for i in {1..8}; do
     rm -rf output$i
     mkdir output$i
 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 output5 mbmg.archive.pst              >out5.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 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 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/lspst ams.pst >out8.err 2>&1
-      ../src/readpstlog -f I lspst.debug >lspst.log
+$val  ../src/readpst -cv    -o output8 -d dumper big_mail.pst        >out8.err 2>&1
+      ../src/readpstlog -f I dumper >big_mail.log
 
-rm -f dumper lspst.debug
+#$val  ../src/lspst ams.pst >out8.err 2>&1
+#      ../src/readpstlog -f I lspst.debug >lspst.log
 
+#rm -f dumper lspst.debug
+
--- a/src/debug.c	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/debug.c	Fri Jan 18 15:07:12 2008 -0800
@@ -1,11 +1,12 @@
-/* Contains the debug functions */
+
+#include "define.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <ctype.h>
 #include <string.h>
 #include <limits.h>
-#include "define.h"
 
 #ifdef _WIN32
 # define vsnprintf _vsnprintf
@@ -246,7 +247,7 @@
     size_t size, ptr, funcname, filename, text, end;
     char *buf = NULL, rec_type;
     if (!debug_fp) return;  // no file
-    off_t index_pos = ftell (debug_fp);
+    off_t index_pos = ftell(debug_fp);
     off_t file_pos  = index_pos;
     // add 2. One for the pointer to the next index,
     // one for the count of this index
--- a/src/define.h	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/define.h	Fri Jan 18 15:07:12 2008 -0800
@@ -8,6 +8,7 @@
 #ifdef HAVE_CONFIG_H
 	#include "config.h"
 #endif
+#include "version.h"
 
 #ifndef DEFINEH_H
 #define DEFINEH_H
--- a/src/dumpblocks.c	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/dumpblocks.c	Fri Jan 18 15:07:12 2008 -0800
@@ -1,8 +1,9 @@
+#include "define.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include "libpst.h"
-#include "define.h"
 
 #define OUT_BUF 20
 int main(int argc, char **argv) {
--- a/src/getidblock.c	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/getidblock.c	Fri Jan 18 15:07:12 2008 -0800
@@ -1,3 +1,5 @@
+#include "define.h"
+
 #include <stdio.h>
 #include <string.h>
 
@@ -9,7 +11,6 @@
 # include <unistd.h>
 #endif
 
-#include "define.h"
 #include "libpst.h"
 
 static void usage();
--- a/src/libpst.c	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/libpst.c	Fri Jan 18 15:07:12 2008 -0800
@@ -4,6 +4,8 @@
  * Written by David Smith
  *            dave.s@earthcorp.com
  */
+#include "define.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
@@ -15,7 +17,6 @@
 #include <errno.h>
 #include <sys/stat.h>   // mkdir
 #include <fcntl.h>      // for Win32 definition of _O_BINARY
-#include "define.h"
 #include "libstrfunc.h"
 #include "vbuf.h"
 
@@ -33,13 +34,13 @@
 //efine SECOND_DEPTH            0x5C
 #define INDEX_TYPE32            0x0E
 #define INDEX_TYPE64            0x17
+#define INDEX_TYPE_OFFSET       (off_t)0x0A
 
 #define FILE_SIZE_POINTER32     (off_t)0xA8
 #define INDEX_POINTER32         (off_t)0xC4
 #define INDEX_BACK32            (off_t)0xC0
 #define SECOND_POINTER32        (off_t)0xBC
 #define SECOND_BACK32           (off_t)0xB8
-#define INDEX_TYPE_OFFSET32     (off_t)0x0A
 #define ENC_OFFSET32            (off_t)0x1CD
 
 #define FILE_SIZE_POINTER64     (off_t)0xB8
@@ -47,7 +48,6 @@
 #define INDEX_BACK64            (off_t)0xE8
 #define SECOND_POINTER64        (off_t)0xE0
 #define SECOND_BACK64           (off_t)0xD8
-#define INDEX_TYPE_OFFSET64     (off_t)0x0A
 #define ENC_OFFSET64            (off_t)0x201
 
 #define FILE_SIZE_POINTER ((pf->do_read64) ? FILE_SIZE_POINTER64 : FILE_SIZE_POINTER32)
@@ -55,8 +55,6 @@
 #define INDEX_BACK        ((pf->do_read64) ? INDEX_BACK64        : INDEX_BACK32)
 #define SECOND_POINTER    ((pf->do_read64) ? SECOND_POINTER64    : SECOND_POINTER32)
 #define SECOND_BACK       ((pf->do_read64) ? SECOND_BACK64       : SECOND_BACK32)
-#define INDEX_TYPE_OFFSET ((pf->do_read64) ? INDEX_TYPE_OFFSET64 : INDEX_TYPE_OFFSET32)
-#define INDEX_TYPE        ((pf->do_read64) ? INDEX_TYPE64        : INDEX_TYPE32)
 #define ENC_OFFSET        ((pf->do_read64) ? ENC_OFFSET64        : ENC_OFFSET32)
 
 #define PST_SIGNATURE 0x4E444221
@@ -85,11 +83,22 @@
 } pst_id2_assoc32;
 
 typedef struct pst_id2_assoc {
-    uint64_t id2;
+    uint32_t id2;       // only 32 bit here?
+    uint16_t unknown1;
+    uint16_t unknown2;
     uint64_t id;
     uint64_t table2;
 } pst_id2_assoc;
 
+typedef struct pst_table3_rec32 {
+    uint32_t id;
+} pst_table3_rec32; //for type 3 (0x0101) blocks
+
+typedef struct pst_table3_rec {
+    uint64_t id;
+} pst_table3_rec;   //for type 3 (0x0101) blocks
+
+
 // this is an array of the un-encrypted values. the un-encrypted value is in the position
 // of the encrypted value. ie the encrypted value 0x13 represents 0x02
 //                     0     1     2     3     4     5     6     7
@@ -170,20 +179,19 @@
     }
 
     // read index type
-    pf->do_read64 = 0;  // start with 32 bit format
     (void)pst_getAtPos(pf->fp, INDEX_TYPE_OFFSET, &(pf->ind_type), sizeof(pf->ind_type));
     DEBUG_INFO(("index_type = %i\n", pf->ind_type));
-    if (pf->ind_type != INDEX_TYPE) {
-        // try with 64 bit format
-        pf->do_read64 = 1;
-        if (pf->ind_type != INDEX_TYPE) {
+    switch (pf->ind_type) {
+        case INDEX_TYPE32 :
+            pf->do_read64 = 0;
+            break;
+        case INDEX_TYPE64 :
+            pf->do_read64 = 1;
+            break;
+        default:
             WARN(("unknown .pst format, possibly newer than Outlook 2003 PST file?\n"));
             DEBUG_RET();
             return -1;
-        }
-        else {
-            WARN(("switching to 64 bit format...\n"));
-        }
     }
 
     // read encryption setting
@@ -193,11 +201,11 @@
     pf->index2_back  = pst_getIntAtPos(pf, SECOND_BACK);
     pf->index2       = pst_getIntAtPos(pf, SECOND_POINTER);
     pf->size         = pst_getIntAtPos(pf, FILE_SIZE_POINTER);
-    DEBUG_INFO(("Pointer2 is %#llx, count %lli[%#llx]\n", pf->index2, pf->index2_back, pf->index2_back));
+    DEBUG_INFO(("Pointer2 is %#llx, back pointer2 is %#llx\n", pf->index2, pf->index2_back));
 
     pf->index1_back  = pst_getIntAtPos(pf, INDEX_BACK);
     pf->index1       = pst_getIntAtPos(pf, INDEX_POINTER);
-    DEBUG_INFO(("Pointer1 is %#llx, count %lli[%#llx]\n", pf->index1, pf->index1_back, pf->index1_back));
+    DEBUG_INFO(("Pointer1 is %#llx, back pointer2 is %#llx\n", pf->index1, pf->index1_back));
 
     DEBUG_RET();
     return 0;
@@ -400,7 +408,7 @@
         DEBUG_WARN(("Have not been able to fetch any id2 values for item 0x61. Brace yourself!\n"));
     }
 
-    na = pst_parse_block(pf, p->desc->id, id2_head);
+    na = pst_parse_block(pf, p->desc->id, id2_head, NULL);
     if (!na) {
         DEBUG_WARN(("Cannot process desc block for item 0x61. Not loading extended Attributes\n"));
         if (id2_head) pst_free_id2(id2_head);
@@ -639,7 +647,7 @@
         DEBUG_INDEX(("Decoding assoc64\n"));
         DEBUG_HEXDUMPC(buf, sizeof(pst_id2_assoc), 0x10);
         memcpy(assoc, buf, sizeof(pst_id2_assoc));
-        LE64_CPU(assoc->id2);
+        LE32_CPU(assoc->id2);
         LE64_CPU(assoc->id);
         LE64_CPU(assoc->table2);
         r = sizeof(pst_id2_assoc);
@@ -660,6 +668,28 @@
 }
 
 
+static size_t pst_decode_type3(pst_file *pf, pst_table3_rec *table3_rec, char *buf);
+static size_t pst_decode_type3(pst_file *pf, pst_table3_rec *table3_rec, char *buf) {
+    size_t r;
+    if (pf->do_read64) {
+        DEBUG_INDEX(("Decoding table3 64\n"));
+        DEBUG_HEXDUMPC(buf, sizeof(pst_table3_rec), 0x10);
+        memcpy(table3_rec, buf, sizeof(pst_table3_rec));
+        LE64_CPU(table3_rec->id);
+        r = sizeof(pst_table3_rec);
+    } else {
+        pst_table3_rec32 table3_rec32;
+        DEBUG_INDEX(("Decoding table3 32\n"));
+        DEBUG_HEXDUMPC(buf, sizeof(pst_table3_rec32), 0x10);
+        memcpy(&table3_rec32, buf, sizeof(pst_table3_rec32));
+        LE32_CPU(table3_rec32.id);
+        table3_rec->id  = table3_rec32.id;
+        r = sizeof(pst_table3_rec32);
+    }
+    return r;
+}
+
+
 int pst_build_id_ptr(pst_file *pf, off_t offset, int32_t depth, uint64_t linku1, uint64_t start_val, uint64_t end_val) {
     struct pst_table_ptr_structn table, table2;
     pst_index_ll *i_ptr=NULL;
@@ -669,7 +699,7 @@
     char *buf = NULL, *bptr;
 
     DEBUG_ENT("pst_build_id_ptr");
-    DEBUG_INDEX(("offset %x depth %i linku1 %llx start %llx end %llx\n", offset, depth, linku1, start_val, end_val));
+    DEBUG_INDEX(("offset %llx depth %i linku1 %llx start %llx end %llx\n", offset, depth, linku1, start_val, end_val));
     if (end_val <= start_val) {
         DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#llx, end:%#llx]\n", start_val, end_val));
         DEBUG_RET();
@@ -878,7 +908,7 @@
     pst_descn desc_rec;
     pst_desc_ll *d_ptr=NULL, *parent=NULL;
     int32_t x, item_count;
-    uint32_t old = start_val;
+    uint64_t old = start_val;
     char *buf = NULL, *bptr;
     struct cache_list_node *cache_ptr = NULL;
     struct cache_list_node *lostfound_ptr = NULL;
@@ -1119,7 +1149,7 @@
         DEBUG_WARN(("Have not been able to fetch any id2 values for this item. Brace yourself!\n"));
     }
 
-    list = pst_parse_block(pf, d_ptr->desc->id, id2_head);
+    list = pst_parse_block(pf, d_ptr->desc->id, id2_head, NULL);
     if (!list) {
         DEBUG_WARN(("pst_parse_block() returned an error for d_ptr->desc->id [%#llx]\n", d_ptr->desc->id));
         if (id2_head) pst_free_id2(id2_head);
@@ -1150,7 +1180,7 @@
         }
 
         DEBUG_EMAIL(("ATTACHMENT processing attachment\n"));
-        if ((list = pst_parse_block(pf, id_ptr->id, id2_head)) == NULL) {
+        if ((list = pst_parse_block(pf, id_ptr->id, id2_head, NULL)) == NULL) {
             DEBUG_WARN(("ERROR error processing main attachment record\n"));
             if (item) pst_freeItem(item);
             if (id2_head) pst_free_id2(id2_head);
@@ -1187,7 +1217,7 @@
                   // id_ptr is a record describing the attachment
                   // we pass NULL instead of id2_head cause we don't want it to
                   // load all the extra stuff here.
-                  if ((list = pst_parse_block(pf, id_ptr->id, NULL)) == NULL) {
+                  if ((list = pst_parse_block(pf, id_ptr->id, NULL, NULL)) == NULL) {
                       DEBUG_WARN(("ERROR error processing an attachment record\n"));
                       attach = attach->next;
                       continue;
@@ -1248,9 +1278,9 @@
 }
 
 
-pst_num_array * pst_parse_block(pst_file *pf, uint64_t block_id, pst_index2_ll *i2_head) {
+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;
-    pst_num_array *na_ptr = NULL, *na_head = NULL;
+    pst_num_array *na_ptr = NULL;
     pst_block_offset_pointer block_offset1;
     pst_block_offset_pointer block_offset2;
     pst_block_offset_pointer block_offset3;
@@ -1275,25 +1305,11 @@
     pst_x_attrib_ll *mapptr;
 
     struct {
-        uint16_t type;
-        uint16_t ref_type;
-        uint32_t value;
-    } table_rec;    //for type 1 (0xBCEC) blocks
-    struct {
-        uint16_t ref_type;
-        uint16_t type;
-        uint16_t ind2_off;
-        uint8_t  size;
-        uint8_t  slot;
-    } table2_rec;   //for type 2 (0x7CEC) blocks
-    struct {
-        uint32_t id;
-    } table3_rec;   //for type 3 (0x0101) blocks
-    struct {
         uint16_t index_offset;
         uint16_t type;
         uint32_t offset;
     } block_hdr;
+
     struct {
         unsigned char seven_c;
         unsigned char item_count;
@@ -1306,11 +1322,28 @@
         uint16_t u7;
         uint16_t u8;
     } seven_c_blk;
+
     struct _type_d_rec {
         uint32_t id;
         uint32_t u1;
     } * type_d_rec;
 
+    struct {
+        uint16_t type;
+        uint16_t ref_type;
+        uint32_t value;
+    } table_rec;    //for type 1 (0xBCEC) blocks
+
+    struct {
+        uint16_t ref_type;
+        uint16_t type;
+        uint16_t ind2_off;
+        uint8_t  size;
+        uint8_t  slot;
+    } table2_rec;   //for type 2 (0x7CEC) blocks
+
+    pst_table3_rec table3_rec;  //for type 3 (0x0101) blocks
+
     DEBUG_ENT("pst_parse_block");
     if ((read_size = pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) {
         WARN(("Error reading block id %#llx\n", block_id));
@@ -1331,7 +1364,7 @@
     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));
+    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;
 
@@ -1440,19 +1473,19 @@
     else if (block_hdr.index_offset == (uint16_t)0x0101) { //type 3
         unsigned char *buf2 = NULL;
         uint16_t n = block_hdr.type; // count
-        size_t   m = sizeof(table3_rec);
         uint16_t i;
         block_type = 3;
+        char *b_ptr = buf + 8;
         for (i=0; i<n; i++) {
-            memcpy(&table3_rec, buf+8+i*m, m);
-            LE32_CPU(table3_rec.id);
-            (void)pst_ff_getIDblock_dec(pf, table3_rec.id, &buf2);
-            if (buf2) free(buf2);
-            buf2 = NULL;
+            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 NULL;
+        return na_head;
     } else {
         WARN(("ERROR: Unknown block constant - %#hx for id %#llx\n", block_hdr.type, block_id));
         DEBUG_HEXDUMPC(buf, read_size,0x10);
@@ -1467,7 +1500,7 @@
         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(structpst_num_item)
+        // 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);
         na_ptr->count_item  = num_list;
         na_ptr->orig_count  = num_list;
@@ -1679,6 +1712,9 @@
     return na_head;
 }
 
+// This version of free does NULL check first
+#define SAFE_FREE(x) {if (x) free(x);}
+
 
 // check if item->email is NULL, and init if so
 #define MALLOC_EMAIL(x)        { if (!x->email)         { x->email         = (pst_item_email*)         xmalloc(sizeof(pst_item_email));         memset(x->email,         0, sizeof(pst_item_email)        );} }
@@ -1694,10 +1730,16 @@
     memset(((char*)targ)+list->items[x]->size, 0, (size_t)1); \
 }
 // malloc space and copy the current item's data and size
-#define LIST_COPY_SIZE(targ, type, mysize) {    \
-    mysize = list->items[x]->size;              \
-    targ = type realloc(targ, mysize);          \
-    memcpy(targ, list->items[x]->data, mysize); \
+#define LIST_COPY_SIZE(targ, type, mysize) {        \
+    mysize = list->items[x]->size;                  \
+    if (mysize) {                                   \
+        targ = type realloc(targ, mysize);          \
+        memcpy(targ, list->items[x]->data, mysize); \
+    }                                               \
+    else {                                          \
+        SAFE_FREE(targ);                            \
+        targ = NULL;                                \
+    }                                               \
 }
 
 #define NULL_CHECK(x) { if (!x) { DEBUG_EMAIL(("NULL_CHECK: Null Found\n")); break;} }
@@ -3443,13 +3485,7 @@
     b_ptr = buf + ((pf->do_read64) ? 0x08 : 0x04);
     while (x < block_head.count) {
         b_ptr += pst_decode_assoc(pf, &id2_rec, b_ptr);
-      //  memcpy(&id2_rec, &(buf[b_ptr]), sizeof(id2_rec));
-      //  LE32_CPU(id2_rec.id2);
-      //  LE32_CPU(id2_rec.id);
-      //  LE32_CPU(id2_rec.table2);
-      //
-      //  b_ptr += sizeof(id2_rec);
-        DEBUG_INDEX(("\tid2 = %#llx, id = %#llx, table2 = %#llx\n", id2_rec.id2, id2_rec.id, id2_rec.table2));
+        DEBUG_INDEX(("\tid2 = %#x, id = %#llx, table2 = %#llx\n", id2_rec.id2, id2_rec.id, id2_rec.table2));
         if ((i_ptr = pst_getID(pf, id2_rec.id)) == NULL) {
             DEBUG_WARN(("\t\t%#llx - Not Found\n", id2_rec.id));
         } else {
@@ -3494,9 +3530,6 @@
 }
 
 
-// This version of free does NULL check first
-#define SAFE_FREE(x) {if (x) free(x);}
-
 void pst_freeItem(pst_item *item) {
     pst_item_attach *t;
     pst_item_extra_field *et;
@@ -4074,7 +4107,7 @@
     size_t rsize = 0;
     DEBUG_ENT("pst_ff_getIDblock");
     if ((rec = pst_getID(pf, id)) == NULL) {
-        DEBUG_INDEX(("Cannot find ID %#x\n", id));
+        DEBUG_INDEX(("Cannot find ID %#llx\n", id));
         DEBUG_RET();
         return 0;
     }
@@ -4084,7 +4117,7 @@
         free(*b);
     }
 
-    DEBUG_INDEX(("id = %#x, record size = %#x, offset = %#x\n", id, rec->size, rec->offset));
+    DEBUG_INDEX(("id = %#llx, record size = %#x, offset = %#x\n", id, rec->size, rec->offset));
     *b = (char*) xmalloc(rec->size+1);
     rsize = fread(*b, (size_t)1, rec->size, pf->fp);
     if (rsize != rec->size) {
@@ -4359,7 +4392,8 @@
 
 
 char *pst_rfc2426_escape(char *str) {
-    static char* buf = NULL;
+    static char*  buf    = NULL;
+    static size_t buflen = 0;
     char *ret, *a, *b;
     size_t x = 0;
     int y, z;
@@ -4379,7 +4413,10 @@
             ret = str;
         else {
             x = strlen(str) + y - z + 1; // don't forget room for the NUL
-            buf = (char*) realloc(buf, x);
+            if (x > buflen) {
+                buf = (char*) realloc(buf, x);
+                buflen = x;
+            }
             a = str;
             b = buf;
             while (*a != '\0') {
--- a/src/libpst.h	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/libpst.h	Fri Jan 18 15:07:12 2008 -0800
@@ -501,10 +501,10 @@
 int            pst_load_extended_attributes(pst_file *pf);
 
 int            pst_build_id_ptr(pst_file *pf, off_t offset, int32_t depth, uint64_t linku1, uint64_t start_val, uint64_t end_val);
-int            pst_build_desc_ptr (pst_file *pf, off_t offset, int32_t depth, uint64_t linku1, uint64_t *high_id, uint64_t start_val, uint64_t end_val);
+int            pst_build_desc_ptr(pst_file *pf, off_t offset, int32_t depth, uint64_t linku1, uint64_t *high_id, uint64_t start_val, uint64_t end_val);
 pst_item*      pst_getItem(pst_file *pf, pst_desc_ll *d_ptr);
 pst_item*      pst_parse_item (pst_file *pf, pst_desc_ll *d_ptr);
-pst_num_array* pst_parse_block(pst_file *pf, uint64_t block_id, pst_index2_ll *i2_head);
+pst_num_array* pst_parse_block(pst_file *pf, uint64_t block_id, pst_index2_ll *i2_head, pst_num_array *na_head);
 int            pst_process(pst_num_array *list, pst_item *item, pst_item_attach *attach);
 void           pst_free_list(pst_num_array *list);
 void           pst_freeItem(pst_item *item);
--- a/src/lspst.c	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/lspst.c	Fri Jan 18 15:07:12 2008 -0800
@@ -6,7 +6,8 @@
  *
  */
 
-// header file includes
+#include "define.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
@@ -15,7 +16,6 @@
 #include <errno.h>
 
 #include "libpst.h"
-#include "define.h"
 #include "timeconv.h"
 
 struct file_ll {
@@ -154,6 +154,10 @@
 
     if (argc <= 1) DIE(("Missing PST filename.\n"));
 
+    #ifdef DEBUG_ALL
+        // force a log file
+        if (!d_log) d_log = "lspst.log";
+    #endif // defined DEBUG_ALL
     DEBUG_INIT(d_log);
     DEBUG_REGISTER_CLOSE();
     DEBUG_ENT("main");
--- a/src/lzfu.c	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/lzfu.c	Fri Jan 18 15:07:12 2008 -0800
@@ -11,6 +11,7 @@
 
 #include "define.h"
 #include "libpst.h"
+
 #include <sys/types.h>
 #include <string.h>
 #include <stdio.h>
--- a/src/readpst.c	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/readpst.c	Fri Jan 18 15:07:12 2008 -0800
@@ -4,6 +4,8 @@
  * Written by David Smith
  *            dave.s@earthcorp.com
  */
+#include "define.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
@@ -32,8 +34,6 @@
 
 #include "libstrfunc.h" // for base64_encoding
 
-#include "version.h"
-#include "define.h"
 #include "libpst.h"
 #include "common.h"
 #include "timeconv.h"
@@ -245,7 +245,7 @@
     pst_item *item = NULL;
     pst_desc_ll *d_ptr;
     char * fname = NULL;
-    char *d_log=NULL;
+    char *d_log  = NULL;
     int c,x;
     char *temp = NULL;               //temporary char pointer
     prog_name = argv[0];
@@ -782,9 +782,9 @@
         // If there is a long filename (filename2) use that, otherwise
         // use the 8.3 filename (filename1)
         if (current_attach->filename2) {
-          attach_filename = current_attach->filename2;
+            attach_filename = current_attach->filename2;
         } else {
-          attach_filename = current_attach->filename1;
+            attach_filename = current_attach->filename1;
         }
         if (!attach_filename) {
             fprintf(f_output, "Content-Disposition: inline\n\n");
--- a/src/readpstlog.c	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/readpstlog.c	Fri Jan 18 15:07:12 2008 -0800
@@ -1,3 +1,5 @@
+#include "define.h"
+
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
@@ -10,7 +12,6 @@
 # include "XGetopt.h"
 #endif
 
-#include "define.h"
 
 #define BUF_SIZE 4096
 
@@ -74,7 +75,9 @@
 	buf = (char*) xmalloc(BUF_SIZE);
 
 	while (!stop) {
-		if (fread(&x, sizeof(int), 1, fp)<=0) break;
+        off_t temp;
+		if (fread(&temp, sizeof(off_t), 1, fp)<=0) break;
+        x = (int)temp;
 		ptr = 0;
 		if (x > 0) {
 			if (i) free(i);
--- a/src/testdebug.c	Sun Jan 13 12:55:59 2008 -0800
+++ b/src/testdebug.c	Fri Jan 18 15:07:12 2008 -0800
@@ -1,6 +1,7 @@
+#include "define.h"
+
 #include <stdlib.h>
 #include <string.h>
-#include "define.h"
 
 #define BUF_SIZE 100000
 int main() {
--- a/xml/libpst.in	Sun Jan 13 12:55:59 2008 -0800
+++ b/xml/libpst.in	Fri Jan 18 15:07:12 2008 -0800
@@ -19,7 +19,7 @@
 
     <refentry id="readpst.1">
         <refentryinfo>
-            <date>2008-01-08</date>
+            <date>2008-01-15</date>
         </refentryinfo>
 
         <refmeta>
@@ -212,7 +212,7 @@
 
     <refentry id="lspst.1">
         <refentryinfo>
-            <date>2008-01-08</date>
+            <date>2008-01-15</date>
         </refentryinfo>
 
         <refmeta>
@@ -286,7 +286,7 @@
 
     <refentry id="readpstlog.1">
         <refentryinfo>
-            <date>2008-01-08</date>
+            <date>2008-01-15</date>
         </refentryinfo>
 
         <refmeta>
@@ -461,7 +461,7 @@
 
     <refentry id="pst2ldif.1">
         <refentryinfo>
-            <date>2008-01-08</date>
+            <date>2008-01-15</date>
         </refentryinfo>
 
         <refmeta>
@@ -585,7 +585,7 @@
 
     <refentry id="pst.5">
         <refentryinfo>
-            <date>2008-01-08</date>
+            <date>2008-01-15</date>
         </refentryinfo>
 
         <refmeta>
@@ -1276,7 +1276,7 @@
         </refsect1>
 
         <refsect1 id='pst.file.list.32.5'>
-            <title>32 bit Associated List Item</title>
+            <title>32 bit Associated List Item 0x0002</title>
             <para>
                 Contains associations between id1 and id2 for the items controlled by the record.
                 In the above 32 bit leaf node, we have a tuple of (0x61, 0x02a82c, 0x02a836, 0)
@@ -1286,7 +1286,7 @@
             <literallayout class="monospaced"><![CDATA[
 0000  02 00  01 00  9f 81 00 00  30 a8 02 00  00 00 00 00
 
-0000  unknown         [2 bytes] 0x0002     constant
+0000  signature       [2 bytes] 0x0002     constant
 0002  count           [2 bytes] 0x0001     in this case
   repeating
 0004  id2             [4 bytes] 0x00819f   in this case
@@ -1296,7 +1296,7 @@
         </refsect1>
 
         <refsect1 id='pst.file.list.64.5'>
-            <title>64 bit Associated List Item</title>
+            <title>64 bit Associated List Item 0x0002</title>
             <para>
                 Contains associations between id1 and id2 for the items controlled by the record.
             </para>
@@ -1306,13 +1306,15 @@
 0020  3f 80 00 00  00 00 00 00  98 00 00 00  00 00 00 00
 0030  00 00 00 00  00 00 00 00
 
-0000  unknown         [2 bytes] 0x0002     constant
+0000  signature       [2 bytes] 0x0002     constant
 0002  count           [2 bytes] 0x0002     in this case
 0004  unknown         [4 bytes] 0   	   possibly constant
   repeating
-0008  id2             [8 bytes] 0x000692   in this case
-0008  id              [8 bytes] 0x0000a8   in this case
-000c  table2          [8 bytes] 0          in this case
+0008  id2             [4 bytes] 0x000692   in this case
+000c  unknown1        [2 bytes] 0          may be a count or size
+000e  unknown2        [2 bytes] 0          may be a count or size
+0010  id              [8 bytes] 0x0000a8   in this case
+0018  table2          [8 bytes] 0          in this case
 ]]></literallayout>
         </refsect1>
 
@@ -1773,11 +1775,17 @@
             </para>
         </refsect1>
 
-        <refsect1 id='pst.file.desc3.5'>
-            <title>Associated Descriptor Item 0x0002</title>
+        <refsect1 id='pst.file.desc3.32.5'>
+            <title>32 bit Associated Descriptor Item 0x0101</title>
             <para>
-                This style of descriptor block is almost unknown here.
-                It seems to contain a list of ID1 values.
+                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.
             </para>
             <literallayout class="monospaced"><![CDATA[
 0000  01 01 02 00  26 28 00 00  18 77 0c 00  b8 04 00 00
@@ -1791,5 +1799,23 @@
 ]]></literallayout>
         </refsect1>
 
+        <refsect1 id='pst.file.desc3.64.5'>
+            <title>64 bit Associated Descriptor Item 0x0101</title>
+            <para>
+                This descriptor block contains a list of ID1 values.
+            </para>
+            <literallayout class="monospaced"><![CDATA[
+0000  01 01 02 00  ea 29 00 00  10 83 00 00  00 00 00 00
+0010  1c 83 00 00  00 00 00 00
+
+0000  signature       [2 bytes] 0x0101     constant
+0002  count           [2 bytes] 0x0002     in this case
+0004  unknown         [4 bytes] 0x0029ea   in this case
+  repeating
+0008  id              [8 bytes] 0x008310   in this case
+0010  id              [8 bytes] 0x00831c   in this case
+]]></literallayout>
+        </refsect1>
+
     </refentry>
 </reference>