changeset 36:6fe121a971c9 stable-0-5-7

valgrind fixes
author carl
date Thu, 09 Aug 2007 15:46:34 -0700
parents b2f247463b83
children ddfb25318812
files ChangeLog NEWS configure.in regression/regression-tests.bash src/debug.c src/define.h src/libpst.c src/libpst.h src/libstrfunc.c src/lzfu.c src/lzfu.h src/readpst.c src/readpstlog.c xml/libpst.in
diffstat 14 files changed, 445 insertions(+), 365 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Jul 15 14:25:34 2007 -0700
+++ b/ChangeLog	Thu Aug 09 15:46:34 2007 -0700
@@ -1,3 +1,10 @@
+LibPST 0.5.7 (2007-08-09)
+===============================
+
+        * fix valgrind errors, using uninitialized data.
+        * improve debug logging and readpstlog for indented listings.
+        * cleanup documentation.
+
 LibPST 0.5.6 (2007-07-15)
 ===============================
 
--- a/NEWS	Sun Jul 15 14:25:34 2007 -0700
+++ b/NEWS	Thu Aug 09 15:46:34 2007 -0700
@@ -1,5 +1,6 @@
     $Id$
 
+0.5.7 2007-08-09 fix valgrind errors, using uninitialized data
 0.5.6 2007-07-15 handle small pst files, better decoding of 7c blocks
 0.5.5 2007-07-10 merge changes from Joe Nahmias version
 0.5.4 2006-02-25 add MH mode, generated filenames with no leading zeros
--- a/configure.in	Sun Jul 15 14:25:34 2007 -0700
+++ b/configure.in	Thu Aug 09 15:46:34 2007 -0700
@@ -1,7 +1,7 @@
 AC_INIT(configure.in)
 
 AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(libpst,0.5.6)
+AM_INIT_AUTOMAKE(libpst,0.5.7)
 AC_PATH_PROGS(BASH, bash)
 
 AC_LANG_CPLUSPLUS
--- a/regression/regression-tests.bash	Sun Jul 15 14:25:34 2007 -0700
+++ b/regression/regression-tests.bash	Thu Aug 09 15:46:34 2007 -0700
@@ -13,9 +13,10 @@
 #   ../src/readpst        -o output5 mbmg.archive.pst
 
     ../src/readpst        -o output1 -d dumper ams.pst
-    ../src/readpstlog dumper >dumperams.log
+    ../src/readpstlog -f I dumper >dumperams.log
 
-    ../src/readpst        -o output6 -d dumper /tmp/pam.pst
-    ../src/readpstlog dumper >dumperpam.log
+#   touch /tmp/pam.pst
+#   ../src/readpst        -o output6 -d dumper /tmp/pam.pst
+#   ../src/readpstlog -f I dumper >dumperpam.log
 
     rm -f dumper
--- a/src/debug.c	Sun Jul 15 14:25:34 2007 -0700
+++ b/src/debug.c	Thu Aug 09 15:46:34 2007 -0700
@@ -258,6 +258,7 @@
 	if (curr_items == 0) return;	// no items to write.
 
 	index = (int*) xmalloc(index_size);
+	memset(index, 0, index_size);	// valgrind, avoid writing uninitialized data
 	file_pos += index_size;
 	// write the index first, we will re-write it later, but
 	// we want to allocate the space
@@ -268,8 +269,9 @@
 	while (item_ptr) {
 		file_pos = ftell(debug_fp);
 		index[index_ptr++] = file_pos;
-		size = strlen(item_ptr->function)+strlen(item_ptr->file)+
-		  strlen(item_ptr->text) + 3; //for the three \0s
+		size = strlen(item_ptr->function) +
+			   strlen(item_ptr->file)	  +
+			   strlen(item_ptr->text)	  + 3; //for the three \0s
 		if (buf) free(buf);
 		buf = xmalloc(size+1);
 		ptr = 0;
@@ -387,11 +389,13 @@
 	struct _debug_file_rec_l lfile_rec;
 	unsigned char rec_type;
 	int index_size = 3 * sizeof(int);
-	int *index = malloc(index_size);
-	int index_pos, file_pos;
+	int index_pos, file_pos, *index;
 	char zero='\0';
 	if (!debug_fp) return;	// no file
+	index = malloc(index_size);
 	index[0] = 1; // only one item in this index run
+	index[1] = 0; // valgrind, avoid writing uninitialized data
+	index[2] = 0; // ""
 	index_pos = ftell(debug_fp);
 	fwrite(index, index_size, 1, debug_fp);
 	index[1] = ftell(debug_fp);
@@ -399,11 +403,12 @@
 	// always use the long
 	rec_type = 'L';
 	fwrite(&rec_type, 1, sizeof(char), debug_fp);
-	lfile_rec.type = item->type;
-	lfile_rec.line = item->line;
 	lfile_rec.funcname = 0;
 	lfile_rec.filename = strlen(item->function)+1;
 	lfile_rec.text = lfile_rec.filename+strlen(item->file)+1;
+	lfile_rec.end  = 0; // valgrind, avoid writing uninitialized data
+	lfile_rec.line = item->line;
+	lfile_rec.type = item->type;
 	fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp);
 
 	file_pos = ftell(debug_fp);
@@ -423,12 +428,13 @@
 }
 
 
