Index: trunk/include/regfi.h
===================================================================
--- trunk/include/regfi.h	(revision 115)
+++ trunk/include/regfi.h	(revision 116)
@@ -72,38 +72,42 @@
 #define REG_KEY                        0x7FFFFFFF
 
-#define REGF_BLOCKSIZE		0x1000
-#define REGF_ALLOC_BLOCK	0x1000  /* Minimum allocation unit for hbins */
-#define REGF_MAX_DEPTH		512
+#define REGF_BLOCKSIZE		   0x1000
+#define REGF_ALLOC_BLOCK	   0x1000 /* Minimum allocation unit for HBINs */
+#define REGF_MAX_DEPTH		   512
 
 /* header sizes for various records */
-
-#define REGF_MAGIC_SIZE		4
-#define HBIN_MAGIC_SIZE		4
-#define HBIN_HEADER_REC_SIZE	0x20
-#define REC_HDR_SIZE		2
-
-#define REGF_OFFSET_NONE	0xffffffff
-#define REGFI_NK_MIN_LENGTH     0x4C
-#define REGFI_VK_MIN_LENGTH     0x14
-#define REGFI_SK_MIN_LENGTH     0x14
-#define REGFI_HASH_LIST_MIN_LENGTH     0x4
+#define REGF_MAGIC_SIZE		   4
+#define HBIN_MAGIC_SIZE		   4
+#define HBIN_HEADER_REC_SIZE	   0x20
+#define REC_HDR_SIZE		   2
+
+#define REGF_OFFSET_NONE           0xffffffff
+#define REGFI_NK_MIN_LENGTH        0x4C
+#define REGFI_VK_MIN_LENGTH        0x14
+#define REGFI_SK_MIN_LENGTH        0x14
+#define REGFI_HASH_LIST_MIN_LENGTH 0x4
+
+/* Constants used for validation */
+ /* Minimum time is Jan 1, 1990 00:00:00 */
+#define REGFI_MTIME_MIN_HIGH       0x01B41E6D
+#define REGFI_MTIME_MIN_LOW        0x26F98000
+ /* Maximum time is Jan 1, 2290 00:00:00
+  * (We hope no one is using Windows by then...) 
+  */
+#define REGFI_MTIME_MAX_HIGH       0x03047543
+#define REGFI_MTIME_MAX_LOW        0xC80A4000
+
 
 /* Flags for the vk records */
-
-#define VK_FLAG_NAME_PRESENT	0x0001
-#define VK_DATA_IN_OFFSET	0x80000000
-#define VK_MAX_DATA_LENGTH      1024*1024
-
-/* NK record macros */
-
-#define NK_TYPE_LINKKEY		0x0010
-#define NK_TYPE_NORMALKEY	0x0020
-#define NK_TYPE_ROOTKEY		0x002c
-  /* TODO: Unknown type that shows up in Vista registries */
-#define NK_TYPE_UNKNOWN1         0x1020 
-
-#define HBIN_STORE_REF(x, y) { x->hbin = y; y->ref_count++ };
-/* if the count == 0; we can clean up */
-#define HBIN_REMOVE_REF(x, y){ x->hbin = NULL; y->ref_count-- };
+#define VK_FLAG_NAME_PRESENT	   0x0001
+#define VK_DATA_IN_OFFSET	   0x80000000
+#define VK_MAX_DATA_LENGTH         1024*1024
+
+/* NK record types */
+#define NK_TYPE_LINKKEY		   0x0010
+#define NK_TYPE_NORMALKEY	   0x0020
+#define NK_TYPE_ROOTKEY		   0x002c
+ /* TODO: Unknown type that shows up in Vista registries */
+#define NK_TYPE_UNKNOWN1           0x1020 
 
 
Index: trunk/lib/range_list.c
===================================================================
--- trunk/lib/range_list.c	(revision 115)
+++ trunk/lib/range_list.c	(revision 116)
@@ -18,5 +18,4 @@
  */
 
-#include <stdio.h>
 #include <math.h>
 #include "../include/range_list.h"
@@ -29,4 +28,5 @@
 
 #if 0
