Index: trunk/Makefile
===================================================================
--- trunk/Makefile	(revision 158)
+++ trunk/Makefile	(revision 159)
@@ -11,6 +11,6 @@
 
 CC=gcc
-OPTS=-std=gnu89 -pedantic -Wall -ggdb
-#OPTS=-std=gnu89 -pedantic -Wall
+OPTS=-std=gnu99 -pedantic -Wall -ggdb
+#OPTS=-std=gnu99 -pedantic -Wall
 INC:=-I$(PWD)/include -I/usr/local/include 
 LIB=-L/usr/local/lib -lm
Index: trunk/include/regfi.h
===================================================================
--- trunk/include/regfi.h	(revision 158)
+++ trunk/include/regfi.h	(revision 159)
@@ -45,4 +45,5 @@
 #include <unistd.h>
 #include <assert.h>
+#include <iconv.h>
 
 #include "talloc.h"
@@ -250,4 +251,43 @@
 
 
+typedef struct _regfi_data
+{
+  uint32 type;
+
+  /* Length of the raw data. */
+  uint32 size;
+
+  /* This is always present, representing the raw data cell contents. */
+  uint8* raw;
+
+  /* Represents the length of the interpreted value. Meaning is type-specific.*/
+  uint32 interpreted_size;
+
+  /* These items represent interpreted versions of the raw attribute above. 
+   * Only use the appropriate member according to the type field.  
+   * In the event of an unknown type, use only the raw field.
+   */
+  union _regfi_data_interpreted
+  {
+    uint8* none; /* */
+    uint8* string;
+    uint8* expand_string;
+    uint8* binary; /* */
+    uint32 dword;
+    uint32 dword_be;
+    uint8* link;
+    uint8** multiple_string;
+    uint64 qword;
+
+    /* The following are treated as binary currently, but this may change in
+     * the future as the formats become better understood.
+     */
+    uint8* resource_list;
+    uint8* full_resource_descriptor;
+    uint8* resource_requirements_list;
+  } interpreted;
+} REGFI_DATA;
+
+
 /* Value record */
 typedef struct 
@@ -256,11 +296,13 @@
   uint32 cell_size;	/* ((start_offset - end_offset) & 0xfffffff8) */
 
-  uint8* data;
+  REGFI_DATA* data;     /* XXX: deprecated */
+
   char*  valuename;
   uint16 name_length;
   uint32 hbin_off;	/* offset from beginning of this hbin block */
   
-  uint32 data_size;
-  uint32 data_off;      /* offset of data cell (virtual) */
+  uint32 data_size;     /* As reported in the VK record.  May be different than
+			 * That obtained while parsing the data cell itself. */
+  uint32 data_off;      /* Offset of data cell (virtual) */
   uint32 type;
   uint8  magic[REGFI_CELL_MAGIC_SIZE];
@@ -423,4 +465,5 @@
   void_stack* key_positions;
   REGFI_NK_REC* cur_key;
+  const char* string_encoding;
   uint32 cur_subkey;
   uint32 cur_value;
@@ -446,4 +489,5 @@
 
 
+
 /******************************************************************************/
 /*                         Main iterator API                                  */
@@ -462,7 +506,30 @@
  */
 char*                 regfi_get_messages(REGFI_FILE* file);
+
 void                  regfi_set_message_mask(REGFI_FILE* file, uint16 mask);
 
-REGFI_ITERATOR*       regfi_iterator_new(REGFI_FILE* fh);
+
+/* regfi_iterator_new: Creates a new iterator for the provided registry file.
+ *
+ * Arguments:
+ *   file            -- The opened registry file the iterator should be
+ *                      created for.
+ *   output_encoding -- An integer representing the output string encoding.
+ *                      These integers currently map to a specific set of 
+ *                      iconv(3) encodings.
+ *                      The following values are currently accepted:
+ *                      0 - default (currently US-ASCII//TRANSLIT)
+ *                      1 - US-ASCII//TRANSLIT
+ *                      2 - UTF-8//TRANSLIT
+ *
+ *                      XXX: This encoding only applies to specific data 
+ *                           strings currently, but should apply to key 
+ *                           names and value names in the future.
+ *
+ * Returns:
+ *   A newly allocated REGFI_ITERATOR. Must be free()d with regfi_iterator_free.
+ */
+REGFI_ITERATOR*       regfi_iterator_new(REGFI_FILE* file,
+					 uint32 output_encoding);
 void                  regfi_iterator_free(REGFI_ITERATOR* i);
 bool                  regfi_iterator_down(REGFI_ITERATOR* i);
