Index: trunk/src/reglookup.c
===================================================================
--- trunk/src/reglookup.c	(revision 66)
+++ trunk/src/reglookup.c	(revision 69)
@@ -83,5 +83,6 @@
        * times the amount of input left to process.  The expansion is bounded 
        * below by a minimum safety increase, and above by the maximum possible 
-       * output string length.
+       * output string length.  This should minimize both the number of 
+       * reallocs() and the amount of wasted memory.
        */
       added_len = (len-i)*num_written/(i+1);
@@ -137,5 +138,9 @@
 
 /*
- * Convert from Unicode to ASCII.
+ * Convert from UTF-16LE to ASCII.  Accepts a Unicode buffer, uni, and
+ * it's length, uni_max.  Writes ASCII to the buffer ascii, whose size
+ * is ascii_max.  Writes at most (ascii_max-1) bytes to ascii, and null
+ * terminates the string.  Returns the length of the string stored in
+ * ascii.  On error, returns a negative errno code.
  */
 static int uni_to_ascii(unsigned char* uni, char* ascii, 
@@ -144,4 +149,5 @@
   char* inbuf = (char*)uni;
   char* outbuf = ascii;
+  unsigned int out_len = ascii_max-1;
   int ret;
 
@@ -149,5 +155,5 @@
   conv_desc = iconv_open("US-ASCII", "UTF-16LE");
 
-  ret = iconv(conv_desc, &inbuf, &uni_max, &outbuf, &ascii_max);
+  ret = iconv(conv_desc, &inbuf, &uni_max, &outbuf, &out_len);
   if(ret == -1)
   {
@@ -163,19 +169,31 @@
 
 /*
- * Convert a data value to a string for display
+ * Convert a data value to a string for display.  Returns NULL on error,
+ * and the string to display if there is no error, or a non-fatal
+ * error.  On any error (fatal or non-fatal) occurs, (*error_msg) will
+ * be set to a newly allocated string, containing an error message.  If
+ * a memory allocation failure occurs while generating the error
+ * message, both the return value and (*error_msg) will be NULL.  It
+ * is the responsibility of the caller to free both a non-NULL return
+ * value, and a non-NULL (*error_msg).
  */
-static char* data_to_ascii(unsigned char *datap, int len, int type)
+static char* data_to_ascii(unsigned char *datap, int len, int type, 
+			   char** error_msg)
 {
   char* asciip;
-  unsigned int i;
-  unsigned short num_nulls;
   char* ascii;
   unsigned char* cur_str;
   char* cur_ascii;
   char* cur_quoted;
+  char* tmp_err;
+  const char* str_type;
+  unsigned int i;
   unsigned int cur_str_len;
   unsigned int ascii_max, cur_str_max;
   unsigned int str_rem, cur_str_rem, alen;
   int ret_err;
+  unsigned short num_nulls;
+
+  *error_msg = NULL;
 
   switch (type) 
@@ -185,6 +203,6 @@
     /* REG_LINK is a symbolic link, stored as a unicode string. */
   case REG_LINK:
-    ascii_max = sizeof(char)*len;
-    ascii = malloc(ascii_max+4);
+    ascii_max = sizeof(char)*(len+1);
+    ascii = malloc(ascii_max);
     if(ascii == NULL)
       return NULL;
@@ -193,15 +211,15 @@
      * conversion fails, just quote it raw.
      */
-    
     ret_err = uni_to_ascii(datap, ascii, len, ascii_max);
     if(ret_err < 0)
     {
-      /* XXX: It would be nice if somehow we could include the name of this
-       *      value in the error message.
-       */
-      if(print_verbose)
-	fprintf(stderr, "VERBOSE: Unicode conversion failed; "
-		"printing as binary.  Error: %s\n", strerror(-ret_err));
-
+      tmp_err = strerror(-ret_err);
+      str_type = regfio_type_val2str(type);
+      *error_msg = (char*)malloc(65+strlen(str_type)+strlen(tmp_err)+1);
+      if(*error_msg == NULL)
+	return NULL;
+      sprintf(*error_msg, "Unicode conversion failed on %s field; "
+	       "printing as binary.  Error: %s", str_type, tmp_err);
+      
       cur_quoted = quote_buffer(datap, len, common_special_chars);
     }
@@ -238,9 +256,9 @@
    */
   case REG_MULTI_SZ:
-    ascii_max = sizeof(char)*len*4;
-    cur_str_max = sizeof(char)*len+1;
+    ascii_max = sizeof(char)*(len*4+1);
+    cur_str_max = sizeof(char)*(len+1);
     cur_str = malloc(cur_str_max);
     cur_ascii = malloc(cur_str_max);
-    ascii = malloc(ascii_max+4);
+    ascii = malloc(ascii_max);
     if(ascii == NULL || cur_str == NULL || cur_ascii == NULL)
       return NULL;
@@ -271,11 +289,15 @@
 	if(ret_err < 0)
 	{
-	  /* XXX: It would be nice if somehow we could include the name of this
-	   *      value in the error message.
-	   */
-	  if(print_verbose)
-	    fprintf(stderr, "VERBOSE: Unicode conversion failed on sub-field; "
-		    "printing as binary.  Error: %s\n", strerror(-ret_err));
-	  
+	  /* XXX: should every sub-field error be enumerated? */
+	  if(*error_msg == NULL)
+	  {
+	    tmp_err = strerror(-ret_err);
+	    *error_msg = (char*)malloc(90+strlen(tmp_err)+1);
+	    if(*error_msg == NULL)
+	      return NULL;
+	    sprintf(*error_msg, "Unicode conversion failed on at least one "
+		    "MULTI_SZ sub-field; printing as binary.  Error: %s",
+		    tmp_err);
+	  }
 	  cur_quoted = quote_buffer(cur_str, cur_str_len-1, 
 				    subfield_special_chars);
@@ -435,4 +457,5 @@
   char* quoted_value = NULL;
   char* quoted_name = NULL;
+  char* conv_error = NULL;
 
   /* Thanks Microsoft for making this process so straight-forward!!! */
@@ -446,5 +469,5 @@
     if(size > 4)
       size = 4;
-    quoted_value = data_to_ascii(tmp_buf, 4, vk->type);
+    quoted_value = data_to_ascii(tmp_buf, 4, vk->type, &conv_error);
   }
   else
@@ -461,5 +484,6 @@
     }
 
-    quoted_value = data_to_ascii(vk->data, vk->data_size, vk->type);
+    quoted_value = data_to_ascii(vk->data, vk->data_size, 
+				 vk->type, &conv_error);
   }
   
@@ -469,4 +493,19 @@
    */
   quoted_name = quote_string(vk->valuename, common_special_chars);
+
+  if(quoted_value == NULL)
+  {
+    if(conv_error == NULL)
+      fprintf(stderr, "ERROR: Could not quote value for '%s/%s'.  "
+	      "Memory allocation failure likely.\n", prefix, quoted_name);
+    else
+      fprintf(stderr, "ERROR: Could not quote value for '%s/%s'.  "
+	      "Returned error: %s\n", prefix, quoted_name, conv_error);
+  }
+  /* XXX: should these always be printed? */
+  else if(conv_error != NULL && print_verbose)
+      fprintf(stderr, "VERBOSE: While quoting value for '%s/%s', "
+	      "warning returned: %s\n", prefix, quoted_name, conv_error);
+
   if(print_security)
     printf("%s/%s,%s,%s,,,,,\n", prefix, quoted_name,
@@ -480,4 +519,6 @@
   if(quoted_name != NULL)
     free(quoted_name);
+  if(conv_error != NULL)
+    free(conv_error);
 }
 
@@ -752,5 +793,4 @@
 	  " [-p <PATH_FILTER>] [-t <TYPE_FILTER>]"
 	  " <REGISTRY_FILE>\n");
-  /* XXX: replace version string with Subversion property? */
   fprintf(stderr, "Version: 0.3.0\n");
   fprintf(stderr, "Options:\n");
