diff src/libpst.c @ 35:b2f247463b83 stable-0-5-6

better decoding of 7c blocks
author carl
date Sun, 15 Jul 2007 14:25:34 -0700
parents 07177825c91b
children 6fe121a971c9
line wrap: on
line diff
--- a/src/libpst.c	Thu Jul 12 14:59:13 2007 -0700
+++ b/src/libpst.c	Sun Jul 15 14:25:34 2007 -0700
@@ -44,7 +44,7 @@
 #define PST_SIGNATURE 0x4E444221
 
 struct _pst_table_ptr_struct{
-	u_int32_t start;
+	int32_t start;
 	int32_t u1;
 	int32_t offset;
 };
@@ -55,12 +55,12 @@
 } pst_block_header;
 
 typedef struct _pst_id2_assoc {
-	int32_t id2;
-	int32_t id;
+	u_int32_t id2;
+	u_int32_t id;
 	int32_t table2;
 } pst_id2_assoc;
 
-// this is an array of the un-encrypted values. the un-encrypyed value is in the position
+// 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
 //					   8	 9	   a	 b	   c	 d	   e	 f
@@ -192,9 +192,6 @@
 
 pst_desc_ll* pst_getTopOfFolders(pst_file *pf, pst_item *root) {
 	pst_desc_ll *ret;
-	//	pst_item *i;
-	//	char *a, *b;
-	//	int x,z;
 	DEBUG_ENT("pst_getTopOfFolders");
 	if (!root || !root->message_store) {
 		DEBUG_INDEX(("There isn't a top of folder record here.\n"));
@@ -521,7 +518,7 @@
 			if (index.id == 0) break;
 			DEBUG_INDEX(("[%i]%i Item [id = %#x, offset = %#x, u1 = %#x, size = %i(%#x)]\n",
 						depth, x, index.id, index.offset, index.u1, index.size, index.size));
-			if (index.id & 0x02) DEBUG_INDEX(("two-bit set!!\n"));
+			// if (index.id & 0x02) DEBUG_INDEX(("two-bit set!!\n"));
 			if ((index.id >= end_val) || (index.id < old)) {
 				DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n"));
 				if (buf) free(buf);
@@ -591,23 +588,124 @@
 }
 
 
-int32_t _pst_build_desc_ptr (pst_file *pf, int32_t offset, int32_t depth, int32_t linku1, u_int32_t *high_id, int32_t start_val, int32_t end_val) {
+/** this list node type is used for a quick cache
+	of the descriptor tree nodes (rooted at pf->d_head)
+	and for a "lost and found" list.
+	If the parent isn't found yet, put it on the lost and found
+	list and check it each time you read a new item.
+*/
+struct cache_list_node {
+	pst_desc_ll *ptr;
+	/** only used for lost and found lists */
+	u_int32_t parent;
+	struct cache_list_node *next;
+	struct cache_list_node *prev;
+};
+struct cache_list_node *cache_head;
+struct cache_list_node *cache_tail;
+struct cache_list_node *lostfound_head;
+int32_t cache_count;
+
+
+/**
+	add the d_ptr descriptor into the global tree
+*/
+void record_descriptor(pst_file *pf, pst_desc_ll *d_ptr, u_int32_t parent_id) {
+	struct cache_list_node *lostfound_ptr = NULL;
+	struct cache_list_node *cache_ptr	  = NULL;
+	pst_desc_ll 		   *parent		  = NULL;
+
+	if (parent_id == 0 || parent_id == d_ptr->id) {
+		// add top level node to the descriptor tree
+		if (parent_id == 0) {
+			DEBUG_INDEX(("No Parent\n"));
+		} else {
+			DEBUG_INDEX(("Record is its own parent. What is this world coming to?\n"));
+		}
+		if (pf->d_tail)  pf->d_tail->next = d_ptr;
+		if (!pf->d_head) pf->d_head = d_ptr;
+		d_ptr->prev = pf->d_tail;
+		pf->d_tail	= d_ptr;
+	} else {
+		DEBUG_INDEX(("Searching for parent\n"));
+		// check in the cache for the parent
+		cache_ptr = cache_head;
+		while (cache_ptr && (cache_ptr->ptr->id != parent_id)) {
+			cache_ptr = cache_ptr->next;
+		}
+		if (!cache_ptr && (parent = _pst_getDptr(pf, parent_id)) == NULL) {
+			// check in the lost/found list
+			lostfound_ptr = lostfound_head;
+			while (lostfound_ptr && (lostfound_ptr->ptr->id != parent_id)) {
+				lostfound_ptr = lostfound_ptr->next;
+			}
+			if (!lostfound_ptr) {
+				DEBUG_WARN(("ERROR -- cannot find parent with id %#x. Adding to lost/found\n", parent_id));
+				lostfound_ptr = (struct cache_list_node*) xmalloc(sizeof(struct cache_list_node));
+				lostfound_ptr->prev   = NULL;
+				lostfound_ptr->next   = lostfound_head;
+				lostfound_ptr->parent = parent_id;
+				lostfound_ptr->ptr	  = d_ptr;
+				lostfound_head = lostfound_ptr;
+			} else {
+				parent = lostfound_ptr->ptr;
+				DEBUG_INDEX(("Found parent (%#x) in Lost and Found\n", parent->id));
+			}
+		}
+
+		if (cache_ptr || parent) {
+			if (cache_ptr)
+				// parent is already in the cache
+				parent = cache_ptr->ptr;
+			else {
+				//add the parent to the cache
+				DEBUG_INDEX(("Cache addition\n"));
+				cache_ptr = (struct cache_list_node*) xmalloc(sizeof(struct cache_list_node));
+				cache_ptr->prev = NULL;
+				cache_ptr->next = cache_head;
+				cache_ptr->ptr	= parent;
+				cache_head = cache_ptr;
+				if (!cache_tail) cache_tail = cache_ptr;
+				cache_count++;
+				if (cache_count > 100) {
+					DEBUG_INDEX(("trimming quick cache\n"));
+					//remove one from the end
+					cache_ptr  = cache_tail;
+					cache_tail = cache_ptr->prev;
+					free (cache_ptr);
+					cache_count--;
+				}
+			}
+			DEBUG_INDEX(("Found a parent\n"));
+			parent->no_child++;
+			d_ptr->parent = parent;
+			if (parent->child_tail)  parent->child_tail->next = d_ptr;
+			if (!parent->child) 	 parent->child = d_ptr;
+			d_ptr->prev = parent->child_tail;
+			parent->child_tail = d_ptr;
+		}
+	}
+}
+
+int32_t _pst_build_desc_ptr (pst_file *pf, int32_t offset, int32_t depth, int32_t linku1, u_int32_t *high_id, u_int32_t start_val, u_int32_t end_val) {
 	struct _pst_table_ptr_struct table, table2;
 	pst_desc desc_rec;
-	pst_desc_ll *d_ptr=NULL, *d_par=NULL;
-	int32_t d_ptr_count = 0;
+	pst_desc_ll *d_ptr=NULL, *parent=NULL;
 	int32_t x, item_count;
-	int32_t old = start_val;
+	u_int32_t old = start_val;
 	char *buf = NULL, *bptr;
+	struct cache_list_node *cache_ptr = NULL;
+	struct cache_list_node *lostfound_ptr = NULL;
+	struct cache_list_node *lostfound_shd = NULL;
+	struct cache_list_node *lostfound_tmp = NULL;
 
-	struct _pst_d_ptr_ll {
-		pst_desc_ll * ptr;
-		int32_t parent; // used for lost and found lists
-		struct _pst_d_ptr_ll * next;
-		struct _pst_d_ptr_ll * prev;
-	} *d_ptr_head=NULL, *d_ptr_tail=NULL, *d_ptr_ptr=NULL, *lf_ptr=NULL, *lf_head=NULL, *lf_shd=NULL, *lf_tmp;
-	// lf_ptr and lf_head are used for the lost/found list. If the parent isn't found yet, put it on this
-	// list and check it each time you read a new item
+	if (depth == 0) {
+		// initialize the linked list and lost/found list.
+		cache_head = NULL;
+		cache_tail = NULL;
+		lostfound_head = NULL;
+		cache_count = 0;
+	}
 
 	DEBUG_ENT("_pst_build_desc_ptr");
 	DEBUG_INDEX(("offset %x depth %i linku1 %x start %x end %x\n", offset, depth, linku1, start_val, end_val));
@@ -663,7 +761,7 @@
 			}
 			old = desc_rec.d_id;
 			if (x == 1) {	// first entry
-				if (start_val != -1 && desc_rec.d_id != start_val) {
+				if (start_val && (desc_rec.d_id != start_val)) {
 					DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n"));
 					if (buf) free(buf);
 					DEBUG_RET();
@@ -672,7 +770,7 @@
 			}
 			// When duplicates found, just update the info.... perhaps this is correct functionality
 			DEBUG_INDEX(("Searching for existing record\n"));
-			if (desc_rec.d_id <= *high_id && (d_ptr = _pst_getDptr(pf, desc_rec.d_id)) !=  NULL) {
+			if (desc_rec.d_id <= *high_id && (d_ptr = _pst_getDptr(pf, desc_rec.d_id))) {
 				DEBUG_INDEX(("Updating Existing Values\n"));
 				d_ptr->list_index = _pst_getID(pf, desc_rec.list_id);
 				d_ptr->desc = _pst_getID(pf, desc_rec.desc_id);
@@ -706,72 +804,7 @@
 					d_ptr->prev   = NULL;
 					d_ptr->next   = NULL;
 					d_ptr->parent = NULL;
-
-					// ok, now place in correct place
-					DEBUG_INDEX(("Searching for parent\n"));
-					if (desc_rec.parent_id == 0) {
-						DEBUG_INDEX(("No Parent\n"));
-						if (pf->d_tail)  pf->d_tail->next = d_ptr;
-						if (!pf->d_head) pf->d_head = d_ptr;
-						d_ptr->prev = pf->d_tail;
-						pf->d_tail	= d_ptr;
-					} else {
-						// check in the quick list
-						d_ptr_ptr = d_ptr_head;
-						while (d_ptr_ptr && (d_ptr_ptr->ptr->id != desc_rec.parent_id)) {
-							d_ptr_ptr = d_ptr_ptr->next;
-						}
-
-						if (!d_ptr_ptr && (d_par = _pst_getDptr(pf, desc_rec.parent_id)) == NULL) {
-							// check in the lost/found list
-							lf_ptr = lf_head;
-							while (lf_ptr && lf_ptr->ptr->id != desc_rec.parent_id) {
-								lf_ptr = lf_ptr->next;
-							}
-							if (!lf_ptr) {
-								DEBUG_WARN(("ERROR -- not found parent with id %#x. Adding to lost/found\n", desc_rec.parent_id));
-								lf_ptr = (struct _pst_d_ptr_ll*) xmalloc(sizeof(struct _pst_d_ptr_ll));
-								lf_ptr->prev   = NULL;
-								lf_ptr->next   = lf_head;
-								lf_ptr->parent = desc_rec.parent_id;
-								lf_ptr->ptr    = d_ptr;
-								lf_head = lf_ptr;
-							} else {
-								d_par = lf_ptr->ptr;
-								DEBUG_INDEX(("Found parent (%#x) in Lost and Found\n", d_par->id));
-							}
-						}
-
-						if (d_ptr_ptr || d_par) {
-							if (d_ptr_ptr)
-								d_par = d_ptr_ptr->ptr;
-							else {
-								//add the d_par to the cache
-								DEBUG_INDEX(("Update - Cache addition\n"));
-								d_ptr_ptr = (struct _pst_d_ptr_ll*) xmalloc(sizeof(struct _pst_d_ptr_ll));
-								d_ptr_ptr->prev = NULL;
-								d_ptr_ptr->next = d_ptr_head;
-								d_ptr_ptr->ptr	= d_par;
-								d_ptr_head = d_ptr_ptr;
-								if (!d_ptr_tail) d_ptr_tail = d_ptr_ptr;
-								d_ptr_count++;
-								if (d_ptr_count > 100) {
-									//remove on from the end
-									d_ptr_ptr = d_ptr_tail;
-									d_ptr_tail = d_ptr_ptr->prev;
-									free (d_ptr_ptr);
-									d_ptr_count--;
-								}
-							}
-							DEBUG_INDEX(("Found a parent\n"));
-							d_par->no_child++;
-							d_ptr->parent = d_par;
-							if (d_par->child_tail)	d_par->child_tail->next = d_ptr;
-							if (!d_par->child)		d_par->child = d_ptr;
-							d_ptr->prev = d_par->child_tail;
-							d_par->child_tail = d_ptr;
-						}
-					}
+					record_descriptor(pf, d_ptr, desc_rec.parent_id);	// add to the global tree
 				}
 			} else {
 				if (*high_id < desc_rec.d_id) {
@@ -789,99 +822,31 @@
 				d_ptr->child = NULL;
 				d_ptr->child_tail = NULL;
 				d_ptr->no_child = 0;
+				record_descriptor(pf, d_ptr, desc_rec.parent_id);	// add to the global tree
 
-				DEBUG_INDEX(("Searching for parent\n"));
-				if (desc_rec.parent_id == 0 || desc_rec.parent_id == desc_rec.d_id) {
-					if (desc_rec.parent_id == 0) {
-						DEBUG_INDEX(("No Parent\n"));
-					} else {
-						DEBUG_INDEX(("Record is its own parent. What is this world coming to?\n"));
-					}
-					if (pf->d_tail)  pf->d_tail->next = d_ptr;
-					if (!pf->d_head) pf->d_head = d_ptr;
-					d_ptr->prev = pf->d_tail;
-					pf->d_tail	= d_ptr;
-				} else {
-					d_ptr_ptr = d_ptr_head;
-					while (d_ptr_ptr && (d_ptr_ptr->ptr->id != desc_rec.parent_id)) {
-						d_ptr_ptr = d_ptr_ptr->next;
-					}
-					if (!d_ptr_ptr && (d_par = _pst_getDptr(pf, desc_rec.parent_id)) == NULL) {
-						// check in the lost/found list
-						lf_ptr = lf_head;
-						while (lf_ptr && (lf_ptr->ptr->id != desc_rec.parent_id)) {
-							lf_ptr = lf_ptr->next;
-						}
-						if (!lf_ptr) {
-							DEBUG_WARN(("ERROR -- not found parent with id %#x. Adding to lost/found\n", desc_rec.parent_id));
-							lf_ptr = (struct _pst_d_ptr_ll*) xmalloc(sizeof(struct _pst_d_ptr_ll));
-							lf_ptr->prev   = NULL;
-							lf_ptr->next   = lf_head;
-							lf_ptr->parent = desc_rec.parent_id;
-							lf_ptr->ptr    = d_ptr;
-							lf_head = lf_ptr;
-						} else {
-							d_par = lf_ptr->ptr;
-							DEBUG_INDEX(("Found parent (%#x) in Lost and Found\n", d_par->id));
-						}
-					}
-
-					if (d_ptr_ptr || d_par) {
-						if (d_ptr_ptr)
-							d_par = d_ptr_ptr->ptr;
-						else {
-							//add the d_par to the cache
-							DEBUG_INDEX(("Normal - Cache addition\n"));
-							d_ptr_ptr = (struct _pst_d_ptr_ll*) xmalloc(sizeof(struct _pst_d_ptr_ll));
-							d_ptr_ptr->prev = NULL;
-							d_ptr_ptr->next = d_ptr_head;
-							d_ptr_ptr->ptr	= d_par;
-							d_ptr_head = d_ptr_ptr;
-							if (!d_ptr_tail) d_ptr_tail = d_ptr_ptr;
-							d_ptr_count++;
-							if (d_ptr_count > 100) {
-								//remove one from the end
-								d_ptr_ptr  = d_ptr_tail;
-								d_ptr_tail = d_ptr_ptr->prev;
-								free (d_ptr_ptr);
-								d_ptr_count--;
-							}
-						}
-
-						DEBUG_INDEX(("Found a parent\n"));
-						d_par->no_child++;
-						d_ptr->parent = d_par;
-						if (d_par->child_tail)	d_par->child_tail->next = d_ptr;
-						if (!d_par->child)		d_par->child = d_ptr;
-						d_ptr->prev = d_par->child_tail;
-						d_par->child_tail = d_ptr;
-					}
-				}
 			}
 			// check here to see if d_ptr is the parent of any of the items in the lost / found list
-			lf_ptr = lf_head;
-			lf_shd = NULL;
-			while (lf_ptr) {
-				if (lf_ptr->parent == d_ptr->id) {
-					DEBUG_INDEX(("Found a child  (%#x) of the current record. Joining to main structure.\n", lf_ptr->ptr->id));
-					d_par = d_ptr;
-					d_ptr = lf_ptr->ptr;
-					d_par->no_child++;
-					d_ptr->parent = d_par;
-					if (d_par->child_tail) d_par->child_tail->next = d_ptr;
-					if (!d_par->child)	   d_par->child = d_ptr;
-					d_ptr->prev = d_par->child_tail;
-					d_par->child_tail = d_ptr;
-					if (!lf_shd)
-						lf_head = lf_ptr->next;
-					else
-						lf_shd->next = lf_ptr->next;
-					lf_tmp = lf_ptr->next;
-					free(lf_ptr);
-					lf_ptr = lf_tmp;
+			lostfound_ptr = lostfound_head;
+			lostfound_shd = NULL;
+			while (lostfound_ptr) {
+				if (lostfound_ptr->parent == d_ptr->id) {
+					DEBUG_INDEX(("Found a child  (%#x) of the current record. Joining to main structure.\n", lostfound_ptr->ptr->id));
+					parent = d_ptr;
+					d_ptr = lostfound_ptr->ptr;
+					parent->no_child++;
+					d_ptr->parent = parent;
+					if (parent->child_tail) parent->child_tail->next = d_ptr;
+					if (!parent->child) 	parent->child = d_ptr;
+					d_ptr->prev = parent->child_tail;
+					parent->child_tail = d_ptr;
+					if (!lostfound_shd) lostfound_head		= lostfound_ptr->next;
+					else				lostfound_shd->next = lostfound_ptr->next;
+					lostfound_tmp = lostfound_ptr->next;
+					free(lostfound_ptr);
+					lostfound_ptr = lostfound_tmp;
 				} else {
-					lf_shd = lf_ptr;
-					lf_ptr = lf_ptr->next;
+					lostfound_shd = lostfound_ptr;
+					lostfound_ptr = lostfound_ptr->next;
 				}
 			}
 		}
@@ -930,14 +895,21 @@
 			_pst_build_desc_ptr(pf, table.offset, depth+1, table.u1, high_id, table.start, table2.start);
 		}
 	}
-	// ok, lets try freeing the d_ptr_head cache here
-	while (d_ptr_head) {
-		d_ptr_ptr = d_ptr_head->next;
-		free(d_ptr_head);
-		d_ptr_head = d_ptr_ptr;
+	if (depth == 0) {
+		// free the quick cache
+		while (cache_head) {
+			cache_ptr = cache_head->next;
+			free(cache_head);
+			cache_head = cache_ptr;
+		}
+		// free the lost and found
+		while (lostfound_head) {
+			lostfound_ptr = lostfound_head->next;
+			WARN(("unused lost/found item with parent %d))", lostfound_head->parent));
+			free(lostfound_head);
+			lostfound_head = lostfound_ptr;
+		}
 	}
-	// TODO - need to free lost and found list also!!
-	// TODO - and show error for any remaining lf items
 	if (buf) free(buf);
 	DEBUG_RET();
 	return 0;
@@ -1076,14 +1048,49 @@
 }
 
 
+void freeall(unsigned char *buf, pst_block_offset_pointer *p1,
+								 pst_block_offset_pointer *p2,
+								 pst_block_offset_pointer *p3,
+								 pst_block_offset_pointer *p4,
+								 pst_block_offset_pointer *p5,
+								 pst_block_offset_pointer *p6,
+								 pst_block_offset_pointer *p7) {
+	if (buf) free(buf);
+	if (p1->needfree) free(p1->from);
+	if (p2->needfree) free(p2->from);
+	if (p3->needfree) free(p3->from);
+	if (p4->needfree) free(p4->from);
+	if (p5->needfree) free(p5->from);
+	if (p6->needfree) free(p6->from);
+	if (p7->needfree) free(p7->from);
+}
+
+
 pst_num_array * _pst_parse_block(pst_file *pf, u_int32_t block_id, pst_index2_ll *i2_head) {
 	unsigned char *buf = NULL;
 	pst_num_array *na_ptr = NULL, *na_head = NULL;
-	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, ind2_end = 0, list_start = 0, num_list = 0, cur_list = 0;
-	int32_t block_type, rec_size;
+	pst_block_offset_pointer block_offset1;
+	pst_block_offset_pointer block_offset2;
+	pst_block_offset_pointer block_offset3;
+	pst_block_offset_pointer block_offset4;
+	pst_block_offset_pointer block_offset5;
+	pst_block_offset_pointer block_offset6;
+	pst_block_offset_pointer block_offset7;
+	u_int32_t size;
+	u_int32_t x;
+	u_int32_t num_recs;
+	u_int32_t count_rec;
+	u_int32_t num_list;
+	u_int32_t cur_list;
+	u_int32_t block_type;
+	u_int32_t rec_size;
+	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;
 	size_t read_size=0;
 	pst_x_attrib_ll *mapptr;
 
@@ -1091,17 +1098,21 @@
 		u_int16_t type;
 		u_int16_t ref_type;
 		u_int32_t value;
-	} table_rec; //for type 1 ("BC") blocks
+	} table_rec;	//for type 1 (0xBCEC) blocks
 	struct {
 		u_int16_t ref_type;
 		u_int16_t type;
 		u_int16_t ind2_off;
-		u_int16_t u1;
-	} table2_rec; //for type 2 ("7C") blocks
+		u_int8_t  size;
+		u_int8_t  slot;
+	} table2_rec;	//for type 2 (0x7CEC) blocks
+	struct {
+		u_int32_t id;
+	} table3_rec;	//for type 3 (0x0101) blocks
 	struct {
 		u_int16_t index_offset;
 		u_int16_t type;
-		u_int16_t offset;
+		u_int32_t offset;
 	} block_hdr;
 	struct {
 		unsigned char seven_c;
@@ -1110,10 +1121,8 @@
 		u_int16_t u2;
 		u_int16_t u3;
 		u_int16_t rec_size;
-		u_int16_t b_five_offset;
-		u_int16_t u5;
-		u_int16_t ind2_offset;
-		u_int16_t u6;
+		u_int32_t b_five_offset;
+		u_int32_t ind2_offset;
 		u_int16_t u7;
 		u_int16_t u8;
 	} seven_c_blk;
@@ -1130,10 +1139,18 @@
 		return NULL;
 	}
 
+	block_offset1.needfree = 0;
+	block_offset2.needfree = 0;
+	block_offset3.needfree = 0;
+	block_offset4.needfree = 0;
+	block_offset5.needfree = 0;
+	block_offset6.needfree = 0;
+	block_offset7.needfree = 0;
+
 	memcpy(&block_hdr, buf, sizeof(block_hdr));
 	LE16_CPU(block_hdr.index_offset);
 	LE16_CPU(block_hdr.type);
-	LE16_CPU(block_hdr.offset);
+	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));
 
 	ind_ptr = block_hdr.index_offset;
