Index: trunk/lib/regfi.c
===================================================================
--- trunk/lib/regfi.c	(revision 104)
+++ trunk/lib/regfi.c	(revision 105)
@@ -450,14 +450,4 @@
     block_off = REGF_BLOCKSIZE;
     do {
-      /* cleanup before the next round */
-      if ( hbin )
-      {
-	if(hbin->ps.is_dynamic)
-	  SAFE_FREE(hbin->ps.data_p);
-	hbin->ps.is_dynamic = false;
-	hbin->ps.buffer_size = 0;
-	hbin->ps.data_offset = 0;
-      }
-
       hbin = regfi_parse_hbin(file, block_off, true, false);
 
@@ -478,7 +468,9 @@
 
 /*******************************************************************
+ TODO: not currently validating against max_size
  *******************************************************************/
 REGF_HASH_LIST* regfi_load_hashlist(REGF_FILE* file, uint32 offset, 
-				    uint32 num_keys, bool strict)
+				    uint32 num_keys, uint32 max_size, 
+				    bool strict)
 {
   REGF_HASH_LIST* ret_val;
@@ -657,8 +649,9 @@
 
 /******************************************************************************
- *
+ TODO: not currently validating against max_size.
  ******************************************************************************/
 REGF_VK_REC** regfi_load_valuelist(REGF_FILE* file, uint32 offset, 
-				   uint32 num_values)
+				   uint32 num_values, uint32 max_size, 
+				   bool strict)
 {
   REGF_VK_REC** ret_val;
@@ -748,96 +741,113 @@
 /*******************************************************************
  *******************************************************************/
-static REGF_NK_REC* hbin_prs_key(REGF_FILE *file, REGF_HBIN *hbin)
-{
+REGF_NK_REC* regfi_load_key(REGF_FILE *file, uint32 offset, bool strict)
+{
+  REGF_HBIN* hbin;
   REGF_HBIN* sub_hbin;
   REGF_NK_REC* nk;
-  uint32 nk_cell_offset;
-  uint32 nk_max_length;
-  uint32 sk_max_length;
-  int depth = 0;
-
-  depth++;
+  uint32 max_length, off;
+
+  hbin = lookup_hbin_block(file, offset-REGF_BLOCKSIZE);
+  if (hbin == NULL) 
+    return NULL;
 
   /* get the initial nk record */
-  nk_cell_offset = hbin->file_off + hbin->ps.data_offset - sizeof(uint32);
-  nk_max_length = hbin->block_size - hbin->ps.data_offset + sizeof(uint32);
-  if ((nk = regfi_parse_nk(file, nk_cell_offset, nk_max_length, true)) == NULL)
-  {
-fprintf(stderr, "DEBUG: regfi_parse_nk returned NULL!\n");
-    return NULL;
-  }
+  max_length = hbin->block_size + hbin->file_off - offset;
+  if ((nk = regfi_parse_nk(file, offset, max_length, true)) == NULL)
+    return NULL;
 
   /* fill in values */
-  if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) 
+  if(nk->num_values && (nk->values_off!=REGF_OFFSET_NONE)) 
   {
     sub_hbin = hbin;
-    if ( !hbin_contains_offset( hbin, nk->values_off ) ) 
-    {
-      sub_hbin = lookup_hbin_block( file, nk->values_off );
-      if ( !sub_hbin ) 
+    if(!hbin_contains_offset(hbin, nk->values_off)) 
+      sub_hbin = lookup_hbin_block(file, nk->values_off);
+    
+    if(sub_hbin == NULL)
+    {
+      if(strict)
       {
-	/*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n", 
-	  nk->values_off));*/
+	free(nk);
 	return NULL;
       }
-    }
-    
-    nk->values = regfi_load_valuelist(file, nk->values_off+REGF_BLOCKSIZE,
-				      nk->num_values);
-    if(nk->values == NULL)
-    {
-      printf("values borked!\n");
-      return NULL;
-    }
-  }
-		
-  /* now get subkeys */
-  if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) 
-  {
-    sub_hbin = hbin;
-    if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) 
-    {
-      sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
-      if ( !sub_hbin ) 
+      else
+	nk->values = NULL;
+    }
+    else
+    {
+      off = nk->values_off + REGF_BLOCKSIZE;
+      max_length = sub_hbin->block_size + sub_hbin->file_off - off;
+      nk->values = regfi_load_valuelist(file, off, nk->num_values, max_length, 
+					true);
+      if(strict && nk->values == NULL)
       {
-	/*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n", 
-	  nk->subkeys_off));*/
+	free(nk);
 	return NULL;
       }
     }
-
-    nk->subkeys = regfi_load_hashlist(file, nk->subkeys_off + REGF_BLOCKSIZE,
-				      nk->num_subkeys, true);
-    if (nk->subkeys == NULL)
-    {
-      /* TODO: temporary hack to get around 'ri' records */
-      nk->num_subkeys = 0;
-    }
-  }
-
-  /* get the security descriptor.  First look if we have already parsed it */
-  if ((nk->sk_off!=REGF_OFFSET_NONE)
-      && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
+  }
+
+  /* now get subkeys */
+  if(nk->num_subkeys && (nk->subkeys_off != REGF_OFFSET_NONE)) 
   {
     sub_hbin = hbin;
-    if (!hbin_contains_offset(hbin, nk->sk_off))
-    {
-      sub_hbin = lookup_hbin_block( file, nk->sk_off );
-      if ( !sub_hbin ) 
+    if(!hbin_contains_offset(hbin, nk->subkeys_off))
+      sub_hbin = lookup_hbin_block(file, nk->subkeys_off);
+
+    if (sub_hbin == NULL) 
+    {
+      if(strict)
       {
 	free(nk);
-	/*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n", 
-	  nk->subkeys_off));*/
+	/* TODO: need convenient way to free nk->values deeply in all cases. */
 	return NULL;
       }
-    }
+      else
+	nk->subkeys = NULL;
+    }
+    else
+    {
+      off = nk->subkeys_off + REGF_BLOCKSIZE;
+      max_length = sub_hbin->block_size + sub_hbin->file_off - off;
+      nk->subkeys = regfi_load_hashlist(file, off, nk->num_subkeys, 
+					max_length, true);
+      if(nk->subkeys == NULL)
+      {
+	/* TODO: temporary hack to get around 'ri' records */
+	nk->num_subkeys = 0;
+      }
+    }
+  }
+
+  /* get the security descriptor.  First look if we have already parsed it */
+  if((nk->sk_off!=REGF_OFFSET_NONE)
+     && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
+  {
+    sub_hbin = hbin;
+    if(!hbin_contains_offset(hbin, nk->sk_off))
+      sub_hbin = lookup_hbin_block(file, nk->sk_off);
+
+    if(sub_hbin == NULL)
+    {
+      free(nk);
+      /* TODO: need convenient way to free nk->values and nk->subkeys deeply 
+       *       in all cases. 
+       */
+      return NULL;
+    }
+
+    off = nk->sk_off + REGF_BLOCKSIZE;
+    max_length = sub_hbin->block_size + sub_hbin->file_off - off;
+    nk->sec_desc = regfi_parse_sk(file, off, max_length, true);
+    if(strict && nk->sec_desc == NULL)
+    {
+      free(nk);
+      /* TODO: need convenient way to free nk->values and nk->subkeys deeply 
+       *       in all cases. 
+       */
+      return NULL;
+    }
+    nk->sec_desc->sk_off = nk->sk_off;
     
-    sk_max_length = sub_hbin->block_size - (nk->sk_off - sub_hbin->first_hbin_off);
-    nk->sec_desc = regfi_parse_sk(file, nk->sk_off + REGF_BLOCKSIZE, 
-				  sk_max_length, true);
-    if(nk->sec_desc == NULL)
-      return NULL;
-    nk->sec_desc->sk_off = nk->sk_off;
-			
     /* add to the list of security descriptors (ref_count has been read from the files) */
     /* XXX: this kind of caching needs to be re-evaluated */
@@ -976,9 +986,5 @@
 			  hbin->block_size-HBIN_HEADER_REC_SIZE, &root_offset))
     {
-      if(!prs_set_offset(&hbin->ps, root_offset + 4 
-			 - hbin->first_hbin_off - REGF_BLOCKSIZE))
-	return NULL;
-      
-      nk = hbin_prs_key(file, hbin);
+      nk = regfi_load_key(file, root_offset, true);
       break;
     }
@@ -1223,6 +1229,4 @@
 const REGF_NK_REC* regfi_iterator_cur_subkey(REGFI_ITERATOR* i)
 {
-  REGF_NK_REC* subkey;
-  REGF_HBIN* hbin;
   uint32 nk_offset;
 
@@ -1233,23 +1237,6 @@
 
   nk_offset = i->cur_key->subkeys->hashes[i->cur_subkey].nk_off;
-
-  /* find the HBIN block which should contain the nk record */
-  hbin = lookup_hbin_block(i->f, nk_offset);
-  if(!hbin)
-  {
-    /* XXX: should print out some kind of error message every time here */
-    /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n", 
-      i->cur_key->subkeys->hashes[i->cur_subkey].nk_off));*/
-    return NULL;
-  }
-  
-  if(!prs_set_offset(&hbin->ps, 
-		     HBIN_MAGIC_SIZE + nk_offset - hbin->first_hbin_off))
-    return NULL;
-		
-  if((subkey = hbin_prs_key(i->f, hbin)) == NULL)
-    return NULL;
-
-  return subkey;
+  
+  return regfi_load_key(i->f, nk_offset+REGF_BLOCKSIZE, true);
 }
 