@@ -487,5 +554,6 @@
 						const char* value_name);
 
-REGFI_DATA*           regfi_iterator_cur_data(REGFI_ITERATOR* i);
+REGFI_DATA*           regfi_iterator_fetch_data(REGFI_ITERATOR* i, 
+						const REGFI_VK_REC* value);
 
 
@@ -512,4 +580,8 @@
 					  range_list* used_ranges,
 					  bool strict);
+bool                  regfi_interpret_data(REGFI_FILE* file, 
+					   const char* string_encoding,
+					   uint32 type, REGFI_DATA* data);
+void                  regfi_free_data(REGFI_DATA* data);
 
 /* These are cached so return values don't need to be freed. */
@@ -599,4 +671,8 @@
 REGFI_VK_REC*         regfi_copy_vk(const REGFI_VK_REC* vk);
 int32                 regfi_calc_maxsize(REGFI_FILE* file, uint32 offset);
+int32                 regfi_conv_charset(const char* output_charset, 
+					 uint8* input, char* output, 
+					 uint32 input_len, uint32 output_max);
+REGFI_DATA*           regfi_buffer_to_data(REGFI_BUFFER raw_data);
 
 #endif	/* _REGFI_H */
Index: trunk/lib/regfi.c
===================================================================
--- trunk/lib/regfi.c	(revision 158)
+++ trunk/lib/regfi.c	(revision 159)
@@ -958,5 +958,4 @@
 {
   REGFI_VK_REC* ret_val = NULL;
-  REGFI_BUFFER data;
   int32 max_size;
 
@@ -969,22 +968,5 @@
     return NULL;
 
-  if(ret_val->data_size == 0)
-    ret_val->data = NULL;
-  else
-  {
-    data = regfi_load_data(file, ret_val->data_off, ret_val->data_size,
-			   ret_val->data_in_offset, strict);
-    ret_val->data = data.buf;
-    ret_val->data_size = data.len;
-
-    if(ret_val->data == NULL)
-    {
-      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse data record"
-			" while parsing VK record at offset 0x%.8X.",
-			ret_val->offset, ret_val->valuename);
-    }
-    else
-      talloc_steal(ret_val, ret_val->data);
-  }
+  /* XXX: convert valuename to proper encoding if necessary */
 
   return ret_val;