-void * xmalloc(size_t size) {
+void *xmalloc(size_t size) {
 	void *mem = malloc(size);
 	if (!mem) {
 		fprintf(stderr, "xMalloc: Out Of memory [req: %ld]\n", (long)size);
 		exit(1);
 	}
+	memset(mem, 0, size);	// valgrind, some email attachment does not initialize the entire buffer passed to base64 encode
 	return mem;
 }
 
--- a/src/define.h	Sun Jul 15 14:25:34 2007 -0700
+++ b/src/define.h	Thu Aug 09 15:46:34 2007 -0700
@@ -29,15 +29,16 @@
 //number of items to save in memory between writes
 #define DEBUG_MAX_ITEMS 0
 
-#define DEBUG_FILE_NO  1
-#define DEBUG_INDEX_NO 2
-#define DEBUG_EMAIL_NO 3
-#define DEBUG_WARN_NO  4
-#define DEBUG_READ_NO  5
-#define DEBUG_INFO_NO  6
-#define DEBUG_MAIN_NO  7
-#define DEBUG_DECRYPT_NO 8
-#define DEBUG_FUNC_NO 10
+#define DEBUG_FILE_NO	  1
+#define DEBUG_INDEX_NO	  2
+#define DEBUG_EMAIL_NO	  3
+#define DEBUG_WARN_NO	  4
+#define DEBUG_READ_NO	  5
+#define DEBUG_INFO_NO	  6
+#define DEBUG_MAIN_NO	  7
+#define DEBUG_DECRYPT_NO  8
+#define DEBUG_FUNCENT_NO  9
+#define DEBUG_FUNCRET_NO 10
 #define DEBUG_HEXDUMP_NO 11
 
 //variable number of arguments to this macro. will expand them into
@@ -161,11 +162,16 @@
 					   _debug_msg_text x;}
 
 #ifdef DEBUG_MODE_FUNC
-# define DEBUG_ENT(x) \
-  {MESSAGEPRINT(("Entering function %s\n",x),DEBUG_FUNC_NO);\
-   _debug_func(x);}
-# define DEBUG_RET() {MESSAGEPRINT(("Leaving function\n"),DEBUG_FUNC_NO);\
-					  _debug_func_ret();}
+# define DEBUG_ENT(x)											\
+	{															\
+		 _debug_func(x);										\
+		MESSAGEPRINT(("Entering function\n"),DEBUG_FUNCENT_NO); \
+	}
+# define DEBUG_RET()											\
+	{															\
+		MESSAGEPRINT(("Leaving function\n"),DEBUG_FUNCRET_NO);  \
+		_debug_func_ret();										\
+	}
 #else
 # define DEBUG_ENT(x) {}
 # define DEBUG_RET() {}
--- a/src/libpst.c	Sun Jul 15 14:25:34 2007 -0700
+++ b/src/libpst.c	Thu Aug 09 15:46:34 2007 -0700
@@ -723,7 +723,7 @@
 	}
 	bptr = buf;
 	item_count = (int)(unsigned)(buf[ITEM_COUNT_OFFSET]);