@@ -1141,26 +1158,34 @@
 	if (block_hdr.type == 0xBCEC) { //type 1
 		block_type = 1;
 
-		_pst_getBlockOffset(buf, read_size, ind_ptr, block_hdr.offset, &block_offset);
-		fr_ptr = block_offset.from;
-
-		memcpy(&table_rec, &(buf[fr_ptr]), sizeof(table_rec));
+		if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, block_hdr.offset, &block_offset1)) {
+			DEBUG_WARN(("internal error (bc.b5 offset %#x) in reading block id %#x\n", block_hdr.offset, block_id));
+			freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
+			DEBUG_RET();
+			return NULL;
+		}
+		memcpy(&table_rec, block_offset1.from, sizeof(table_rec));
 		LE16_CPU(table_rec.type);
 		LE16_CPU(table_rec.ref_type);
 		LE32_CPU(table_rec.value);
-		DEBUG_EMAIL(("table_rec (type=%#hx, ref_type=%#hx, value=%#x\n", table_rec.type, table_rec.ref_type, table_rec.value));
+		DEBUG_EMAIL(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value));
 
 		if (table_rec.type != 0x02B5) {
 			WARN(("Unknown second block constant - %#X for id %#x\n", table_rec.type, block_id));
 			DEBUG_HEXDUMPC(buf, sizeof(table_rec), 0x10);
-			if (buf) free (buf);
+			freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
 			DEBUG_RET();
 			return NULL;
 		}
 