@@ -1189,5 +1171,4 @@
   while(cur_offset < hbin_end)
   {
-    fprintf(stderr, "DEBUG: trying cell offset 0x%.8X\n", cur_offset);
     if(!regfi_parse_cell(file->fd, cur_offset, NULL, 0, &cell_length, &unalloc))
     {
@@ -1383,5 +1364,5 @@
 /******************************************************************************
  *****************************************************************************/
-REGFI_ITERATOR* regfi_iterator_new(REGFI_FILE* fh)
+REGFI_ITERATOR* regfi_iterator_new(REGFI_FILE* file, uint32 output_encoding)
 {
   REGFI_NK_REC* root;
@@ -1390,5 +1371,5 @@
     return NULL;
 
-  root = regfi_rootkey(fh);
+  root = regfi_rootkey(file);
   if(root == NULL)
   {
@@ -1405,9 +1386,23 @@
   talloc_steal(ret_val, ret_val->key_positions);
 
-  ret_val->f = fh;
+  ret_val->f = file;
   ret_val->cur_key = root;
   ret_val->cur_subkey = 0;
   ret_val->cur_value = 0;
-
+  
+  switch (output_encoding)
+  {
+  case 0:
+  case 1:
+    ret_val->string_encoding = "US-ASCII//TRANSLIT";
+    break;
+  case 2:
+    ret_val->string_encoding = "UTF-8//TRANSLIT";
+    break;
+  default:
+    talloc_free(ret_val);
+    return NULL;
+  }
+  
   return ret_val;
 }
@@ -1688,7 +1683,285 @@
 
 
+/******************************************************************************
+ *****************************************************************************/
+REGFI_DATA* regfi_iterator_fetch_data(REGFI_ITERATOR* i, 
+				      const REGFI_VK_REC* value)
+{
+  REGFI_DATA* ret_val = NULL;
+  REGFI_BUFFER raw_data;
+
+  if(value->data_size != 0)
+  {
+    raw_data = regfi_load_data(i->f, value->data_off, value->data_size,
+			      value->data_in_offset, true);
+    if(raw_data.buf == NULL)
+    {
+      regfi_add_message(i->f, REGFI_MSG_WARN, "Could not parse data record"
+			" while parsing VK record at offset 0x%.8X.",
+			value->offset);
+    }
+    else
+    {
+      ret_val = regfi_buffer_to_data(raw_data);
+
+      if(ret_val == NULL)
+      {
+	regfi_add_message(i->f, REGFI_MSG_WARN, "Error occurred in converting"
+			  " data buffer to data structure while interpreting "
+			  "data for VK record at offset 0x%.8X.",
+			  value->offset);
+	talloc_free(raw_data.buf);
+	return NULL;
+      }
+
+      if(!regfi_interpret_data(i->f, i->string_encoding, value->type, ret_val))
+      {
+	regfi_add_message(i->f, REGFI_MSG_INFO, "Error occurred while"
+			  " interpreting data for VK record at offset 0x%.8X.",
+			  value->offset);
+      }
+    }
+  }
+  
+  return ret_val;
+}
+
+
+/******************************************************************************
+ *****************************************************************************/
+void regfi_free_data(REGFI_DATA* data)
+{
+  talloc_free(data);
+}
+
+
+/******************************************************************************
+ *****************************************************************************/
+REGFI_DATA* regfi_buffer_to_data(REGFI_BUFFER raw_data)
+{
+  REGFI_DATA* ret_val;
+
+  if(raw_data.buf == NULL)
+    return NULL;
+
+  ret_val = talloc(NULL, REGFI_DATA);
+  if(ret_val == NULL)
+    return NULL;
+  
+  talloc_steal(ret_val, raw_data.buf);
+  ret_val->raw = raw_data.buf;
+  ret_val->size = raw_data.len;
+  ret_val->interpreted_size = 0;
+  ret_val->interpreted.qword = 0;
+
+  return ret_val;
+}
+
+
+/******************************************************************************
+ *****************************************************************************/
+bool regfi_interpret_data(REGFI_FILE* file, const char* string_encoding,
+			  uint32 type, REGFI_DATA* data)
+{
+  uint8** tmp_array;
+  uint8* tmp_str;
+  int32 tmp_size;
+  uint32 i, j, array_size;
+
+  if(data == NULL)
+    return false;
+
+  switch (type)
+  {
+  case REG_SZ:
+  case REG_EXPAND_SZ:
+  /* REG_LINK is a symbolic link, stored as a unicode string. */
+  case REG_LINK:
+    tmp_str = talloc_array(NULL, uint8, data->size);
+    if(tmp_str == NULL)
+    {
+      data->interpreted.string = NULL;
+      data->interpreted_size = 0;
+      return false;
+    }
+      
+    tmp_size = regfi_conv_charset(string_encoding, 
+				  data->raw, (char*)tmp_str, 
+				  data->size, data->size);
+    if(tmp_size < 0)
+    {
+      regfi_add_message(file, REGFI_MSG_INFO, "Error occurred while"
+			" converting data of type %d to %s.  Error message: %s",
+			type, string_encoding, strerror(-tmp_size));
+      talloc_free(tmp_str);
+      data->interpreted.string = NULL;
+      data->interpreted_size = 0;
+      return false;
+    }
+
+    tmp_str = talloc_realloc(NULL, tmp_str, uint8, tmp_size);
+    data->interpreted.string = tmp_str;
+    data->interpreted_size = tmp_size;
+    talloc_steal(data, tmp_str);
+    break;
+
+  case REG_DWORD:
+    if(data->size < 4)
+    {
+      data->interpreted.dword = 0;
+      data->interpreted_size = 0;
+      return false;
+    }
+    data->interpreted.dword = IVAL(data->raw, 0);
+    data->interpreted_size = 4;
+    break;
+
+  case REG_DWORD_BE:
+    if(data->size < 4)
+    {
+      data->interpreted.dword_be = 0;
+      data->interpreted_size = 0;
+      return false;
+    }
+    data->interpreted.dword_be = RIVAL(data->raw, 0);
+    data->interpreted_size = 4;
+    break;
+
+  case REG_QWORD:
+    if(data->size < 8)
+    {
+      data->interpreted.qword = 0;
+      data->interpreted_size = 0;
+      return false;
+    }
+    data->interpreted.qword = 
+      (uint64)IVAL(data->raw, 0) + (((uint64)IVAL(data->raw, 4))<<32);
+    data->interpreted_size = 8;
+    break;
+    
+  case REG_MULTI_SZ:
+    tmp_str = talloc_array(NULL, uint8, data->size);
+    if(tmp_str == NULL)
+    {
+      data->interpreted.multiple_string = NULL;
+      data->interpreted_size = 0;
+      return false;
+    }
+
+    /* Attempt to convert entire string from UTF-16LE to output encoding,
+     * then parse and quote fields individually.
+     */
+    tmp_size = regfi_conv_charset(string_encoding, 
+				  data->raw, (char*)tmp_str,
+				  data->size, data->size);
+    if(tmp_size < 0)
+    {
+      regfi_add_message(file, REGFI_MSG_INFO, "Error occurred while"
+			" converting data of type %d to %s.  Error message: %s",
+			type, string_encoding, strerror(-tmp_size));
+      talloc_free(tmp_str);
+      data->interpreted.multiple_string = NULL;
+      data->interpreted_size = 0;
+      return false;
+    }
+
+    array_size = tmp_size+1;
+    tmp_array = talloc_array(NULL, uint8*, array_size);
+    if(tmp_array == NULL)
+    {
+      talloc_free(tmp_str);
+      data->interpreted.string = NULL;
+      data->interpreted_size = 0;
+      return false;
+    }
+    
+    tmp_array[0] = tmp_str;
+    for(i=0,j=1; i < tmp_size && j < array_size-1; i++)
+    {
+      if(tmp_str[i] == '\0' && (i+1 < tmp_size))
+	tmp_array[j++] = tmp_str+i+1;
+    }
+    tmp_array[j] = NULL;
+    tmp_array = talloc_realloc(NULL, tmp_array, uint8*, j+1);
+    data->interpreted.multiple_string = tmp_array;
+    /* XXX: how meaningful is this?  should we store number of strings instead? */
+    data->interpreted_size = tmp_size;
+    talloc_steal(tmp_array, tmp_str);
+    talloc_steal(data, tmp_array);
+    break;
+
+  /* XXX: Dont know how to interpret these yet, just treat as binary */
+  case REG_NONE:
+    data->interpreted.none = data->raw;
+    data->interpreted_size = data->size;
+    break;
+
+  case REG_RESOURCE_LIST:
+    data->interpreted.resource_list = data->raw;
+    data->interpreted_size = data->size;
+    break;
+
+  case REG_FULL_RESOURCE_DESCRIPTOR:
+    data->interpreted.full_resource_descriptor = data->raw;
+    data->interpreted_size = data->size;
+    break;
+
+  case REG_RESOURCE_REQUIREMENTS_LIST:
+    data->interpreted.resource_requirements_list = data->raw;
+    data->interpreted_size = data->size;
+    break;
+
+  case REG_BINARY:
+    data->interpreted.binary = data->raw;
+    data->interpreted_size = data->size;
+    break;
+
+  default:
+    data->interpreted.qword = 0;
+    data->interpreted_size = 0;
+    return false;
+  }
+
+  data->type = type;
+  return true;
+}
+
+
+
+/*******************************************************************
+ * Convert from UTF-16LE to specified character set. 
+ * On error, returns a negative errno code.
+ *******************************************************************/
+int32 regfi_conv_charset(const char* output_charset, 
+			 uint8* input, char* output, 
+			 uint32 input_len, uint32 output_max)
+{
+  iconv_t conv_desc;
+  char* inbuf = (char*)input;
+  char* outbuf = output;
+  size_t in_len = (size_t)input_len;
+  size_t out_len = (size_t)(output_max-1);
+  int ret;
+
+  /* Set up conversion descriptor. */
+  conv_desc = iconv_open(output_charset, "UTF-16LE");
+
+  ret = iconv(conv_desc, &inbuf, &in_len, &outbuf, &out_len);
+  if(ret == -1)
+  {
+    iconv_close(conv_desc);
+    return -errno;
+  }
+  *outbuf = '\0';
+
+  iconv_close(conv_desc);  
+  return output_max-out_len-1;
+}
+
+
+
 /*******************************************************************
  * Computes the checksum of the registry file header.
- * buffer must be at least the size of an regf header (4096 bytes).
+ * buffer must be at least the size of a regf header (4096 bytes).
  *******************************************************************/
 static uint32 regfi_compute_header_checksum(uint8* buffer)
@@ -2187,5 +2460,5 @@
  *
  ******************************************************************************/
-REGFI_BUFFER regfi_load_data(REGFI_FILE* file, uint32 voffset, 
+REGFI_BUFFER regfi_load_data(REGFI_FILE* file, uint32 voffset,
 			     uint32 length, bool data_in_offset,
 			     bool strict)
@@ -2196,4 +2469,25 @@
   bool unalloc;
   
+  /* Microsoft's documentation indicates that "available memory" is 
+   * the limit on value sizes.  Annoying.  We limit it to 1M which 
+   * should rarely be exceeded, unless the file is corrupt or 
+   * malicious. For more info, see:
+   *   http://msdn2.microsoft.com/en-us/library/ms724872.aspx
+   */
+  /*
+XXX
+  if(size > REGFI_VK_MAX_DATA_LENGTH)
+  {
+    *error_msg = (char*)malloc(82);
+    if(*error_msg == NULL)
+      return NULL;
+    
+    sprintf(*error_msg, "WARN: value data size %d larger than "
+	    "%d, truncating...", size, REGFI_VK_MAX_DATA_LENGTH);
+    size = REGFI_VK_MAX_DATA_LENGTH;
+  }
+
+  */
+
   if(data_in_offset)
     return regfi_parse_little_data(file, voffset, length, strict);
@@ -2289,5 +2583,5 @@
   }
 
-  if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL)
+  if((ret_val.buf = talloc_array(NULL, uint8, length)) == NULL)
     return ret_val;
   ret_val.len = length;
@@ -2329,5 +2623,5 @@
   }
 
-  if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL)
+  if((ret_val.buf = talloc_array(NULL, uint8, length)) == NULL)
     return ret_val;
   ret_val.len = length;