-	memcpy(&desc_rec, buf+BACKLINK_OFFSET, sizeof(desc_rec));
+	memcpy(&desc_rec.d_id, buf+BACKLINK_OFFSET, sizeof(u_int32_t)); // for valgrind, only have 3 ints here, not 4
 	LE32_CPU(desc_rec.d_id);
 	if (desc_rec.d_id != linku1) {
 		DEBUG_WARN(("Backlink %#x in this node does not match required %#x\n", desc_rec.d_id, linku1));
@@ -1083,14 +1083,14 @@
 	u_int32_t num_list;
 	u_int32_t cur_list;
 	u_int32_t block_type;
-	u_int32_t rec_size;
+	u_int32_t rec_size = 0;
 	u_int32_t ind_ptr;
 	unsigned char* list_start;
 	unsigned char* t_ptr;
 	unsigned char* fr_ptr;
 	unsigned char* to_ptr;
 	unsigned char* ind2_end;
-	unsigned char* ind2_ptr;
+	unsigned char* ind2_ptr = NULL;
 	size_t read_size=0;
 	pst_x_attrib_ll *mapptr;
 
@@ -1188,7 +1188,6 @@
 		to_ptr	   = block_offset2.to;
 		num_list = (to_ptr - list_start)/sizeof(table_rec);
 		num_recs = 1; // only going to be one object in these blocks
-		rec_size = 0; // doesn't matter cause there is only one object
 	}
 	else if (block_hdr.type == 0x7CEC) { //type 2
 		block_type = 2;
@@ -1292,6 +1291,7 @@
 		na_ptr->items		= (struct _pst_num_item**) xmalloc(sizeof(struct _pst_num_item)*num_list);
 		na_ptr->count_item	= num_list;
 		na_ptr->count_array = num_recs; // each record will have a record of the total number of records
+		for (x=0; x<num_list; x++) na_ptr->items[x] = NULL;
 		x = 0;
 
 		DEBUG_EMAIL(("going to read %i (%#x) items\n", na_ptr->count_item, na_ptr->count_item));
@@ -3098,26 +3098,25 @@
 
 
 int32_t _pst_free_list(pst_num_array *list) {
-	int32_t x = 0;
 	pst_num_array *l;
 	DEBUG_ENT("_pst_free_list");
 	while (list) {
-		while (x < list->count_item) {
-			if (list->items[x]->data) {
-				free (list->items[x]->data);
+		int32_t x = 0;
+		if (list->items) {
+			while (x < list->count_item) {
+				if (list->items[x]) {
+					if (list->items[x]->data) {
+						free (list->items[x]->data);
+					}
+					free (list->items[x]);
+				}
+				x++;
 			}
-			if (list->items[x]) {
-				free (list->items[x]);
-			}
-			x++;
-		}
-		if (list->items) {
 			free(list->items);
 		}
 		l = list;
 		list = list->next;
 		free (l);
-		x = 0;
 	}
 	DEBUG_RET();
 	return 1;
@@ -3831,12 +3830,11 @@
 	DEBUG_ENT("_pst_ff_getIDblock_dec");
 	DEBUG_INDEX(("for id %#x\n", id));
 	r = _pst_ff_getIDblock(pf, id, b);
-	DEBUG_HEXDUMPC(*b, r, 16);
 	int noenc = (id & 2);	// disable encryption
 	if ((pf->encryption) & !(noenc)) {
 		_pst_decrypt(*b, r, pf->encryption);
-		DEBUG_HEXDUMPC(*b, r, 16);
 	}
+	DEBUG_HEXDUMPC(*b, r, 16);
 	DEBUG_RET();
 	return r;
 }
--- a/src/libpst.h	Sun Jul 15 14:25:34 2007 -0700
+++ b/src/libpst.h	Thu Aug 09 15:46:34 2007 -0700
@@ -349,7 +349,7 @@
   char *filename2;
   char *mimetype;
   char *data;
-  size_t  size;
+  size_t   size;
   int32_t  id2_val;
   int32_t  id_val; // calculated from id2_val during creation of record
   int32_t  method;
--- a/src/libstrfunc.c	Sun Jul 15 14:25:34 2007 -0700
+++ b/src/libstrfunc.c	Thu Aug 09 15:46:34 2007 -0700
@@ -6,9 +6,6 @@
 #include <stdlib.h>
 #include "libstrfunc.h"
 
-char *_sf_b64_buf=NULL;
-size_t _sf_b64_len=0;
-
 
 static unsigned char _sf_uc_ib[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/==";
 
@@ -26,44 +23,41 @@
 #endif
   //register void *dte=data + size;
   register int nc=0;
-  
+
   if ( data == NULL || size == 0 )
-    return NULL;
-  
-  ou=output=(char *)malloc(size / 3 * 4 + (size / 50) + 5);
+	return NULL;
+
+  ou=output=(char *)malloc(size / 3 * 4 + (size / 57) + 5);
   if(!output)
-    return NULL;
-  
+	return NULL;
+
   while((char *)dte - (char *)p >= 3) {
-    *ou = _sf_uc_ib[ *p >> 2 ];
-    ou[1] = _sf_uc_ib[ ((*p & 0x03) << 4) | (p[1] >> 4) ];
-    ou[2] = _sf_uc_ib[ ((p[1] & 0x0F) << 2) | (p[2] >> 6) ];
-    ou[3] = _sf_uc_ib[ p[2] & 0x3F ];
-    
-    p+=3;
-    ou+=4;
-    
-    nc+=4;
-    if(!(nc % 76)) *ou++='\n';
+	unsigned char x = p[0];
+	unsigned char y = p[1];
+	unsigned char z = p[2];
+	ou[0] = _sf_uc_ib[ x >> 2 ];
+	ou[1] = _sf_uc_ib[ ((x & 0x03) << 4) | (y >> 4) ];
+	ou[2] = _sf_uc_ib[ ((y & 0x0F) << 2) | (z >> 6) ];
+	ou[3] = _sf_uc_ib[ z & 0x3F ];
+	p+=3;
+	ou+=4;
+	nc+=4;
+	if(!(nc % 76)) *ou++='\n';
   };
   if((char *)dte - (char *)p == 2) {
-    *ou++ = _sf_uc_ib[ *p >> 2 ];
-    *ou++ = _sf_uc_ib[ ((*p & 0x03) << 4) | (p[1] >> 4) ];
-    *ou++ = _sf_uc_ib[ ((p[1] & 0x0F) << 2) ];
-    *ou++ = '=';
+	*ou++ = _sf_uc_ib[ *p >> 2 ];
+	*ou++ = _sf_uc_ib[ ((*p & 0x03) << 4) | (p[1] >> 4) ];
+	*ou++ = _sf_uc_ib[ ((p[1] & 0x0F) << 2) ];
+	*ou++ = '=';
   } else if((char *)dte - (char *)p == 1) {
-    *ou++ = _sf_uc_ib[ *p >> 2 ];
-    *ou++ = _sf_uc_ib[ ((*p & 0x03) << 4) ];
-    *ou++ = '=';
-    *ou++ = '=';
+	*ou++ = _sf_uc_ib[ *p >> 2 ];
+	*ou++ = _sf_uc_ib[ ((*p & 0x03) << 4) ];
+	*ou++ = '=';
+	*ou++ = '=';
   };
-  
+
   *ou=0;
-  
-  _sf_b64_len = (ou - output);
-  
-  if(_sf_b64_buf)
-    free(_sf_b64_buf);
-  return _sf_b64_buf=output;
+
+  return output;
 };
 
--- a/src/lzfu.c	Sun Jul 15 14:25:34 2007 -0700
+++ b/src/lzfu.c	Thu Aug 09 15:46:34 2007 -0700
@@ -1,12 +1,12 @@
  /*
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-     the Free Software Foundation; either version 2 of the License, or
-     (at your option) any later version.
+	 This program is free software; you can redistribute it and/or modify
+	 it under the terms of the GNU General Public License as published by
+	 the Free Software Foundation; either version 2 of the License, or
+	 (at your option) any later version.
 
-     You should have received a copy of the GNU General Public License
-     along with this program; if not, write to the Free Software Foundation,
-     Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+	 You should have received a copy of the GNU General Public License
+	 along with this program; if not, write to the Free Software Foundation,
+	 Inc., 59 Temple Place - Suite 330, Boston, MA	02111-1307, USA
   */
 
 #include "define.h"
@@ -25,103 +25,104 @@
 
 #include "lzfu.h"
 
-#define LZFU_COMPRESSED         0x75465a4c
-#define LZFU_UNCOMPRESSED       0x414c454d
+#define LZFU_COMPRESSED 		0x75465a4c
+#define LZFU_UNCOMPRESSED		0x414c454d
 
 // initital dictionary
-#define LZFU_INITDICT   "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" \
-                                                 "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscrip" \
-                                                 "t \\fdecor MS Sans SerifSymbolArialTimes Ne" \
-                                                 "w RomanCourier{\\colortbl\\red0\\green0\\blue0" \
-                                                 "\r\n\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab" \
-                                                 "\\tx"
+#define LZFU_INITDICT	"{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" \
+												 "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscrip" \
+												 "t \\fdecor MS Sans SerifSymbolArialTimes Ne" \
+												 "w RomanCourier{\\colortbl\\red0\\green0\\blue0" \
+												 "\r\n\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab" \
+												 "\\tx"
 // initial length of dictionary
 #define LZFU_INITLENGTH 207
 
 // header for compressed rtf
 typedef struct _lzfuheader {
-  uint32_t cbSize;
-  uint32_t cbRawSize;
-  uint32_t dwMagic;
-  uint32_t dwCRC;
+	uint32_t cbSize;
+	uint32_t cbRawSize;
+	uint32_t dwMagic;
+	uint32_t dwCRC;
 } lzfuheader;
 
 
-/** 
-    We always need to add 0x10 to the buffer offset because we need to skip past the header info
+/**
+	We always need to add 0x10 to the buffer offset because we need to skip past the header info
 */
 
-unsigned char* lzfu_decompress (unsigned char* rtfcomp) {
-  // the dictionary buffer
-  unsigned char dict[4096];
-  // the dictionary pointer
-  unsigned int dict_length=0;
-  // the header of the lzfu block
-  lzfuheader lzfuhdr;
-  // container for the data blocks
-  unsigned char flags;
-  // temp value for determining the bits in the flag
-  unsigned char flag_mask;
-  unsigned int i, in_size;
-  unsigned char *out_buf;
-  unsigned int out_ptr = 0;
+unsigned char* lzfu_decompress (unsigned char* rtfcomp, size_t *size) {
+	// the dictionary buffer
+	unsigned char dict[4096];
+	// the dictionary pointer
+	unsigned int dict_length=0;
+	// the header of the lzfu block
+	lzfuheader lzfuhdr;
+	// container for the data blocks
+	unsigned char flags;
+	// temp value for determining the bits in the flag
+	unsigned char flag_mask;
+	unsigned int i, in_size;
+	unsigned char *out_buf;
+	unsigned int out_ptr = 0;
 
-  memcpy(dict, LZFU_INITDICT, LZFU_INITLENGTH);
-  dict_length = LZFU_INITLENGTH;
-  memcpy(&lzfuhdr, rtfcomp, sizeof(lzfuhdr));
-  LE32_CPU(lzfuhdr.cbSize);   LE32_CPU(lzfuhdr.cbRawSize);
-  LE32_CPU(lzfuhdr.dwMagic);  LE32_CPU(lzfuhdr.dwCRC);
-  /*  printf("total size: %d\n", lzfuhdr.cbSize+4);
-  printf("raw size  : %d\n", lzfuhdr.cbRawSize);
-  printf("compressed: %s\n", (lzfuhdr.dwMagic == LZFU_COMPRESSED ? "yes" : "no"));
-  printf("CRC       : %#x\n", lzfuhdr.dwCRC);
-  printf("\n");*/
-  out_buf = (unsigned char*)xmalloc(lzfuhdr.cbRawSize+20); //plus 4 cause we have 2x'}' and a \0
-  in_size = 0;
-  // we add plus one here cause when referencing an array, the index is always one less 
-  // (ie, when accessing 2 element array, highest index is [1])
-  while (in_size+0x11 < lzfuhdr.cbSize) {
-    memcpy(&flags, &(rtfcomp[in_size+0x10]), 1);
-    in_size += 1;
+	memcpy(dict, LZFU_INITDICT, LZFU_INITLENGTH);
+	dict_length = LZFU_INITLENGTH;
+	memcpy(&lzfuhdr, rtfcomp, sizeof(lzfuhdr));
+	LE32_CPU(lzfuhdr.cbSize);	LE32_CPU(lzfuhdr.cbRawSize);
+	LE32_CPU(lzfuhdr.dwMagic);	LE32_CPU(lzfuhdr.dwCRC);
+	/*	printf("total size: %d\n", lzfuhdr.cbSize+4);
+	printf("raw size  : %d\n", lzfuhdr.cbRawSize);
+	printf("compressed: %s\n", (lzfuhdr.dwMagic == LZFU_COMPRESSED ? "yes" : "no"));
+	printf("CRC       : %#x\n", lzfuhdr.dwCRC);
+	printf("\n");*/
+	out_buf = (unsigned char*)xmalloc(lzfuhdr.cbRawSize+20); //plus 4 cause we have 2x'}' and a \0
+	in_size = 0;
+	// we add plus one here cause when referencing an array, the index is always one less
+	// (ie, when accessing 2 element array, highest index is [1])
+	while (in_size+0x11 < lzfuhdr.cbSize) {
+		memcpy(&flags, &(rtfcomp[in_size+0x10]), 1);
+		in_size += 1;
 
-    flag_mask = 1;
-    while (flag_mask != 0 && in_size+0x11 < lzfuhdr.cbSize) {
-      if (flag_mask & flags) {
-	// read 2 bytes from input
-	unsigned short int blkhdr, offset, length;
-	memcpy(&blkhdr, &(rtfcomp[in_size+0x10]), 2);
-	LE16_CPU(blkhdr);
-	in_size += 2;
-	/* swap the upper and lower bytes of blkhdr */
-	blkhdr = (((blkhdr&0xFF00)>>8)+
-		  ((blkhdr&0x00FF)<<8));
-	/* the offset is the first 24 bits of the 32 bit value */
-	offset = (blkhdr&0xFFF0)>>4;
-	/* the length of the dict entry are the last 8 bits */
-	length = (blkhdr&0x000F)+2;
-	// add the value we are about to print to the dictionary
-	for (i=0; i < length; i++) {
-	  unsigned char c1;
-	  c1 = dict[(offset+i)%4096];
-	  dict[dict_length]=c1;
-	  dict_length = (dict_length+1) % 4096;
-	  out_buf[out_ptr++] = c1;
+		flag_mask = 1;
+		while (flag_mask != 0 && in_size+0x11 < lzfuhdr.cbSize) {
+			if (flag_mask & flags) {
+				// read 2 bytes from input
+				unsigned short int blkhdr, offset, length;
+				memcpy(&blkhdr, &(rtfcomp[in_size+0x10]), 2);
+				LE16_CPU(blkhdr);
+				in_size += 2;
+				/* swap the upper and lower bytes of blkhdr */
+				blkhdr = (((blkhdr&0xFF00)>>8)+
+					  ((blkhdr&0x00FF)<<8));
+				/* the offset is the first 24 bits of the 32 bit value */
+				offset = (blkhdr&0xFFF0)>>4;
+				/* the length of the dict entry are the last 8 bits */
+				length = (blkhdr&0x000F)+2;
+				// add the value we are about to print to the dictionary
+				for (i=0; i < length; i++) {
+					unsigned char c1;
+					c1 = dict[(offset+i)%4096];
+					dict[dict_length]=c1;
+					dict_length = (dict_length+1) % 4096;
+					out_buf[out_ptr++] = c1;
+				}
+			} else {
+				// uncompressed chunk (single byte)
+				char c1 = rtfcomp[in_size+0x10];
+				in_size ++;
+				dict[dict_length] = c1;
+				dict_length = (dict_length+1)%4096;
+				out_buf[out_ptr++] = c1;
+			}
+			flag_mask <<= 1;
+		}
 	}
-      } else {
-	// uncompressed chunk (single byte)
-	char c1 = rtfcomp[in_size+0x10];
-	in_size ++;
-	dict[dict_length] = c1;
-	dict_length = (dict_length+1)%4096;
-	out_buf[out_ptr++] = c1;
-      }
-      flag_mask <<= 1;
-    }
-  }
-  // the compressed version doesn't appear to drop the closing braces onto the doc.
-  // we should do that
-  out_buf[out_ptr++] = '}';
-  out_buf[out_ptr++] = '}';
-  out_buf[out_ptr++] = '\0';
-  return out_buf;
+	// the compressed version doesn't appear to drop the closing braces onto the doc.
+	// we should do that
+	out_buf[out_ptr++] = '}';
+	out_buf[out_ptr++] = '}';
+	out_buf[out_ptr++] = '\0';
+	*size = out_ptr;
+	return out_buf;
 }
--- a/src/lzfu.h	Sun Jul 15 14:25:34 2007 -0700
+++ b/src/lzfu.h	Thu Aug 09 15:46:34 2007 -0700
@@ -1,4 +1,4 @@
 #ifndef LZFU_H
 #define LZFU_H
-unsigned char* lzfu_decompress (unsigned char* rtfcomp);
+unsigned char* lzfu_decompress (unsigned char* rtfcomp, size_t *size);
 #endif
--- a/src/readpst.c	Sun Jul 15 14:25:34 2007 -0700
+++ b/src/readpst.c	Thu Aug 09 15:46:34 2007 -0700
@@ -1005,6 +1005,7 @@
 	if (current_attach->data) {
 		fwrite(enc, 1, strlen(enc), f_output);
 		DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc)));
+		free(enc);	// caught by valgrind
 	} else {
 		pst_attach_to_file_base64(pst, current_attach, f_output);
 	}
@@ -1202,25 +1203,36 @@
 			fprintf(f_output, "\n");
 		}
 		removeCR(item->email->body);
-		if (base64_body)
-			write_email_body(f_output, base64_encode(item->email->body, strlen(item->email->body)));
-		else
+		if (base64_body) {
+			char *enc = base64_encode(item->email->body, strlen(item->email->body));
+			if (enc) {
+				write_email_body(f_output, enc);
+				free(enc);
+			}
+		}
+		else {
 			write_email_body(f_output, item->email->body);
+		}
 	}
 
 	if (item->email->htmlbody) {
 		if (boundary) {
 			fprintf(f_output, "\n--%s\n", boundary);
 			fprintf(f_output, "Content-type: text/html\n");
-			if (base64_body)
-				fprintf(f_output, "Content-Transfer-Encoding: base64\n");
+			if (base64_body) fprintf(f_output, "Content-Transfer-Encoding: base64\n");
 			fprintf(f_output, "\n");
 		}
 		removeCR(item->email->htmlbody);
-		if (base64_body)
-			write_email_body(f_output, base64_encode(item->email->htmlbody, strlen(item->email->htmlbody)));
-		else
+		if (base64_body) {
+			char *enc = base64_encode(item->email->htmlbody, strlen(item->email->htmlbody));
+			if (enc) {
+				write_email_body(f_output, enc);
+				free(enc);
+			}
+		}
+		else {
 			write_email_body(f_output, item->email->htmlbody);
+		}
 	}
 
 	if (item->email->rtf_compressed && save_rtf) {
@@ -1229,7 +1241,7 @@
 		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->data = lzfu_decompress(item->email->rtf_compressed, &current_attach->size);
 		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);