-		_pst_getBlockOffset(buf, read_size, ind_ptr, table_rec.value, &block_offset);
-		list_start = block_offset.from;
-		to_ptr	   = block_offset.to;
+		if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset2)) {
+			DEBUG_WARN(("internal error (bc.b5.desc offset) in reading block id %#x\n", table_rec.value, block_id));
+			freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
+			DEBUG_RET();
+			return NULL;
+		}
+		list_start = block_offset2.from;
+		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
@@ -1168,18 +1193,21 @@
 	else if (block_hdr.type == 0x7CEC) { //type 2
 		block_type = 2;
 
-		_pst_getBlockOffset(buf, read_size, ind_ptr, block_hdr.offset, &block_offset);
-		fr_ptr = block_offset.from; //now got pointer to "7C block"
+		if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, block_hdr.offset, &block_offset3)) {
+			DEBUG_WARN(("internal error (7c.7c offset %#x) in reading block id %#x\n", block_hdr.offset, block_id));
+			freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
+			DEBUG_RET();
+			return NULL;
+		}
+		fr_ptr = block_offset3.from; //now got pointer to "7C block"
 		memset(&seven_c_blk, 0, sizeof(seven_c_blk));
-		memcpy(&seven_c_blk, &(buf[fr_ptr]), sizeof(seven_c_blk));
+		memcpy(&seven_c_blk, fr_ptr, sizeof(seven_c_blk));
 		LE16_CPU(seven_c_blk.u1);
 		LE16_CPU(seven_c_blk.u2);
 		LE16_CPU(seven_c_blk.u3);
 		LE16_CPU(seven_c_blk.rec_size);