Index: trunk/src/common.c
===================================================================
--- trunk/src/common.c	(revision 158)
+++ trunk/src/common.c	(revision 159)
@@ -160,5 +160,4 @@
   int ret;
 
-  /* Set up conversion descriptor. */
   conv_desc = iconv_open("US-ASCII//TRANSLIT", "UTF-16LE");
 
@@ -229,154 +228,149 @@
  * value, and a non-NULL (*error_msg).
  */
-/* XXX: Part of this function's logic should be pushed into the regfi API.
- *      The structures should be parsed and stored with VK records and only 
- *      escaped/encoded later in reglookup and reglookup-recover.
- */
-static char* data_to_ascii(unsigned char* datap, uint32 len, uint32 type, 
-			   char** error_msg)
-{
-  char* asciip;
-  char* ascii;
-  char* ascii_tmp;
+static char* data_to_ascii(REGFI_DATA* data, char** error_msg)
+{
+  char* ret_val;
   char* cur_quoted;
-  char* tmp_err = NULL;
-  const char* delim;
-  uint32 i;
-  uint32 cur_str_len;
-  uint32 ascii_max;
-  uint32 str_rem, alen;
-  int ret_err;
-
-  if(datap == NULL)
-  {
-    *error_msg = (char*)malloc(24);
-    if(*error_msg == NULL)
-      return NULL;
-    strcpy(*error_msg, "Data pointer was NULL.");
+  char* tmp_ptr;
+  char* delim;
+  uint32 ret_val_left, i, tmp_len;
+
+  if(data == NULL || data->size == 0)
+  {
+    *error_msg = (char*)malloc(37);
+    if(*error_msg == NULL)
+      return NULL;
+    strcpy(*error_msg, "Data pointer was NULL or size was 0.");
     return NULL;
   }
   *error_msg = NULL;
 
-  switch (type) 
+
+  if(data->interpreted_size == 0)
+  {
+    *error_msg = (char*)malloc(51);
+    if(*error_msg == NULL)
+      return NULL;
+    strcpy(*error_msg, "Data could not be interpreted, quoting raw buffer.");
+    return quote_buffer(data->raw, data->size, common_special_chars);
+  }
+
+  switch (data->type) 
   {
   case REG_SZ:
+    ret_val = quote_string((char*)data->interpreted.string, common_special_chars);
+    if(ret_val == NULL && (*error_msg = (char*)malloc(49)) != NULL)
+	strcpy(*error_msg, "Buffer could not be quoted due to unknown error.");
+
+    return ret_val;
+    break;
+
+    
   case REG_EXPAND_SZ:
-    /* REG_LINK is a symbolic link, stored as a unicode string. */
+    ret_val = quote_string((char*)data->interpreted.expand_string, 
+			   common_special_chars);
+    if(ret_val == NULL && (*error_msg = (char*)malloc(49)) != NULL)
+	strcpy(*error_msg, "Buffer could not be quoted due to unknown error.");
+
+    return ret_val;
+    break;
+
   case REG_LINK:
-    /* Sometimes values have binary stored in them.  If the unicode
-     * conversion fails, just quote it raw.
+    ret_val = quote_string((char*)data->interpreted.link, common_special_chars);
+    if(ret_val == NULL && (*error_msg = (char*)malloc(49)) != NULL)
+	strcpy(*error_msg, "Buffer could not be quoted due to unknown error.");
+
+    return ret_val;
+    break;
+
+  case REG_DWORD:
+    ret_val = malloc(sizeof(char)*(8+2+1));
+    if(ret_val == NULL)
+      return NULL;
+
+    sprintf(ret_val, "0x%.8X", data->interpreted.dword);
+    return ret_val;
+    break;
+
+  case REG_DWORD_BE:
+    ret_val = malloc(sizeof(char)*(8+2+1));
+    if(ret_val == NULL)
+      return NULL;
+
+    sprintf(ret_val, "0x%.8X", data->interpreted.dword_be);
+    return ret_val;
+    break;
+
+  case REG_QWORD:
+    ret_val = malloc(sizeof(char)*(16+2+1));
+    if(ret_val == NULL)
+      return NULL;
+
+    sprintf(ret_val, "0x%.16llX", 
+	    (long long unsigned int)data->interpreted.qword);
+    return ret_val;
+    break;
+
+  case REG_MULTI_SZ:
+    ret_val_left = data->interpreted_size*4+1;
+    ret_val = malloc(ret_val_left);
+    if(ret_val == NULL)
+      return NULL;
+
+    tmp_ptr = ret_val;
+    tmp_ptr[0] = '\0';
+    delim = "";
+    for(i=0; data->interpreted.multiple_string[i] != NULL; i++)
+    {
+      cur_quoted = quote_string((char*)data->interpreted.multiple_string[i],
+				subfield_special_chars);
+      if(cur_quoted != NULL && cur_quoted[0] != '\0')
+      {
+	tmp_len = snprintf(tmp_ptr, ret_val_left, "%s%s",delim, cur_quoted);
+	tmp_ptr += tmp_len;
+	ret_val_left -= tmp_len;
+	free(cur_quoted);
+      }
+      delim = "|";
+    }
+
+    return ret_val;
+    break;
+
+    
+  case REG_NONE:
+    return quote_buffer(data->interpreted.none, data->interpreted_size,
+			common_special_chars);
+
+    break;
+
+  case REG_RESOURCE_LIST:
+    return quote_buffer(data->interpreted.resource_list, data->interpreted_size,
+			common_special_chars);
+
+    break;
+
+  case REG_FULL_RESOURCE_DESCRIPTOR:
+    return quote_buffer(data->interpreted.full_resource_descriptor, 
+			data->interpreted_size, common_special_chars);
+
+    break;
+
+  case REG_RESOURCE_REQUIREMENTS_LIST:
+    return quote_buffer(data->interpreted.resource_requirements_list,
+			data->interpreted_size, common_special_chars);
+
+    break;
+
+  case REG_BINARY:
+    return quote_buffer(data->interpreted.binary, data->interpreted_size,
+			common_special_chars);
+
+    break;
+
+  default:
+    /* This shouldn't happen, since the regfi routines won't interpret 
+     * unknown types, but just as a safety measure against library changes... 
      */
-    cur_quoted = quote_unicode(datap, len, common_special_chars, &tmp_err);
-    if(cur_quoted == NULL)
-    {
-      if(tmp_err == NULL && (*error_msg = (char*)malloc(49)) != NULL)
-	strcpy(*error_msg, "Buffer could not be quoted due to unknown error.");
-      else if((*error_msg = (char*)malloc(42+strlen(tmp_err))) != NULL)
-      {
-	sprintf(*error_msg, "Buffer could not be quoted due to error: %s", 
-		tmp_err);
-	free(tmp_err);
-      }
-    }
-    else if (tmp_err != NULL)
-      *error_msg = tmp_err;
-    return cur_quoted;
-    break;
-
-  case REG_DWORD:
-    ascii_max = sizeof(char)*(8+2+1);
-    ascii = malloc(ascii_max);
-    if(ascii == NULL)
-      return NULL;
-
-    snprintf(ascii, ascii_max, "0x%.2X%.2X%.2X%.2X", 
-	     datap[3], datap[2], datap[1], datap[0]);
-    return ascii;
-    break;
-
-  case REG_DWORD_BE:
-    ascii_max = sizeof(char)*(8+2+1);
-    ascii = malloc(ascii_max);
-    if(ascii == NULL)
-      return NULL;
-
-    snprintf(ascii, ascii_max, "0x%.2X%.2X%.2X%.2X", 
-	     datap[0], datap[1], datap[2], datap[3]);
-    return ascii;
-    break;
-
-  case REG_QWORD:
-    ascii_max = sizeof(char)*(16+2+1);
-    ascii = malloc(ascii_max);
-    if(ascii == NULL)
-      return NULL;
-
-    snprintf(ascii, ascii_max, "0x%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X",
-	     datap[7], datap[6], datap[5], datap[4],
-	     datap[3], datap[2], datap[1], datap[0]);
-    return ascii;
-    break;
-    
-  case REG_MULTI_SZ:
-    ascii_max = sizeof(char)*(len*4+1);
-    ascii_tmp = malloc(ascii_max);
-    if(ascii_tmp == NULL)
-      return NULL;
-
-    /* Attempt to convert entire string from UTF-16LE to ASCII, 
-     * then parse and quote fields individually.
-     * If this fails, simply quote entire buffer as binary. 
-     */
-    ret_err = uni_to_ascii(datap, ascii_tmp, len, ascii_max);
-    if(ret_err < 0)
-    {
-      tmp_err = strerror(-ret_err);
-      *error_msg = (char*)malloc(61+strlen(tmp_err));
-      if(*error_msg == NULL)
-      {
-	free(ascii_tmp);
-	return NULL;
-      }
-
-      sprintf(*error_msg, "MULTI_SZ unicode conversion"
-	      " failed with '%s'. Quoting as binary.", tmp_err);
-      ascii = quote_buffer(datap, len, subfield_special_chars);
-    }
-    else
-    {
-      ascii = malloc(ascii_max);
-      if(ascii == NULL)
-      {
-	free(ascii_tmp);
-	return NULL;
-      }
-      asciip = ascii;
-      asciip[0] = '\0';
-      str_rem = ascii_max;
-      delim = "";
-      for(i=0; i<ret_err; i+=cur_str_len+1)
-      {
-	cur_str_len = strlen(ascii_tmp+i);
-	if(ascii_tmp[i] != '\0')
-	{
-	  cur_quoted = quote_string(ascii_tmp+i, subfield_special_chars);
-	  if(cur_quoted != NULL)
-	  {
-	    alen = snprintf(asciip, str_rem, "%s%s", delim, cur_quoted);
-	    asciip += alen;
-	    str_rem -= alen;
-	    free(cur_quoted);
-	  }
-	}
-	delim = "|";
-      }
-    }
-
-    free(ascii_tmp);
-    return ascii;
-    break;
-
-  /* XXX: Dont know what to do with these yet, just print as binary... */
-  default:
     *error_msg = (char*)malloc(65);
     if(*error_msg == NULL)
@@ -384,16 +378,8 @@
     sprintf(*error_msg,
 	    "Unrecognized registry data type (0x%.8X); quoting as binary.",
-	    type);
+	    data->type);
+    return quote_buffer(data->raw, data->size, common_special_chars);
+  }
     
-  case REG_NONE:
-  case REG_RESOURCE_LIST:
-  case REG_FULL_RESOURCE_DESCRIPTOR:
-  case REG_RESOURCE_REQUIREMENTS_LIST:
-
-  case REG_BINARY:
-    return quote_buffer(datap, len, common_special_chars);
-    break;
-  }
-
   return NULL;
 }
