Index: trunk/include/regfi.h
===================================================================
--- trunk/include/regfi.h	(revision 126)
+++ trunk/include/regfi.h	(revision 127)
@@ -86,5 +86,5 @@
 #define REGFI_VK_MIN_LENGTH        0x14
 #define REGFI_SK_MIN_LENGTH        0x14
-#define REGFI_HASH_LIST_MIN_LENGTH 0x4
+#define REGFI_SUBKEY_LIST_MIN_LEN  0x4
 
 /* Constants used for validation */
@@ -138,10 +138,10 @@
 
 
-/* Hash List -- list of key offsets and hashed names for consistency */
+/* Subkey List -- list of key offsets and hashed names for consistency */
 typedef struct 
 {
   uint32 nk_off;
   uint32 hash;
-} REGF_HASH_LIST_ELEM;
+} REGF_SUBKEY_LIST_ELEM;
 
 
@@ -150,13 +150,9 @@
   uint32 offset;	/* Real offset of this record's cell in the file */
   uint32 cell_size;	 /* ((start_offset - end_offset) & 0xfffffff8) */
-  REGF_HBIN* hbin;       /* pointer to HBIN record (in memory) containing 
-			  * this nk record 
-			  */
-  uint32 hbin_off;	 /* offset from beginning of this hbin block */
-  REGF_HASH_LIST_ELEM* hashes;
+  uint32 num_keys;
+  REGF_SUBKEY_LIST_ELEM* elements;
   
   uint8 magic[REC_HDR_SIZE];
-  uint16 num_keys;
-} REGF_HASH_LIST;
+} REGF_SUBKEY_LIST;
 
 
@@ -219,5 +215,5 @@
   /* link in the other records here */
   REGF_VK_REC** values;
-  REGF_HASH_LIST* subkeys;
+  REGF_SUBKEY_LIST* subkeys;
   
   /* header information */
@@ -246,8 +242,8 @@
   /* children */
   uint32 num_subkeys;
-  uint32 subkeys_off;	/* hash records that point to NK records */	
+  uint32 subkeys_off;	/* offset of subkey list that points to NK records */
   uint32 num_values;
   uint32 values_off;	/* value lists which point to VK records */
-  uint32 sk_off;	/* offset to SK record */  
+  uint32 sk_off;	/* offset to SK record */
 } REGF_NK_REC;
 
@@ -347,4 +343,24 @@
 const REGF_VK_REC*    regfi_iterator_cur_value(REGFI_ITERATOR* i);
 const REGF_VK_REC*    regfi_iterator_next_value(REGFI_ITERATOR* i);
+
+
+/********************************************************/
+/* Middle-layer structure caching, loading, and linking */
+/********************************************************/
+REGF_HBIN* regfi_lookup_hbin(REGF_FILE* file, uint32 offset);
+
+REGF_NK_REC* regfi_load_key(REGF_FILE* file, uint32 offset, bool strict);
+
+REGF_SUBKEY_LIST* regfi_load_subkeylist(REGF_FILE* file, uint32 offset, 
+					uint32 num_keys, uint32 max_size, 
+					bool strict);
+
+REGF_VK_REC** regfi_load_valuelist(REGF_FILE* file, uint32 offset, 
+				   uint32 num_values, uint32 max_size, 
+				   bool strict);
+
+REGF_SUBKEY_LIST* regfi_merge_subkeylists(uint16 num_lists, 
+					  REGF_SUBKEY_LIST** lists,
+					  bool strict);
 
 /************************************/
@@ -370,42 +386,27 @@
 				     uint32 max_size, bool strict);
 