-		LE16_CPU(seven_c_blk.b_five_offset);
-		LE16_CPU(seven_c_blk.u5);
-		LE16_CPU(seven_c_blk.ind2_offset);
-		LE16_CPU(seven_c_blk.u6);
+		LE32_CPU(seven_c_blk.b_five_offset);
+		LE32_CPU(seven_c_blk.ind2_offset);
 		LE16_CPU(seven_c_blk.u7);
 		LE16_CPU(seven_c_blk.u8);
 
@@ -1187,53 +1215,75 @@
 
 		if (seven_c_blk.seven_c != 0x7C) { // this would mean it isn't a 7C block!
 			WARN(("Error. There isn't a 7C where I want to see 7C!\n"));
-			if (buf) free(buf);
+			freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
 			DEBUG_RET();
 			return NULL;
 		}
 
 		rec_size = seven_c_blk.rec_size;
 		num_list = seven_c_blk.item_count;
-		DEBUG_EMAIL(("b5 offset = %#x\n", seven_c_blk.b_five_offset));
 
-		_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));
+		if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, seven_c_blk.b_five_offset, &block_offset4)) {
+			DEBUG_WARN(("internal error (7c.b5 offset %#x) in reading block id %#x\n", seven_c_blk.b_five_offset, block_id));
+			freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
+			DEBUG_RET();
+			return NULL;
+		}
+		memcpy(&table_rec, block_offset4.from, sizeof(table_rec));
 		LE16_CPU(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));