Index: trunk/src/reglookup-recover.c
===================================================================
--- trunk/src/reglookup-recover.c	(revision 158)
+++ trunk/src/reglookup-recover.c	(revision 159)
@@ -111,24 +111,5 @@
   char* conv_error = NULL;
   const char* str_type = NULL;
-  uint32 size = vk->data_size;
-
-  /* Microsoft's documentation indicates that "available memory" is 
-   * the limit on value sizes.  Annoying.  We limit it to 1M which 
-   * should rarely be exceeded, unless the file is corrupt or 
-   * malicious. For more info, see:
-   *   http://msdn2.microsoft.com/en-us/library/ms724872.aspx
-   */
-  /* 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 > REGFI_VK_MAX_DATA_LENGTH)
-  {
-    fprintf(stderr, "WARN: value data size %d larger than "
-	    "%d, truncating...\n", size, REGFI_VK_MAX_DATA_LENGTH);
-    size = REGFI_VK_MAX_DATA_LENGTH;
-  }
-  
+
   quoted_name = quote_string(vk->valuename, key_special_chars);
   if (quoted_name == NULL)
@@ -144,6 +125,14 @@
     quoted_name[0] = '\0';
   }
-
-  quoted_value = data_to_ascii(vk->data, size, vk->type, &conv_error);
+  /* XXX: Add command line option to choose output encoding */
+  if(vk->data != NULL 
+     && !regfi_interpret_data(f, "US-ASCII//TRANSLIT", vk->type, vk->data))
+  {
+    fprintf(stderr, "WARN: Error occurred while interpreting data for VK record"
+	    " at offset 0x%.8X.\n", vk->offset);
+  }
+  printMsgs(f);
+
+  quoted_value = data_to_ascii(vk->data, &conv_error);
   if(quoted_value == NULL)
   {
@@ -469,4 +458,6 @@
     return 10;
 
+  data.buf = NULL;
+  data.len = 0;
   for(i=0; i<range_list_size(unalloc_values); i++)
   {
@@ -571,7 +562,9 @@
 	  }
 	}