+REGF_VK_REC* regfi_parse_vk(REGF_FILE* file, uint32 offset, 
+			    uint32 max_size, bool strict);
+
+uint8* regfi_parse_data(REGF_FILE* file, uint32 offset, 
+			uint32 length, bool strict);
+
+REGF_SK_REC* regfi_parse_sk(REGF_FILE* file, uint32 offset, uint32 max_size, bool strict);
+
+range_list* regfi_parse_unalloc_cells(REGF_FILE* file);
+
+bool regfi_parse_cell(int fd, uint32 offset, uint8* hdr, uint32 hdr_len,
+		      uint32* cell_length, bool* unalloc);
+
+char* regfi_parse_classname(REGF_FILE* file, uint32 offset,
+			    uint16* name_length, bool strict);
+
 
 /* Private Functions */
 REGF_NK_REC*          regfi_rootkey(REGF_FILE* file);
 void                  regfi_key_free(REGF_NK_REC* nk);
+void                  regfi_subkeylist_free(REGF_SUBKEY_LIST* list);
 uint32                regfi_read(int fd, uint8* buf, uint32* length);
 
 
-
-/****************/
-/* Experimental */
-/****************/
-REGF_NK_REC* regfi_load_key(REGF_FILE* file, uint32 offset, bool strict);
-
-REGF_HASH_LIST* regfi_load_hashlist(REGF_FILE* file, uint32 offset, 
-				    uint32 num_keys, uint32 max_size, 
-				    bool strict);
-
-REGF_VK_REC** regfi_load_valuelist(REGF_FILE* file, uint32 offset, 
-				   uint32 num_values, uint32 max_size, 
-				   bool strict);
-
-REGF_VK_REC* regfi_parse_vk(REGF_FILE* file, uint32 offset, 
-			    uint32 max_size, bool strict);
-
-uint8* regfi_parse_data(REGF_FILE* file, uint32 offset, 
-			uint32 length, bool strict);
-
-REGF_SK_REC* regfi_parse_sk(REGF_FILE* file, uint32 offset, uint32 max_size, bool strict);
-
-range_list* regfi_parse_unalloc_cells(REGF_FILE* file);
-
-REGF_HBIN* regfi_lookup_hbin(REGF_FILE* file, uint32 offset);
-
-bool regfi_parse_cell(int fd, uint32 offset, uint8* hdr, uint32 hdr_len,
-		      uint32* cell_length, bool* unalloc);
-
-char* regfi_parse_classname(REGF_FILE* file, uint32 offset,
-			    uint16* name_length, bool strict);
-
 #endif	/* _REGFI_H */
Index: trunk/lib/regfi.c
===================================================================
--- trunk/lib/regfi.c	(revision 126)
+++ trunk/lib/regfi.c	(revision 127)
@@ -440,26 +440,71 @@
 
 
-
 /*******************************************************************
  *******************************************************************/