-			if (buf) free(buf);
+			freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
 			DEBUG_RET();
 			return NULL;
 		}
 
-		if (table_rec.value == 0) { // this is for the 2nd index offset
-			DEBUG_INFO(("reference to second index block is zero. ERROR\n"));
-			if (buf) free(buf);
+		if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset5)) {
+			DEBUG_WARN(("internal error (7c.5b.desc offset %#x) in reading block id %#x\n", table_rec.value, block_id));
+			freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
+			DEBUG_RET();
+			return NULL;
+		}
+		num_recs = (block_offset5.to - block_offset5.from) / 6; // this will give the number of records in this block
+
+		if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, seven_c_blk.ind2_offset, &block_offset6)) {
+			DEBUG_WARN(("internal error (7c.ind2 offset %#x) in reading block id %#x\n", seven_c_blk.ind2_offset, block_id));
+			freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
 			DEBUG_RET();
 			return NULL;
 		}
-
-		_pst_getBlockOffset(buf, read_size, ind_ptr, table_rec.value, &block_offset);
-		num_recs = (block_offset.to - block_offset.from) / 6; // this will give the number of records in this block
-
-		_pst_getBlockOffset(buf, read_size, ind_ptr, seven_c_blk.ind2_offset, &block_offset);
-		ind2_ptr = block_offset.from;
-		ind2_end = block_offset.to;
+		ind2_ptr = block_offset6.from;
+		ind2_end = block_offset6.to;
+	}
+	else if (block_hdr.index_offset == 0x0101) { //type 2
+		unsigned char *buf2 = NULL;
+		int n = block_hdr.type; // count
+		int m = sizeof(table3_rec);
+		int i;
+		block_type = 3;
+		for (i=0; i<n; i++) {
+			memcpy(&table3_rec, buf+8+i*m, m);
+			LE32_CPU(table3_rec.id);
+			_pst_ff_getIDblock_dec(pf, table3_rec.id, &buf2);
+			if (buf2) free(buf2);
+			buf2 = NULL;
+		}
+		freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
+		DEBUG_RET();
+		return NULL;
 	} else {
 		WARN(("ERROR: Unknown block constant - %#X for id %#x\n", block_hdr.type, block_id));
 		DEBUG_HEXDUMPC(buf, read_size,0x10);
-		if (buf) free(buf);
+		freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
 		DEBUG_RET();
 		return NULL;
 	}
 