+#include <stdio.h>
 static void range_list_print(const range_list* rl)
 {
Index: trunk/lib/regfi.c
===================================================================
--- trunk/lib/regfi.c	(revision 115)
+++ trunk/lib/regfi.c	(revision 116)
@@ -442,5 +442,4 @@
 
 /*******************************************************************
- TODO: not currently validating against max_size
  *******************************************************************/
 REGF_HASH_LIST* regfi_load_hashlist(REGF_FILE* file, uint32 offset, 
@@ -463,4 +462,10 @@
 
   ret_val->offset = offset;
+  if(cell_length > max_size)
+  {
+    if(strict)
+      return NULL;
+    cell_length = max_size & 0xFFFFFFF8;
+  }
   ret_val->cell_size = cell_length;
 
@@ -491,8 +496,8 @@
       return NULL;
     }
-    /* TODO: Not sure which should be authoritative, the number from the 
-     *       NK record, or the number in the hash list.  Go with the larger
-     *       of the two to ensure all keys are found.  Note the length checks
-     *       on the cell later ensure that there won't be any critical errors.
+    /* XXX: Not sure which should be authoritative, the number from the 
+     *      NK record, or the number in the hash list.  Go with the larger
+     *      of the two to ensure all keys are found.  Note the length checks
+     *      on the cell later ensure that there won't be any critical errors.
      */
     if(num_keys < ret_val->num_keys)
@@ -565,6 +570,6 @@
 
   ret_val->offset = offset;
-  /* TODO: is there a way to be more conservative (shorter) with 
-   *       cell length when cell is unallocated?
+  /* XXX: Is there a way to be more conservative (shorter) with 
+   *      cell length when cell is unallocated?
    */
   ret_val->cell_size = cell_length;
@@ -582,5 +587,5 @@
   ret_val->magic[1] = sk_header[1];
 
-  /* TODO: can additional validation be added here? */
+  /* XXX: Can additional validation be added here? */
   ret_val->unknown_tag = SVAL(sk_header, 0x2);
   ret_val->prev_sk_off = IVAL(sk_header, 0x4);
@@ -595,5 +600,5 @@
   }
 
-  /* TODO: need to get rid of this, but currently the security descriptor
+  /* XXX: need to get rid of this, but currently the security descriptor
    * code depends on the ps structure.
    */
@@ -678,5 +683,5 @@
 
 /******************************************************************************
- * If !strict, the list may contain NULLs and VK records may point to NULL data.
+ * If !strict, the list may contain NULLs, VK records may point to NULL.
  ******************************************************************************/
 REGF_VK_REC** regfi_load_valuelist(REGF_FILE* file, uint32 offset, 
@@ -686,14 +691,17 @@
   REGF_VK_REC** ret_val;
   REGF_HBIN* hbin;
-  uint32 i, vk_offset, vk_max_length;
+  uint32 i, vk_offset, vk_max_length, usable_num_values;
   uint32* voffsets;
 
   if((num_values+1) * sizeof(uint32) > max_size)
-    return NULL;
-
-  /* TODO: For now, everything strict seems to make sense on this call.
-   *       Maybe remove the parameter or use it for other things.
-   */
-  voffsets = regfi_parse_valuelist(file, offset, num_values, true);
+  {
+    if(strict)
+      return NULL;
+    usable_num_values = max_size/sizeof(uint32) - sizeof(uint32);
+  }
+  else
+    usable_num_values = num_values;
+
+  voffsets = regfi_parse_valuelist(file, offset, usable_num_values, strict);
   if(voffsets == NULL)
     return NULL;
@@ -706,5 +714,5 @@
   }
   
-  for(i=0; i < num_values; i++)
+  for(i=0; i < usable_num_values; i++)
   {
     hbin = regfi_lookup_hbin(file, voffsets[i]);
@@ -739,6 +747,6 @@
 
 /*******************************************************************
- * TODO: Need to add full key caching using a 
- *       custom cache structure.
+ * XXX: Need to add full key caching using a 
+ *      custom cache structure.
  *******************************************************************/
 REGF_NK_REC* regfi_load_key(REGF_FILE* file, uint32 offset, bool strict)
@@ -800,6 +808,5 @@
       if(strict)
       {
-	free(nk);
-	/* TODO: need convenient way to free nk->values deeply in all cases. */
+	regfi_key_free(nk);
 	return NULL;
       }
@@ -815,5 +822,5 @@
       if(nk->subkeys == NULL)
       {
-	/* TODO: temporary hack to get around 'ri' records */
+	/* XXX: Temporary hack to get around 'ri' records */
 	nk->num_subkeys = 0;
       }
@@ -1031,6 +1038,11 @@
   }
 
-  /* TODO: come up with a better secret. */
-  ret_val->sk_recs = lru_cache_create(127, 0xDEADBEEF, true);
+  /* This secret isn't very secret, but we don't need a good one.  This 
+   * secret is just designed to prevent someone from trying to blow our
+   * caching and make things slow.
+   */
+  ret_val->sk_recs = lru_cache_create(127, 0x15DEAD05^time(NULL)
+				           ^(getpid()<<16)^(getppid()<<8),
+				      true);
 
   ret_val->f = fh;
