diff src/libpst.c @ 48:f66078abed38

more fixes for 64 bit format
author carl
date Fri, 18 Jan 2008 15:07:12 -0800
parents 5fb8d997feed
children 17654fbdf76b
line wrap: on
line diff
--- 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') {