-REGF_HASH_LIST* regfi_load_hashlist(REGF_FILE* file, uint32 offset, 
-				    uint32 num_keys, uint32 max_size, 
-				    bool strict)
-{
-  REGF_HASH_LIST* ret_val;
-  uint32 i, cell_length, length;
+REGF_SUBKEY_LIST* regfi_merge_subkeylists(uint16 num_lists, 
+					  REGF_SUBKEY_LIST** lists,
+					  bool strict)
+{
+  uint32 i,j,k;
+  REGF_SUBKEY_LIST* ret_val = (REGF_SUBKEY_LIST*)zalloc(sizeof(REGF_SUBKEY_LIST));
+  if(ret_val == NULL || lists == NULL)
+    return NULL;
+  
+  /* Obtain total number of elements */
+  ret_val->num_keys = 0;
+  for(i=0; i < num_lists; i++)
+  {
+    if(lists[i] == NULL)
+    {
+      ret_val->num_keys = 0;
+      break;
+    }
+    ret_val->num_keys += lists[i]->num_keys;
+  }
+  
+  if(ret_val->num_keys > 0)
+  {
+    ret_val->elements = 
+      (REGF_SUBKEY_LIST_ELEM*)zalloc(sizeof(REGF_SUBKEY_LIST_ELEM)
+				     * ret_val->num_keys);
+    k=0;
+    if(ret_val->elements != NULL)
+    {
+      for(i=0; i<num_lists; i++)
+	for(j=0; j<lists[i]->num_keys; j++)
+	{
+	  ret_val->elements[k].hash=lists[i]->elements[j].hash;
+	  ret_val->elements[k++].nk_off=lists[i]->elements[j].nk_off;
+	}
+    }
+  }
+  
+  for(i=0; i < num_lists; i++)
+    regfi_subkeylist_free(lists[i]);
+  free(lists);
+
+  return ret_val;
+}
+
+
+
+/*******************************************************************
+ *******************************************************************/
+REGF_SUBKEY_LIST* regfi_load_subkeylist(REGF_FILE* file, uint32 offset, 
+					uint32 num_keys, uint32 max_size, 
+					bool strict)
+{
+  REGF_SUBKEY_LIST* ret_val;
+  REGF_SUBKEY_LIST** sublists;
+  REGF_HBIN* sublist_hbin;
+  uint32 i, cell_length, length, num_sublists, off, max_length;
   uint8* hashes;
-  uint8 buf[REGFI_HASH_LIST_MIN_LENGTH];
+  uint8 buf[REGFI_SUBKEY_LIST_MIN_LEN];
   bool unalloc;
 
-  if(!regfi_parse_cell(file->fd, offset, buf, REGFI_HASH_LIST_MIN_LENGTH, 
+  if(!regfi_parse_cell(file->fd, offset, buf, REGFI_SUBKEY_LIST_MIN_LEN, 
 		       &cell_length, &unalloc))
     return NULL;
 
-  ret_val = (REGF_HASH_LIST*)zalloc(sizeof(REGF_HASH_LIST));
-  if(ret_val == NULL)
-    return NULL;
-
-  ret_val->offset = offset;
   if(cell_length > max_size)
   {
@@ -468,8 +513,44 @@
     cell_length = max_size & 0xFFFFFFF8;
   }
+
+  if(buf[0] == 'r' && buf[1] == 'i')
+  {
+    num_sublists = SVAL(buf, 0x2);
+
+    /* XXX: check cell_length vs num_sublists vs max_length */
+    length = num_sublists*sizeof(uint32);
+    hashes = (uint8*)zalloc(length);
+    if(hashes == NULL)
+      return NULL;
+
+    if(regfi_read(file->fd, hashes, &length) != 0
+       || length != num_sublists*sizeof(uint32))
+    { 
+      free(hashes);
+      return NULL; 
+    }
+
+    sublists = (REGF_SUBKEY_LIST**)zalloc(num_sublists*sizeof(REGF_SUBKEY_LIST*));    
+    for(i=0; i < num_sublists; i++)
+    {
+      off = IVAL(hashes, i*4)+REGF_BLOCKSIZE;
+      sublist_hbin = regfi_lookup_hbin(file, IVAL(hashes, i*4));
+      max_length = sublist_hbin->block_size + sublist_hbin->file_off - off;
+
+      /* XXX: Need to add a recursion depth limit of some kind. */
+      sublists[i] = regfi_load_subkeylist(file, off, 0, max_length, strict);
+    }
+
+    return regfi_merge_subkeylists(num_sublists, sublists, strict);
+  }
+
+  ret_val = (REGF_SUBKEY_LIST*)zalloc(sizeof(REGF_SUBKEY_LIST));
+  if(ret_val == NULL)
+    return NULL;
+
+  ret_val->offset = offset;
   ret_val->cell_size = cell_length;
 
-  if((buf[0] != 'l' || buf[1] != 'f') && (buf[0] != 'l' || buf[1] != 'h')
-     && (buf[0] != 'r' || buf[1] != 'i'))
+  if((buf[0] != 'l' || buf[1] != 'f') && (buf[0] != 'l' || buf[1] != 'h'))
   {
     /*printf("DEBUG: lf->header=%c%c\n", buf[0], buf[1]);*/
@@ -478,11 +559,4 @@
   }
 
-  if(buf[0] == 'r' && buf[1] == 'i')
-  {
-    fprintf(stderr, "WARNING: ignoring encountered \"ri\" record.\n");
-    free(ret_val);
-    return NULL;
-  }
-
   ret_val->magic[0] = buf[0];
   ret_val->magic[1] = buf[1];
@@ -491,13 +565,10 @@
   if(num_keys != ret_val->num_keys)
   {
-    if(strict)
-    {
-      free(ret_val);
-      return NULL;
-    }
-    /* 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.
+    /*  Not sure which should be authoritative, the number from the 
+     *  NK record, or the number in the subkey list.  Go with the larger
+     *  of the two to ensure all keys are found, since in 'ri' records, 
+     *  there is no authoritative parent count for a leaf subkey list.  
+     *  Note the length checks on the cell later ensure that there won't
+     *  be any critical errors.
      */
     if(num_keys < ret_val->num_keys)
@@ -507,11 +578,11 @@
   }
 
-  if(cell_length - REGFI_HASH_LIST_MIN_LENGTH - sizeof(uint32) 
-     < ret_val->num_keys*sizeof(REGF_HASH_LIST_ELEM))
-    return NULL;
-
-  length = sizeof(REGF_HASH_LIST_ELEM)*ret_val->num_keys;
-  ret_val->hashes = (REGF_HASH_LIST_ELEM*)zalloc(length);
-  if(ret_val->hashes == NULL)
+  if(cell_length - REGFI_SUBKEY_LIST_MIN_LEN - sizeof(uint32) 
+     < ret_val->num_keys*sizeof(REGF_SUBKEY_LIST_ELEM))
+    return NULL;
+
+  length = sizeof(REGF_SUBKEY_LIST_ELEM)*ret_val->num_keys;
+  ret_val->elements = (REGF_SUBKEY_LIST_ELEM*)zalloc(length);
+  if(ret_val->elements == NULL)
   {
     free(ret_val);
@@ -522,5 +593,5 @@
   if(hashes == NULL)
   {
-    free(ret_val->hashes);
+    free(ret_val->elements);
     free(ret_val);
     return NULL;
@@ -528,7 +599,7 @@
 
   if(regfi_read(file->fd, hashes, &length) != 0
-     || length != sizeof(REGF_HASH_LIST_ELEM)*ret_val->num_keys)
-  {
-    free(ret_val->hashes);
+     || length != sizeof(REGF_SUBKEY_LIST_ELEM)*ret_val->num_keys)
+  {
+    free(ret_val->elements);
     free(ret_val);
     return NULL;
@@ -537,6 +608,6 @@
   for (i=0; i < ret_val->num_keys; i++)
   {
-    ret_val->hashes[i].nk_off = IVAL(hashes, i*sizeof(REGF_HASH_LIST_ELEM));
-    ret_val->hashes[i].hash = IVAL(hashes, i*sizeof(REGF_HASH_LIST_ELEM)+4);
+    ret_val->elements[i].nk_off = IVAL(hashes, i*sizeof(REGF_SUBKEY_LIST_ELEM));
+    ret_val->elements[i].hash = IVAL(hashes, i*sizeof(REGF_SUBKEY_LIST_ELEM)+4);
   }
   free(hashes);
@@ -818,6 +889,6 @@
       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);
+      nk->subkeys = regfi_load_subkeylist(file, off, nk->num_subkeys, 
+					  max_length, true);
       if(nk->subkeys == NULL)
       {
@@ -1003,4 +1074,6 @@
   }
 
+  regfi_subkeylist_free(nk->subkeys);
+
   if(nk->keyname != NULL)
     free(nk->keyname);
@@ -1011,4 +1084,16 @@
   /* XXX: not freeing sec_desc because these are cached.  This needs to be reviewed. */
   free(nk);
+}
+
+
+/******************************************************************************
+ *****************************************************************************/
+void regfi_subkeylist_free(REGF_SUBKEY_LIST* list)
+{
+  if(list != NULL)
+  {
+    free(list->elements);
+    free(list);
+  }
 }
 
@@ -1269,5 +1354,5 @@
     return NULL;
 
-  nk_offset = i->cur_key->subkeys->hashes[i->cur_subkey].nk_off;
+  nk_offset = i->cur_key->subkeys->elements[i->cur_subkey].nk_off;
   
   return regfi_load_key(i->f, nk_offset+REGF_BLOCKSIZE, true);