-	DEBUG_EMAIL(("Mallocing number of items %i\n", num_recs));
-	while (count_rec < num_recs) {
+	DEBUG_EMAIL(("Mallocing number of records %i\n", num_recs));
+	for (count_rec=0; count_rec<num_recs; count_rec++) {
 		na_ptr = (pst_num_array*) xmalloc(sizeof(pst_num_array));
 		memset(na_ptr, 0, sizeof(pst_num_array));
 		na_ptr->next = na_head;
@@ -1246,45 +1296,51 @@
 
 		DEBUG_EMAIL(("going to read %i (%#x) items\n", na_ptr->count_item, na_ptr->count_item));
 
-		fr_ptr = list_start; // init fr_ptr to the start of the list.
-		cur_list = 0;
-		while (cur_list < num_list) { //we will increase fr_ptr as we progress through index
+		fr_ptr = list_start; // initialize fr_ptr to the start of the list.
+		for (cur_list=0; cur_list<num_list; cur_list++) { //we will increase fr_ptr as we progress through index
+			unsigned char* value_pointer = NULL;	// needed for block type 2 with values larger than 4 bytes
+			int value_size = 0;
 			if (block_type == 1) {
-				memcpy(&table_rec, &(buf[fr_ptr]), sizeof(table_rec));
+				memcpy(&table_rec, 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
-				memcpy(&table2_rec, &(buf[fr_ptr]), sizeof(table2_rec));
+				memcpy(&table2_rec, fr_ptr, sizeof(table2_rec));
 				LE16_CPU(table2_rec.ref_type);
 				LE16_CPU(table2_rec.type);
 				LE16_CPU(table2_rec.ind2_off);
-				LE16_CPU(table2_rec.u1);
 
 				// 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 <= ind2_end) {
-					memcpy(&(table_rec.value), &(buf[ind2_ptr+table2_rec.ind2_off]), sizeof(table_rec.value));
+				if ((ind2_end - ind2_ptr) <= (table2_rec.ind2_off + table2_rec.size)) {
+					int n = table2_rec.size;
+					int m = sizeof(table_rec.value);
+					table_rec.value = 0;
+					if (n <= m) {
+						memcpy(&table_rec.value, ind2_ptr + table2_rec.ind2_off, n);
+					}
+					else {
+						value_pointer = ind2_ptr + table2_rec.ind2_off;
+						value_size	  = n;
+					}
 					//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,
-							 sizeof(table_rec.value)));
+					DEBUG_WARN (("Trying to read outside buffer, buffer size %#x, offset %#x, data size %#x\n",
+								read_size, ind2_end-ind2_ptr+table2_rec.ind2_off, table2_rec.size));
 				}
-
 				fr_ptr += sizeof(table2_rec);
 			} else {
 				WARN(("Missing code for block_type %i\n", block_type));
-				if (buf)	 free(buf);
+				freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
 				if (na_head) _pst_free_list(na_head);
 				DEBUG_RET();
 				return NULL;
 			}
-			cur_list++; // get ready to read next bit from list
 			DEBUG_EMAIL(("reading block %i (type=%#x, ref_type=%#x, value=%#x)\n",
 				x, table_rec.type, table_rec.ref_type, table_rec.value));
 
@@ -1329,84 +1385,68 @@
 				0x1102 - Array of Binary data
 			*/
 
-			if (table_rec.ref_type == 0x0002 || table_rec.ref_type == 0x0003 || table_rec.ref_type == 0x000b) {
-				//contains data
-				na_ptr->items[x]->data = xmalloc(sizeof(int32_t));
-				memcpy(na_ptr->items[x]->data, &(table_rec.value), sizeof(int32_t));
+			if (table_rec.ref_type == 0x0002 ||
+				table_rec.ref_type == 0x0003 ||
+				table_rec.ref_type == 0x000b) {
+				//contains 32 bits of data
 				na_ptr->items[x]->size = sizeof(int32_t);
 				na_ptr->items[x]->type = table_rec.ref_type;
+				na_ptr->items[x]->data = xmalloc(sizeof(int32_t));
+				memcpy(na_ptr->items[x]->data, &(table_rec.value), sizeof(int32_t));
 
-			} else if (table_rec.ref_type == 0x0005 || table_rec.ref_type == 0x000D
-					|| table_rec.ref_type == 0x1003 || table_rec.ref_type == 0x0014
-					|| table_rec.ref_type == 0x001E || table_rec.ref_type == 0x0102
-					|| table_rec.ref_type == 0x0040 || table_rec.ref_type == 0x101E
-					|| table_rec.ref_type == 0x0048 || table_rec.ref_type == 0x1102
-					|| table_rec.ref_type == 0x1014) {
-				//contains index_ref to data
+			} else if (table_rec.ref_type == 0x0005 ||
+					   table_rec.ref_type == 0x000d ||
+					   table_rec.ref_type == 0x0014 ||
+					   table_rec.ref_type == 0x001e ||
+					   table_rec.ref_type == 0x0040 ||
+					   table_rec.ref_type == 0x0048 ||
+					   table_rec.ref_type == 0x0102 ||
+					   table_rec.ref_type == 0x1003 ||
+					   table_rec.ref_type == 0x1014 ||
+					   table_rec.ref_type == 0x101e ||
+					   table_rec.ref_type == 0x1102) {
+				//contains index reference to data
 				LE32_CPU(table_rec.value);
-				if ((table_rec.value & 0x0000000F) == 0xF) {
-					// if value ends in 'F' then this should be an id2 value
-					DEBUG_EMAIL(("Found id2 [%#x] value. Will follow it\n", table_rec.value));
-					if ((na_ptr->items[x]->size = _pst_ff_getID2block(pf, table_rec.value, i2_head,
-											  &(na_ptr->items[x]->data)))==0) {
-						DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n", table_rec.value));
+				if (value_pointer) {
+					// in a type 2 block, with a value that is more than 4 bytes
+					// directly stored in this block.
+					na_ptr->items[x]->size = value_size;
+					na_ptr->items[x]->type = table_rec.ref_type;
+					na_ptr->items[x]->data = xmalloc(value_size);
+					memcpy(na_ptr->items[x]->data, value_pointer, value_size);
+				}
+				else if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset7)) {
+					if (table_rec.value) {
+						DEBUG_WARN(("failed to get block offset for table_rec.value of %#x\n", table_rec.value));
+					}
+					na_ptr->count_item --; //we will be skipping a row
+					continue;
+				}
+				else {
+					value_size = block_offset7.to - block_offset7.from;
+					na_ptr->items[x]->size = value_size;
+					na_ptr->items[x]->type = table_rec.ref_type;
+					na_ptr->items[x]->data = xmalloc(value_size+1);
+					memcpy(na_ptr->items[x]->data, block_offset7.from, value_size);
+					na_ptr->items[x]->data[value_size] = '\0';  // it might be a string, null terminate it.
+				}
+				if (table_rec.ref_type == 0xd) {
+					// there is still more to do for the type of 0xD
+					type_d_rec = (struct _type_d_rec*) na_ptr->items[x]->data;
+					LE32_CPU(type_d_rec->id);
+					if ((na_ptr->items[x]->size = _pst_ff_getID2block(pf, type_d_rec->id, i2_head, &(na_ptr->items[x]->data)))==0){
+						DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n",
+						  type_d_rec->id));
+						free(na_ptr->items[x]->data);
 						na_ptr->items[x]->size = 0;
 						na_ptr->items[x]->data = NULL;
-						na_ptr->items[x]->type = table_rec.value;
-					}
-				} else if (table_rec.value != 0) {
-					if ((table_rec.value >> 4)+ind_ptr > read_size) {
-						// check that we will not be outside the buffer we have read
-						DEBUG_WARN(("table_rec.value [%#x] is outside of block [%#x]\n", table_rec.value, read_size));
-						na_ptr->count_item --;
-						continue;
-					}
-					if (_pst_getBlockOffset(buf, read_size, ind_ptr, table_rec.value, &block_offset)) {
-						DEBUG_WARN(("failed to get block offset for table_rec.value of %#x\n", table_rec.value));
-						na_ptr->count_item --; //we will be skipping a row
-						continue;
-					}
-					t_ptr = block_offset.from;
-					if (t_ptr <= block_offset.to) {
-						na_ptr->items[x]->size = size = block_offset.to - t_ptr;
-					} else {
-						DEBUG_WARN(("I don't want to malloc less than zero sized block. from=%#x, to=%#x."
-							"Will change to 1 byte\n", block_offset.from, block_offset.to));
-						na_ptr->items[x]->size = size = 0; // the malloc statement will add one to this
+						na_ptr->items[x]->type = type_d_rec->id;
 					}
-
-					// plus one for good luck (and strings) we will null terminate all reads
-					na_ptr->items[x]->data = (unsigned char*) xmalloc(size+1);
-					memcpy(na_ptr->items[x]->data, &(buf[t_ptr]), size);
-					na_ptr->items[x]->data[size] = '\0'; // null terminate buffer
-
-					if (table_rec.ref_type == 0xd) {
-						// there is still more to do for the type of 0xD
-						type_d_rec = (struct _type_d_rec*) na_ptr->items[x]->data;
-						LE32_CPU(type_d_rec->id);
-						if ((na_ptr->items[x]->size = _pst_ff_getID2block(pf, type_d_rec->id, i2_head, &(na_ptr->items[x]->data)))==0){
-							DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n",
-							  type_d_rec->id));
-							na_ptr->items[x]->size = 0;
-							na_ptr->items[x]->data = NULL;
-							na_ptr->items[x]->type = type_d_rec->id;
-						}
-					}
-				} else {
-					DEBUG_EMAIL(("Ignoring 0 value in offset\n"));
-					if (na_ptr->items[x]->data) free (na_ptr->items[x]->data);
-					na_ptr->items[x]->data = NULL;
-					free(na_ptr->items[x]);
-					na_ptr->count_item--; // remove this item from the destination list
-					continue;
 				}
-				if (na_ptr->items[x]->type == 0)
-					//it can be used to convey information
-					// to later functions
-					na_ptr->items[x]->type = table_rec.ref_type;
+				if (na_ptr->items[x]->type == 0) na_ptr->items[x]->type = table_rec.ref_type;
 			} else {
 				WARN(("ERROR Unknown ref_type %#x\n", table_rec.ref_type));
-				if (buf)	 free(buf);
+				freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
 				if (na_head) _pst_free_list(na_head);
 				DEBUG_RET();
 				return NULL;
@@ -1415,9 +1455,8 @@
 		}
 		DEBUG_EMAIL(("increasing ind2_ptr by %i [%#x] bytes. Was %#x, Now %#x\n", rec_size, rec_size, ind2_ptr, ind2_ptr+rec_size));
 		ind2_ptr += rec_size;