@@ -1265,7 +1277,6 @@
 	}
 
 	// attachments
-	base64_body = 0;
 	attach_num = 0;
 	for (current_attach = item->attach;
 		   current_attach;
@@ -1323,19 +1334,28 @@
 		fprintf(f_output, "LABEL;TYPE=home:%s\n", rfc2426_escape(contact->home_address));
 	}
 	if (contact->business_address) {
-		fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n",
-			(!contact->business_po_box) 	 ? "" : rfc2426_escape(contact->business_po_box),
-			"", // extended Address
-			(!contact->business_street) 	 ? "" : rfc2426_escape(contact->business_street),
-			(!contact->business_city)		 ? "" : rfc2426_escape(contact->business_city),
-			(!contact->business_state)		 ? "" : rfc2426_escape(contact->business_state),
-			(!contact->business_postal_code) ? "" : rfc2426_escape(contact->business_postal_code),
-			(!contact->business_country)	 ? "" : rfc2426_escape(contact->business_country));
+		// these should be equivalent, but valgrind complains about the single large fprintf
+		//
+		char *ab = (!contact->business_po_box	  ) 	? "" : rfc2426_escape(contact->business_po_box     );
+		char *ac = (!contact->business_street	  ) 	? "" : rfc2426_escape(contact->business_street     );
+		char *ad = (!contact->business_city 	  ) 	? "" : rfc2426_escape(contact->business_city       );
+		char *ae = (!contact->business_state	  ) 	? "" : rfc2426_escape(contact->business_state      );
+		char *af = (!contact->business_postal_code) 	? "" : rfc2426_escape(contact->business_postal_code);
+		char *ag = (!contact->business_country	  ) 	? "" : rfc2426_escape(contact->business_country    );
+		fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n", ab, "", ac, ad, ae, af, ag);
+	  //fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n",
+	  //	(!contact->business_po_box) 	 ? "" : rfc2426_escape(contact->business_po_box),
+	  //	"", // extended Address
+	  //	(!contact->business_street) 	 ? "" : rfc2426_escape(contact->business_street),
+	  //	(!contact->business_city)		 ? "" : rfc2426_escape(contact->business_city),
+	  //	(!contact->business_state)		 ? "" : rfc2426_escape(contact->business_state),
+	  //	(!contact->business_postal_code) ? "" : rfc2426_escape(contact->business_postal_code),
+	  //	(!contact->business_country)	 ? "" : rfc2426_escape(contact->business_country));
 		fprintf(f_output, "LABEL;TYPE=work:%s\n", rfc2426_escape(contact->business_address));
 	}
 	if (contact->other_address) {
 		fprintf(f_output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n",
-			(!contact->other_po_box)	   ? "" : rfc2426_escape(contact->business_po_box),
+			(!contact->other_po_box)	   ? "" : rfc2426_escape(contact->other_po_box),
 			"", // extended Address
 			(!contact->other_street)	   ? "" : rfc2426_escape(contact->other_street),
 			(!contact->other_city)		   ? "" : rfc2426_escape(contact->other_city),
--- a/src/readpstlog.c	Sun Jul 15 14:25:34 2007 -0700
+++ b/src/readpstlog.c	Thu Aug 09 15:46:34 2007 -0700
@@ -20,191 +20,230 @@
 int is_in(int a, int *b, int c);
 
 int main(int argc, char** argv) {
-  int *i=NULL, x, ptr, stop=0, flag;  
-  char *fname, *buf, format, rec_type;
-  unsigned char version;
-  int *show_type=NULL, show_size=0;
-  int *ex_type=NULL, ex_size=0;
-  unsigned int funcname, filename, text, end, dtype, line, c;
-  FILE *fp;
-  struct _debug_file_rec_m mfile_rec;
-  struct _debug_file_rec_l lfile_rec;
+	int level = 0;
+	int *i=NULL, x, ptr, stop=0, flag;
+	char *fname, *buf, rec_type;
+	unsigned char version;
+	int *show_type=NULL, show_size=0;
+	int *ex_type=NULL, ex_size=0;
+	unsigned int funcname, filename, text, end, dtype, line, c;
+	FILE *fp;
+	struct _debug_file_rec_m mfile_rec;
+	struct _debug_file_rec_l lfile_rec;
+	char format = 'D';  // default
+	while ((c = getopt(argc, argv, "f:t:x:")) != -1) {
+		switch(c) {
+			case 'f':
+				// change the output format
+				format = toupper(optarg[0]);
+				break;
+			case 't':
+				//change the type of statements shown
+				show_size = split_args(optarg, &show_type);
+				//		type = atoi(optarg);
+				break;
+			case 'x':
+				// change the type of statements excluded
+				ex_size = split_args(optarg, &ex_type);
+				break;
+		}
+	}
+	if (argc > optind) {
+		fname = argv[optind++];
+	} else {
+		usage();
+		exit(2);
+	}
 
-  while ((c = getopt(argc, argv, "f:t:x:")) != -1) {
-    switch(c) {
-    case 'f':
-      // change the output format
-      format = toupper(optarg[0]);
-      break;
-    case 't':
-      //change the type of statements shown
-      show_size = split_args(optarg, &show_type);
-      //      type = atoi(optarg);
-      break;
-    case 'x':
-      // change the type of statements excluded
-      ex_size = split_args(optarg, &ex_type);
-      break;
-    }
-  }
-  if (argc > optind) {
-    fname = argv[optind++];
-  } else {
-    usage();
-    exit(2);
-  }
+	fp = fopen(fname, "rb");
+	if (fp == NULL) {
+		printf("Error. couldn't open debug file\n");
+		return 2;
+	}
+	if (get(&version, sizeof(char), 1, fp)==0) {
+		printf("Error. could not read version byte from front of file");
+		return 3;
+	}
 
-  fp = fopen(fname, "rb");
-  if (fp == NULL) {
-    printf("Error. couldn't open debug file\n");
-    return 2;
-  }
-  if (get(&version, sizeof(char), 1, fp)==0) {
-    printf("Error. could not read version byte from front of file");
-    return 3;
-  }
+	if (version > DEBUG_VERSION) {
+		printf("Version number is higher than the format I know about.");
+		return 4;
+	}
 
-  if (version > DEBUG_VERSION) {
-    printf("Version number is higher than the format I know about.");
-    return 4;
-  }
-
-  buf = (char*) xmalloc(BUF_SIZE);
+	buf = (char*) xmalloc(BUF_SIZE);
 
-  while (!stop) {
-    if (fread(&x, sizeof(int), 1, fp)<=0) {
-      break;
-    }
-    ptr = 0;
-    if (x > 0) {
-      if (i != NULL)
-        free(i);
-      i = (int*)xmalloc(sizeof(int)*(x+1));
-      // plus 1 cause we want to read the offset of the next index
-      if (get(i, sizeof(int), x+1, fp)==0) {
-	// we have reached the end of the debug file
-	printf("oh dear. we must now end\n");
-	break;
-      }
-      while (ptr < x) {
-	fseek(fp,i[ptr++], SEEK_SET);
-        get(&rec_type, 1, sizeof(char), fp);
-        if (rec_type == 'L') {
-          get(&lfile_rec, sizeof(lfile_rec), 1, fp);
-          funcname=lfile_rec.funcname;
-          filename=lfile_rec.filename;
-          text = lfile_rec.text;
-          end = lfile_rec.end;
-          dtype = lfile_rec.type;
-          line = lfile_rec.line;
-        } else if (rec_type == 'M') {
-	  get(&mfile_rec, sizeof(mfile_rec), 1, fp);
-          funcname = mfile_rec.funcname;
-          filename = mfile_rec.filename;
-          text = mfile_rec.text;
-          end = mfile_rec.end;
-          dtype = mfile_rec.type;
-          line = mfile_rec.line;
-        }
-	if ((show_type == NULL || is_in(dtype, show_type, show_size))
-	    && (ex_type == NULL || !is_in(dtype, ex_type, ex_size))) {
-	  c = 0; flag = 0;
-	  while (c < end) {
-	    if (c + (BUF_SIZE-1) < end) {
-	      get(buf, 1, BUF_SIZE-1, fp);
-	      buf[BUF_SIZE-1] = '\0';
-	      c += BUF_SIZE-1;
-	    } else {
-	      get(buf, 1, end-c, fp);
-	      buf[end-c] = '\0';
-	      c = end;
-	    }
-	    if (flag == 0) {
-	      if (format=='T') { // text format
-                printf("%s[%d]: %s", &buf[funcname], line, &buf[text]);
-	      } else {
-		printf("Type: %d\nFile[line]: %s[%d]\nFunction:%s\nText:%s", dtype, 
-		       &buf[filename], line, &buf[funcname], &buf[text]);
-	      }
-	      flag = 1;
-	    } else {
-	      printf("%s", buf);
-	    }
-	  }
-	  printf("\n");
+	while (!stop) {
+		if (fread(&x, sizeof(int), 1, fp)<=0) break;
+		ptr = 0;
+		if (x > 0) {
+			if (i) free(i);
+			i = (int*)xmalloc(sizeof(int)*(x+1));
+			// plus 1 cause we want to read the offset of the next index
+			if (get(i, sizeof(int), x+1, fp)==0) {
+				// we have reached the end of the debug file
+				printf("oh dear. we must now end\n");
+				break;
+			}
+			while (ptr < x) {
+				fseek(fp,i[ptr++], SEEK_SET);
+				get(&rec_type, 1, sizeof(char), fp);
+				if (rec_type == 'L') {
+					get(&lfile_rec, sizeof(lfile_rec), 1, fp);
+					funcname=lfile_rec.funcname;
+					filename=lfile_rec.filename;
+					text = lfile_rec.text;
+					end = lfile_rec.end;
+					dtype = lfile_rec.type;
+					line = lfile_rec.line;
+				} else if (rec_type == 'M') {
+					get(&mfile_rec, sizeof(mfile_rec), 1, fp);
+					funcname = mfile_rec.funcname;
+					filename = mfile_rec.filename;
+					text = mfile_rec.text;
+					end = mfile_rec.end;
+					dtype = mfile_rec.type;
+					line = mfile_rec.line;
+				}
+				if (dtype == DEBUG_FUNCENT_NO) level++;
+				if ((show_type == NULL || is_in(dtype, show_type, show_size)) &&
+					(ex_type == NULL   || !is_in(dtype, ex_type, ex_size))) {
+					c = 0; flag = 0;
+					while (c < end) {
+						int ii = (level-1) * 4;
+						if (ii < 0) ii = 0;
+						if (ii > 64) ii = 64;
+						char indent[ii+1];
+						memset(indent, ' ', ii);
+						indent[ii] = '\0';
+						if (c + (BUF_SIZE-1) < end) {
+							get(buf, 1, BUF_SIZE-1, fp);
+							buf[BUF_SIZE-1] = '\0';
+							c += BUF_SIZE-1;
+						} else {
+							get(buf, 1, end-c, fp);
+							buf[end-c] = '\0';
+							c = end;
+						}
+						if (flag == 0) {
+							if (format == 'I') { // indented text format
+								char *b = buf+text;
+								printf("%s %s/%s[%d]: ", indent, &buf[filename], &buf[funcname], line);
+								while (b) {
+									char *p = strchr(b, '\n');
+									if (p) {
+										*p = '\0';
+										printf("%s\n%s ", b, indent);
+										b = p + 1;
+									}
+									else {
+										printf("%s", b);
+										b = NULL;
+									}
+								}
+							}
+							else if (format == 'T') { // text format
+								printf("%s/%s[%d]: %s", &buf[filename], &buf[funcname], line, &buf[text]);
+							} else {
+								printf("Type: %d\nFile[line]: %s[%d]\nFunction:%s\nText:%s", dtype,
+									   &buf[filename], line, &buf[funcname], &buf[text]);
+							}
+							flag = 1;
+						} else {
+							if (format == 'I') {
+								char *b = buf;
+								while (b) {
+									char *p = strchr(b, '\n');
+									if (p) {
+										*p = '\0';
+										printf("%s\n%s ", b, indent);
+										b = p + 1;
+									}
+									else {
+										printf("%s", b);
+										b = NULL;
+									}
+								}
+							}
+							else printf("%s", buf);
+						}
+					}
+					printf("\n");
+				}
+				if (dtype == DEBUG_FUNCRET_NO) level--;
+			}
+			if (fseek(fp, i[ptr], SEEK_SET)==-1) {
+				printf("finished\n");
+				break;
+			}
+		} else {
+			printf("...no more items\n");
+			break;
+		}
 	}
-      }
-      if (fseek(fp, i[ptr], SEEK_SET)==-1) {
-	printf("finished\n");
-	break;
-      }
-    } else {
-      printf("...no more items\n");
-      break;
-    }
-  }
-  free(buf);
-  fclose(fp);
-  return 0;
+	free(buf);
+	fclose(fp);
+	return 0;
 }
-    
+
 size_t get(void * buf, int size, unsigned int  count, FILE *fp) {
-  size_t z;
-  if ((z=fread(buf,size, count, fp)) < count) {
-    printf("Read Failed! (size=%d, count=%d,z=%ld)\n", size, count, (long)z);
-    exit(1);
-  }
-  return z;
+	size_t z;
+	if ((z=fread(buf,size, count, fp)) < count) {
+		printf("Read Failed! (size=%d, count=%d,z=%ld)\n", size, count, (long)z);
+		exit(1);
+	}
+	return z;
 }
 
 int usage() {
-  printf("readlog -t[show_type] -x[exclude_type] -f[format] filename\n");
-  printf("\tformat:\n\t\tt: Text log format\n");
-  printf("\tshow_type:\n\t\tcomma separated list of types to show "
-	 "[ie, 2,4,1,6]\n");
-  printf("\texclude_type:\n\t\tcomma separated list of types to exclude "
-	 "[ie, 1,5,3,7]\n");
-  return 0;
+	printf("readlog -t[show_type] -x[exclude_type] -f[format] filename\n");
+	printf("\tformat:\n\t\tt: text log format\n");
+	printf("\t\ti: indented text log format\n");
+	printf("\tshow_type:\n\t\tcomma separated list of types to show "
+	   "[ie, 2,4,1,6]\n");
+	printf("\texclude_type:\n\t\tcomma separated list of types to exclude "
+	   "[ie, 1,5,3,7]\n");
+	return 0;
 }
 
+
 int split_args(char *args, int **targ) {
-  int count = 1, *i, x, z;
-  char *tmp = args, *y;
-  if (*targ != NULL) {
-    free(*targ);
-  }
-  // find the number of tokens in the string. Starting 
-  // from 1 cause there will always be one
-  while ((tmp = strchr(tmp, ',')) != NULL) {
-    tmp++; count++;
-  }
-  *targ = (int*)xmalloc(count * sizeof(int));
-  i = *targ; // for convienience
-  tmp = args;
-  z = 0;
-  for (x = 0; x < count; x++) {
-    y = strtok(tmp, ",");
-    tmp = NULL; // must be done after first call
-    if (y != NULL) {
-      i[x] = atoi(y);
-      z++;
-    }
-  }
-  return z;
+	int count = 1, *i, x, z;
+	char *tmp = args, *y;
+	if (*targ != NULL) {
+	  free(*targ);
+	}
+	// find the number of tokens in the string. Starting
+	// from 1 cause there will always be one
+	while ((tmp = strchr(tmp, ',')) != NULL) {
+		tmp++; count++;
+	}
+	*targ = (int*)xmalloc(count * sizeof(int));
+	i = *targ; // for convienience
+	tmp = args;
+	z = 0;
+	for (x = 0; x < count; x++) {
+		y = strtok(tmp, ",");
+		tmp = NULL; // must be done after first call
+		if (y != NULL) {
+			i[x] = atoi(y);
+			z++;
+		}
+	}
+	return z;
 }
 
+
 // checks to see if the first arg is in the array of the second arg,
 // the size of which is specified with the third arg. If the second
-// arg is NULL, then it is obvious that it ain't there.
+// arg is NULL, then it is obvious that it is not there.
 int is_in(int a, int *b, int c){
-  int d = 0;
-  if (b == NULL || c == 0) { // no array or no items in array
-    return 0;
-  }
-  while (d < c) {
-    if (a == b[d])
-      return 1;
-    d++;
-  }
-  return 0;
+	int d = 0;
+	if (b == NULL || c == 0) { // no array or no items in array
+		return 0;
+	}
+	while (d < c) {
+		if (a == b[d]) return 1;
+		d++;
+	}
+	return 0;
 }
--- a/xml/libpst.in	Sun Jul 15 14:25:34 2007 -0700
+++ b/xml/libpst.in	Thu Aug 09 15:46:34 2007 -0700
@@ -245,7 +245,8 @@
                     <term>-f <replaceable class="parameter">format</replaceable></term>
                     <listitem><para>
                         Sets the format of the text log output.  Currently, the only valid output
-                        format is T, for text; anything else gives the default.
+                        formats are T, for single line text, D for the default default multi line
+                        format, and I for an indented style with single line text.
                     </para></listitem>
                 </varlistentry>
                 <varlistentry>
@@ -320,9 +321,15 @@
                     </para></listitem>
                 </varlistentry>
                 <varlistentry>
+                    <term>9</term>
+                    <listitem><para>
+                        Function entries
+                    </para></listitem>
+                </varlistentry>
+                <varlistentry>
                     <term>10</term>
                     <listitem><para>
-                        Function calls
+                        Function exits
                     </para></listitem>
                 </varlistentry>
                 <varlistentry>
@@ -1056,7 +1063,7 @@
 1009  RTF Compressed body
 1010  RTF whitespace prefix count
 1011  RTF whitespace tailing count
-1013  HTML Email Body. Does not exist if the email doesn't have a HTML version
+1013  HTML Email Body. Does not exist if the email doesn't have an HTML version
 1035  Message ID
 1042  In-Reply-To or Parent's Message ID
 1046  Return Path
@@ -1070,7 +1077,7 @@
 35df  Valid Folder Mask
 35e0  binary record found in first item. Contains the reference to "Top of Personal Folder" item
 35e3  binary record with a reference to "Deleted Items" item
-35e7  binary record with a refernece to "Search Root" item
+35e7  binary record with a reference to "Search Root" item
 3602  the number of emails stored in a folder
 3603  the number of unread emails in a folder
 360a  Has Subfolders
@@ -1165,10 +1172,10 @@
 3a64  Other Address Post Office box
 65e3  Entry ID
 67f2  Attachment ID2 value
-67ff  Password checksum [0x67FF]
+67ff  Password checksum
 6f02  Secure HTML Body
 6f04  Secure Text Body
-7c07  Top of folders RecID [0x7c07]
+7c07  Top of folders RecID
 8000  Contain extra bits of information that have been taken from the email's header. I call them extra lines
 8005  Contact Fullname
 801a  Home Address
@@ -1180,9 +1187,9 @@
 8085  Email Address 1 Record
 8092  Email Address 2 Transport
 8093  Email Address 2 Address
-8094  DEBUG_EMAIL (("Email Address 2 Description
+8094  Email Address 2 Description
 8095  Email Address 2 Record
-80a2  DEBUG_EMAIL (("Email Address 3 Transport
+80a2  Email Address 3 Transport
 80a3  Email Address 3 Address
 80a4  Email Address 3 Description
 80a5  Email Address 3 Record