-
-	vk->data = data.buf;
-	vk->data_size = data.len;
+	/* XXX: Need to come up with a different way to link these so the
+	 *      vk->data item can be removed from the structure.
+	 */
+	vk->data = regfi_buffer_to_data(data);
+	talloc_steal(vk, vk->data);
       }
     }
Index: trunk/src/reglookup.c
===================================================================
--- trunk/src/reglookup.c	(revision 158)
+++ trunk/src/reglookup.c	(revision 159)
@@ -50,25 +50,12 @@
 
 
-void printValue(const REGFI_VK_REC* vk, char* prefix)
-{
+void printValue(REGFI_ITERATOR* iter, const REGFI_VK_REC* vk, char* prefix)
+{
+  REGFI_DATA* data;
   char* quoted_value = NULL;
   char* quoted_name = NULL;
   char* conv_error = NULL;
   const char* str_type = NULL;
-  uint32 size = vk->data_size;
-
-  /* Microsoft's documentation indicates that "available memory" is 
-   * the limit on value sizes.  Annoying.  We limit it to 1M which 
-   * should rarely be exceeded, unless the file is corrupt or 
-   * malicious. For more info, see:
-   *   http://msdn2.microsoft.com/en-us/library/ms724872.aspx
-   */
-  if(size > REGFI_VK_MAX_DATA_LENGTH)
-  {
-    fprintf(stderr, "WARN: value data size %d larger than "
-	    "%d, truncating...\n", size, REGFI_VK_MAX_DATA_LENGTH);
-    size = REGFI_VK_MAX_DATA_LENGTH;
-  }
-  
+
   quoted_name = quote_string(vk->valuename, key_special_chars);
   if (quoted_name == NULL)
@@ -84,14 +71,11 @@
     quoted_name[0] = '\0';
   }
-
-  if(vk->data == NULL)
-  {
-    if(print_verbose)
-      fprintf(stderr, "INFO: While quoting value for '%s/%s', "
-	      "data pointer was NULL.\n", prefix, quoted_name);
-  }
-  else
-  {
-    quoted_value = data_to_ascii(vk->data, size, vk->type, &conv_error);
+  
+  data = regfi_iterator_fetch_data(iter, vk);
+
+  printMsgs(iter->f);
+  if(data != NULL)
+  {
+    quoted_value = data_to_ascii(data, &conv_error);
     if(quoted_value == NULL)
     {
@@ -103,7 +87,8 @@
 		"Returned error: %s\n", prefix, quoted_name, conv_error);
     }
-    else if(conv_error != NULL && print_verbose)
-      fprintf(stderr, "INFO: While quoting value for '%s/%s', "
+    else if(conv_error != NULL)
+      fprintf(stderr, "WARN: While quoting value for '%s/%s', "
 	      "warning returned: %s\n", prefix, quoted_name, conv_error);
+    regfi_free_data(data);
   }
 
@@ -281,5 +266,5 @@
   {
     if(!type_filter_enabled || (value->type == type_filter))
-      printValue(value, prefix);
+      printValue(iter, value, prefix);
     regfi_free_value(value);
     value = regfi_iterator_next_value(iter);
@@ -511,5 +496,5 @@
 
     if(!type_filter_enabled || (value->type == type_filter))
-      printValue(value, tmp_path_joined);
+      printValue(iter, value, tmp_path_joined);
 
     regfi_free_value(value);
@@ -632,5 +617,6 @@
     regfi_set_message_mask(f, REGFI_MSG_INFO|REGFI_MSG_WARN|REGFI_MSG_ERROR);
 
-  iter = regfi_iterator_new(f);
+  /* XXX: add command line option to choose output encoding */
+  iter = regfi_iterator_new(f, 0);
   if(iter == NULL)
   {