@@ -1367,5 +1379,5 @@
 
 /*******************************************************************
- * TODO: add way to return more detailed error information.
+ * XXX: Add way to return more detailed error information.
  *******************************************************************/
 REGF_FILE* regfi_parse_regf(int fd, bool strict)
@@ -1441,6 +1453,5 @@
  * along with it's associated cells.
  *******************************************************************/
-/* TODO: Need a way to return types of errors.  Also need to free 
- *       the hbin/ps when an error occurs.
+/* XXX: Need a way to return types of errors.
  */
 REGF_HBIN* regfi_parse_hbin(REGF_FILE* file, uint32 offset, bool strict)
@@ -1485,6 +1496,7 @@
    * the end of the file. 
    */
-  /* TODO: This may need to be relaxed for dealing with 
-   *       partial or corrupt files. */
+  /* XXX: This may need to be relaxed for dealing with 
+   *      partial or corrupt files. 
+   */
   if((offset + hbin->block_size > file->file_length)
      || (hbin->block_size & 0xFFFFF000) != hbin->block_size)
@@ -1515,5 +1527,7 @@
   if((nk_header[0x0] != 'n') || (nk_header[0x1] != 'k'))
   {
-    /* TODO: deal with subkey-lists that reference other subkey-lists. */
+    /* XXX: Deal with subkey-lists that reference other subkey-lists
+     *      (e.g. 'ri' records). 
+     */
     return NULL;
   }
@@ -1549,5 +1563,15 @@
   ret_val->mtime.low = IVAL(nk_header, 0x4);
   ret_val->mtime.high = IVAL(nk_header, 0x8);
-  
+  /* If the key is unallocated and the MTIME is earlier than Jan 1, 1990
+   * or later than Jan 1, 2290, we consider this a bad key.  This helps
+   * weed out some false positives during deleted data recovery.
+   */
+  if(unalloc
+     && ((ret_val->mtime.high < REGFI_MTIME_MIN_HIGH 
+	  && ret_val->mtime.low < REGFI_MTIME_MIN_LOW)
+	 || (ret_val->mtime.high > REGFI_MTIME_MAX_HIGH 
+	     && ret_val->mtime.low > REGFI_MTIME_MAX_LOW)))
+    return NULL;
+
   ret_val->unknown1 = IVAL(nk_header, 0xC);
   ret_val->parent_off = IVAL(nk_header, 0x10);
@@ -1559,5 +1583,5 @@
   ret_val->values_off = IVAL(nk_header, 0x28);
   ret_val->sk_off = IVAL(nk_header, 0x2C);
-  /* TODO: currently we do nothing with class names.  Need to investigate. */
+  /* XXX: currently we do nothing with class names.  Need to investigate. */
   ret_val->classname_off = IVAL(nk_header, 0x30);
 
@@ -1758,7 +1782,7 @@
     if(cell_length - 4 < length)
     {
-      /* TODO: This strict condition has been triggered in multiple registries.
-       *       Not sure the cause, but the data length values are very large,
-       *       such as 53392.
+      /* XXX: This strict condition has been triggered in multiple registries.
+       *      Not sure the cause, but the data length values are very large,
+       *      such as 53392.
        */
       if(strict)
@@ -1768,6 +1792,6 @@
     }
 
-    /* TODO: There is currently no check to ensure the data 
-     *       cell doesn't cross HBIN boundary.
+    /* XXX: There is currently no check to ensure the data 
+     *      cell doesn't cross HBIN boundary.
      */
 
@@ -1816,5 +1840,5 @@
       
       if((cell_len == 0) || ((cell_len & 0xFFFFFFF8) != cell_len))
-	/* TODO: should report an error here. */
+	/* XXX: should report an error here. */
 	break;
       
Index: trunk/src/common.c
===================================================================
--- trunk/src/common.c	(revision 115)
+++ trunk/src/common.c	(revision 116)
@@ -29,5 +29,5 @@
 const char* common_special_chars = ",\"\\";
 
-#define REGLOOKUP_VERSION "1.0.0"
+#define REGLOOKUP_VERSION "0.9.0"
 
 
@@ -357,4 +357,8 @@
   /* XXX: Dont know what to do with these yet, just print as binary... */
   default:
+    /* XXX: It would be really nice if this message somehow included the
+     *      name of the current value we're having trouble with, since
+     *      stderr/stdout don't always sync nicely.
+     */
     fprintf(stderr, "WARNING: Unrecognized registry data type (0x%.8X); quoting as binary.\n", type);
     
Index: trunk/src/reglookup-recover.c
===================================================================
--- trunk/src/reglookup-recover.c	(revision 115)
+++ trunk/src/reglookup-recover.c	(revision 116)
@@ -148,5 +148,9 @@
    *   http://msdn2.microsoft.com/en-us/library/ms724872.aspx
    */
-  /* TODO: should probably do something different here for this tool.*/
+  /* XXX: Should probably do something different here for this tool.
+   *      Also, It would be really nice if this message somehow included the
+   *      name of the current value we're having trouble with, since
+   *      stderr/stdout don't always sync nicely.
+   */
   if(size > VK_MAX_DATA_LENGTH)
   {
@@ -277,7 +281,7 @@
  * Paths returned must be free()d.
  */
-/* TODO: This is not terribly efficient, as it may reparse many keys 
- *       repeatedly.  Should try to add caching.  Also, piecing the path 
- *       together is slow and redundant.
+/* XXX: This is not terribly efficient, as it may reparse many keys 
+ *      repeatedly.  Should try to add caching.  Also, piecing the path 
+ *      together is slow and redundant.
  */
 char* getParentPath(REGF_FILE* f, REGF_NK_REC* nk)
@@ -425,10 +429,13 @@
   rm_idx = range_list_find(rl, offset);
   if(rm_idx < 0)
+  {
+    fprintf(stderr, "DEBUG: removeRange: rm_idx < 0; (%d)\n", rm_idx);
     return false;
+  }
 
   cur_elem = range_list_get(rl, rm_idx);
   if(cur_elem == NULL)
   {
-    printf("removeRange: cur_elem == NULL.  rm_idx=%d\n", rm_idx);
+    fprintf(stderr, "DEBUG: removeRange: cur_elem == NULL.  rm_idx=%d\n", rm_idx);
     return false;
   }
@@ -438,8 +445,16 @@
     if(!range_list_split_element(rl, rm_idx, offset))
     {
-      printf("removeRange: first split failed\n");
+      fprintf(stderr, "DEBUG: removeRange: first split failed\n");
       return false;
     }
     rm_idx++;
+    cur_elem = range_list_get(rl, rm_idx);
+    if(cur_elem == NULL)
+    {
+      fprintf(stderr, 
+	      "DEBUG: removeRange: cur_elem == NULL after first split.  rm_idx=%d\n",
+	      rm_idx);
+      return false;
+    }
   }
   
@@ -448,5 +463,5 @@
     if(!range_list_split_element(rl, rm_idx, offset+length))
     {
-      printf("removeRange: second split failed\n");
+      fprintf(stderr, "DEBUG: removeRange: second split failed\n");
       return false;
     }
@@ -455,5 +470,5 @@
   if(!range_list_remove(rl, rm_idx))
   {
-    printf("removeRange: remove failed\n");
+    fprintf(stderr, "DEBUG: removeRange: remove failed\n");
     return false;
   }
@@ -487,18 +502,14 @@
 	  return 20;
 	}
-	
-	if(removeRange(unalloc_cells, key->offset, key->cell_size))
-	{
-	  /* TODO: This ugly hack is needed because unalloc_cells is changing
-	   *       underneath us when we find things.  Need a better approach
-	   *       so we can parse things single-pass.
-	   */
-	  i=0;
-	  break;
-	}
-	else
-	  return 30;
+	j+=key->cell_size-8;
       }
     }
+  }
+
+  for(i=0; i<range_list_size(unalloc_keys); i++)
+  {
+    cur_elem = range_list_get(unalloc_keys, i);
+    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
+      return 30;
   }
 
@@ -743,5 +754,5 @@
   REGF_NK_REC* tmp_key;
   REGF_VK_REC* tmp_value;
-  uint32 argi, arge, i, j, k, ret, num_unalloc_keys;
+  uint32 argi, arge, i, j, ret, num_unalloc_keys;
   /* uint32 test_offset;*/
   
Index: trunk/src/reglookup.c
===================================================================
--- trunk/src/reglookup.c	(revision 115)
+++ trunk/src/reglookup.c	(revision 116)
@@ -46,6 +46,6 @@
 
 
-/* TODO: a hack to share some functions with reglookup-recover.c.
- *       Should move these into a properly library at some point.
+/* XXX: A hack to share some functions with reglookup-recover.c.
+ *      Should move these into a properly library at some point.
  */
 #include "common.c"