@@ -1459,5 +1446,5 @@
   uint8 hbin_header[HBIN_HEADER_REC_SIZE];
   uint32 length, curr_off;
-  int32 cell_len;
+  uint32 cell_len;
   bool is_unalloc;
   
@@ -1506,33 +1493,12 @@
   }
 
-  /* TODO: need to get rid of this, but currently lots depends on the 
-   * ps structure. 
-   */
-  if(!prs_init(&hbin->ps, hbin->block_size, file->mem_ctx, UNMARSHALL))
-  {
-    free(hbin);
-    return NULL;
-  }
-  length = hbin->block_size;
-  if((regfi_read(file->fd, (uint8*)hbin->ps.data_p, &length) != 0) 
-     || length != hbin->block_size)
-  {
-    free(hbin);
-    return NULL;
-  }
-
-
   if(save_unalloc)
   {
-    cell_len = 0;
     curr_off = HBIN_HEADER_REC_SIZE;
-    while ( curr_off < hbin->block_size ) 
-    {
-      is_unalloc = false;
-      cell_len = IVALS(hbin->ps.data_p, curr_off);
-      if(cell_len > 0)
-	is_unalloc = true;
-      else
-	cell_len = -1*cell_len;
+    while(curr_off < hbin->block_size)
+    {
+      if(!regfi_parse_cell(file->fd, hbin->file_off+curr_off, NULL, 0,
+			   &cell_len, &is_unalloc))
+	break;
 
       if((cell_len == 0) || ((cell_len & 0xFFFFFFFC) != cell_len))
@@ -1554,10 +1520,4 @@
     }
   }
-
-  /* TODO: need to get rid of this, but currently lots depends on the 
-   * ps structure. 
-   */
-  if(!prs_set_offset(&hbin->ps, file->data_offset+HBIN_MAGIC_SIZE))
-    return NULL;
 
   return hbin;