-		count_rec++;
 	}
-	if (buf) free(buf);
+	freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
 	DEBUG_RET();
 	return na_head;
 }
@@ -2998,6 +3037,7 @@
 					DEBUG_EMAIL(("%s\n", item->journal->type));
 					break;
 				default:
+					DEBUG_EMAIL(("unknown type %#x\n", list->items[x]->id));
 						/* Reference Types
 
 					   2 - 0x0002 - Signed 16bit value
@@ -3431,11 +3471,50 @@
 }
 
 
+/**
+  * The offset might be zero, in which case we have no data, so return a pair of null pointers.
+  * Or, the offset might end in 0xf, so it is an id2 pointer, in which case we read the id2 block.
+  * Otherwise, the offset>>4 is an index into the table of offsets in the buffer.
+*/
+int32_t _pst_getBlockOffsetPointer(pst_file *pf, pst_index2_ll *i2_head, unsigned char *buf, int32_t read_size, int32_t i_offset, int32_t offset, pst_block_offset_pointer *p) {
+	int32_t size;
+	pst_block_offset block_offset;
+	DEBUG_ENT("_pst_getBlockOffsetPointer");
+	if (p->needfree) free(p->from);
+	p->from = NULL;
+	p->needfree = 0;
+	if (!offset) {
+		p->from = p->to = NULL;
+	}
+	else if ((offset & 0xf) == 0xf) {
+		DEBUG_WARN(("Found id2 %#x value. Will follow it\n", offset));
+		size = _pst_ff_getID2block(pf, offset, i2_head, &(p->from));
+		if (size) {
+			p->to = p->from + size;
+			p->needfree = 1;
+		}
+		else {
+			p->from = p->to = NULL;
+		}
+	}
+	else if (_pst_getBlockOffset(buf, read_size, i_offset, offset, &block_offset)) {
+		p->from = p->to = NULL;
+	}
+	else {
+		p->from = buf + block_offset.from;
+		p->to	= buf + block_offset.to;
+	}
+	DEBUG_RET();
+	return (p->from) ? 0 : 1;
+}
+
+
 int32_t _pst_getBlockOffset(unsigned char *buf, int32_t read_size, int32_t i_offset, int32_t offset, pst_block_offset *p) {
-	int32_t of1 = offset>>4;
+	int32_t low = offset & 0xf;
+	int32_t of1 = offset >> 4;
 	DEBUG_ENT("_pst_getBlockOffset");
-	if (!p || !buf || (i_offset == 0) || (i_offset+2+of1+sizeof(*p) > read_size)) {
-		DEBUG_WARN(("p is NULL or buf is NULL or offset is 0 (%p, %p, %#x, %i, %i)\n", p, buf, offset, read_size, i_offset));
+	if (!p || !buf || !i_offset || low || (i_offset+2+of1+sizeof(*p) > read_size)) {
+		DEBUG_WARN(("p is NULL or buf is NULL or offset is 0 or offset has low bits or beyond read size (%p, %p, %#x, %i, %i)\n", p, buf, offset, read_size, i_offset));
 		DEBUG_RET();
 		return -1;
 	}
@@ -3443,13 +3522,17 @@
 	memcpy(&(p->to), &(buf[(i_offset+2)+of1+sizeof(p->from)]), sizeof(p->to));
 	LE16_CPU(p->from);
 	LE16_CPU(p->to);
-	DEBUG_WARN(("get block offset finds from=%i(%#x), to=%i(%#x)", p->from, p->from, p->to, p->to));
+	DEBUG_WARN(("get block offset finds from=%i(%#x), to=%i(%#x)\n", p->from, p->from, p->to, p->to));
+	if (p->from > p->to) {
+		DEBUG_WARN(("get block offset from > to"));
+		return -1;
+	}
 	DEBUG_RET();
 	return 0;
 }
 
 
-pst_index_ll * _pst_getID(pst_file* pf, u_int32_t id) {
+pst_index_ll* _pst_getID(pst_file* pf, u_int32_t id) {
 	pst_index_ll *ptr = NULL;
 	DEBUG_ENT("_pst_getID");
 	if (id == 0) {
@@ -3457,21 +3540,17 @@
 		return NULL;
 	}
 
-	/*	if (id & 0x3) { // if either of the last two bits on the id are set
-	  DEBUG_INDEX(("ODD_INDEX (not even) is this a pointer to a table?\n"));
-	  }*/
-	// Dave: I don't think I should do this. next bit. I really think it doesn't work
-	// it isn't based on sound principles either.
-	// update: seems that the last two sig bits are flags. u tell me!
-	id &= 0xFFFFFFFE; // remove least sig. bit. seems that it might work if I do this
+	//if (id & 1) DEBUG_INDEX(("have odd id bit %#x\n", id));
+	//if (id & 2) DEBUG_INDEX(("have two id bit %#x\n", id));
+	id &= 0xFFFFFFFE;
 
 	DEBUG_INDEX(("Trying to find %#x\n", id));
 	if (!ptr) ptr = pf->i_head;
 	while (ptr && (ptr->id != id)) {
 		ptr = ptr->next;
 	}
-	if (ptr) {DEBUG_INDEX(("Found Value %#x\n", ptr->id));}
-	else	 {DEBUG_INDEX(("ERROR: Value not found\n"));  }
+	if (ptr) {DEBUG_INDEX(("Found Value %#x\n", id));            }
+	else	 {DEBUG_INDEX(("ERROR: Value %#x not found\n", id)); }
 	DEBUG_RET();
 	return ptr;
 }
@@ -3496,7 +3575,15 @@
 }
 
 
-pst_desc_ll * _pst_getDptr(pst_file *pf, u_int32_t id) {
+/**
+ * find the id in the descriptor tree rooted at pf->d_head
+ *
+ * @param pf	global pst file pointer
+ * @param id	the id we are looking for
+ *
+ * @return pointer to the pst_desc_ll node in the descriptor tree
+*/
+pst_desc_ll* _pst_getDptr(pst_file *pf, u_int32_t id) {
 	pst_desc_ll *ptr = pf->d_head;
 	DEBUG_ENT("_pst_getDptr");
 	while (ptr && (ptr->id != id)) {
@@ -3742,16 +3829,19 @@
 size_t _pst_ff_getIDblock_dec(pst_file *pf, u_int32_t id, unsigned char **b) {
 	size_t r;
 	DEBUG_ENT("_pst_ff_getIDblock_dec");
+	DEBUG_INDEX(("for id %#x\n", id));
 	r = _pst_ff_getIDblock(pf, id, b);
-	if (pf->encryption) _pst_decrypt(*b, r, pf->encryption);
 	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_RET();
 	return r;
 }
 
 
-/** the get ID function for the default file format that I am working with
-	ie the one in the PST files */
 size_t _pst_ff_getIDblock(pst_file *pf, u_int32_t id, unsigned char** b) {
 	pst_index_ll *rec;
 	size_t rsize = 0;//, re_size=0;