Index: trunk/include/regfio.h
===================================================================
--- trunk/include/regfio.h	(revision 59)
+++ trunk/include/regfio.h	(revision 61)
@@ -6,5 +6,5 @@
  * Windows NT registry I/O library
  *
- * Copyright (C) 2005 Timothy D. Morgan
+ * Copyright (C) 2005-2006 Timothy D. Morgan
  * Copyright (C) 2005 Gerald (Jerry) Carter
  *
@@ -67,8 +67,4 @@
 #define REG_KEY                        255
 
-typedef struct _val_str { 
-  unsigned int val;
-  const char * str;
-} VAL_STR;
 
 #define REGF_BLOCKSIZE		0x1000
Index: trunk/lib/regfio.c
===================================================================
--- trunk/lib/regfio.c	(revision 59)
+++ trunk/lib/regfio.c	(revision 61)
@@ -6,5 +6,5 @@
  * Windows NT registry I/O library
  *
- * Copyright (C) 2005 Timothy D. Morgan
+ * Copyright (C) 2005-2006 Timothy D. Morgan
  * Copyright (C) 2005 Gerald (Jerry) Carter
  *
@@ -28,21 +28,9 @@
 
 
-
 /* Registry types mapping */
-const VAL_STR reg_type_names[] = 
-{
-  { REG_SZ,                        "SZ"           },
-  { REG_EXPAND_SZ,                 "EXPAND_SZ"    },
-  { REG_BINARY,                    "BINARY"       },
-  { REG_DWORD,                     "DWORD"        },
-  { REG_DWORD_BE,                  "DWORD_BE"     },
-  { REG_LINK,                      "LINK"         },
-  { REG_MULTI_SZ,                  "MULTI_SZ"     },
-  { REG_RESOURCE_LIST,             "RSRC_LIST"    },
-  { REG_FULL_RESOURCE_DESCRIPTOR,  "RSRC_DESC"    },
-  { REG_RESOURCE_REQUIREMENTS_LIST,"RSRC_REQ_LIST"},
-  { REG_KEY,                       "KEY"          },
-  { 0,                             NULL           },
-};
+const unsigned int regfio_num_reg_types = 11;
+static const char* regfio_type_names[] =
+  {"NONE", "SZ", "EXPAND_SZ", "BINARY", "DWORD", "DWORD_BE", "LINK"
+   "MULTI_SZ", "RSRC_LIST", "RSRC_DESC", "RSRC_REQ_LIST"};
 
 
@@ -50,24 +38,30 @@
 const char* regfio_type_val2str(unsigned int val)
 {
+  if(val == REG_KEY)
+    return "KEY";
+  
+  if(val >= regfio_num_reg_types)
+    return NULL;
+  
+  return regfio_type_names[val];
+}
+
+
+/* Returns -1 on error */
+int regfio_type_str2val(const char* str)
+{
   int i;
 
-  for(i=0; reg_type_names[i].val && reg_type_names[i].str; i++)
-    if (reg_type_names[i].val == val) 
-      return reg_type_names[i].str;
-
-  return NULL;
-}
-
-
-/* Returns 0 on error */
-int regfio_type_str2val(const char* str)
-{
-  int i;
-
-  for(i=0; reg_type_names[i].val && reg_type_names[i].str; i++) 
-    if (strcmp(reg_type_names[i].str, str) == 0) 
-      return reg_type_names[i].val;
-
-  return 0;
+  if(strcmp("KEY", str) == 0)
+    return REG_KEY;
+
+  for(i=0; i < regfio_num_reg_types; i++)
+    if (strcmp(regfio_type_names[i], str) == 0) 
+      return i;
+
+  if(strcmp("DWORD_LE", str) == 0)
+    return REG_DWORD_LE;
+
+  return -1;
 }
 
@@ -182,9 +176,11 @@
   char* perms_str;
   char* sid_str;
+  char* ace_delim = "";
   char* ret_val = NULL;
-  char* ace_delim = "";
+  char* tmp_val = NULL;
+  bool failed = false;
   char field_delim = ':';
 
-  for (i = 0; i < acl->num_aces; i++)
+  for (i = 0; i < acl->num_aces && !failed; i++)
   {
     sid_str = regfio_sid2str(&acl->ace[i].trustee);
@@ -193,23 +189,37 @@
     flags_str = regfio_ace_flags2str(acl->ace[i].flags);
     
-    if(flags_str == NULL || perms_str == NULL 
-       || type_str == NULL || sid_str == NULL)
-      return NULL;
-
-    /* XXX: this is slow */
-    extra = strlen(sid_str) + strlen(type_str) 
-          + strlen(perms_str) + strlen(flags_str)+5;
-    ret_val = realloc(ret_val, size+extra);
-    if(ret_val == NULL)
-      return NULL;
-    size += snprintf(ret_val+size, extra, "%s%s%c%s%c%s%c%s",
-		     ace_delim,sid_str,
-		     field_delim,type_str,
-		     field_delim,perms_str,
-		     field_delim,flags_str);
-    ace_delim = "|";
-    free(sid_str);
-    free(perms_str);
-    free(flags_str);
+    if(flags_str != NULL && perms_str != NULL 
+       && type_str != NULL && sid_str != NULL)
+    {
+      /* XXX: this is slow */
+      extra = strlen(sid_str) + strlen(type_str) 
+	+ strlen(perms_str) + strlen(flags_str)+5;
+      tmp_val = realloc(ret_val, size+extra);
+
+      if(tmp_val == NULL)
+      {
+	free(ret_val);
+	failed = true;
+      }
+      else
+      {
+	ret_val = tmp_val;
+	size += snprintf(ret_val+size, extra, "%s%s%c%s%c%s%c%s",
+			 ace_delim,sid_str,
+			 field_delim,type_str,
+			 field_delim,perms_str,
+			 field_delim,flags_str);
+	ace_delim = "|";
+      }
+    }
+    else
+      failed = true;
+
+    if(sid_str != NULL)
+      free(sid_str);
+    if(sid_str != NULL)
+      free(perms_str);
+    if(sid_str != NULL)
+      free(flags_str);
   }
 
@@ -254,4 +264,5 @@
 		       uint32 block_size )
 {
+  const int hdr_size = 0x20;
   int bytes_read, returned;
   char *buffer;
@@ -279,8 +290,18 @@
     }
 
-    returned = read( file->fd, hdr, 0x20 );
-    if ( (returned == -1) || (returned < 0x20) ) {
-      /*DEBUG(0,("read_block: failed to read in HBIN header. Is the file corrupt?\n"));*/
-      return -1;
+    bytes_read = returned = 0;
+    while (bytes_read < hdr_size)
+    {
+      returned = read(file->fd, hdr + bytes_read, hdr_size - bytes_read);
+      if(returned == -1 && errno != EINTR && errno != EAGAIN)
+      {
+	/*DEBUG(0,("read_block: read of hdr failed (%s)\n",strerror(errno)));*/
+	return -1;
+      }
+
+      if(returned == 0)
+	return -1;
+
+      bytes_read += returned;
     }
 
@@ -310,14 +331,15 @@
   while ( bytes_read < block_size ) 
   {
-    if((returned = 
-	read(file->fd, buffer+bytes_read, block_size-bytes_read)) == -1)
+    returned = read(file->fd, buffer+bytes_read, block_size-bytes_read);
+    if(returned == -1 && errno != EINTR && errno != EAGAIN)
     {
       /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
-      return false;
-    }
+      return -1;
+    }
+
     if ((returned == 0) && (bytes_read < block_size)) 
     {
       /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
-      return false;
+      return -1;
     }	
 
Index: trunk/src/reglookup.c
===================================================================
--- trunk/src/reglookup.c	(revision 59)
+++ trunk/src/reglookup.c	(revision 61)
@@ -3,5 +3,5 @@
  * Gerald Carter''s regfio interface.
  *
- * Copyright (C) 2005 Timothy D. Morgan
+ * Copyright (C) 2005-2006 Timothy D. Morgan
  * Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com
  *
@@ -28,4 +28,5 @@
 #include <strings.h>
 #include <time.h>
+#include <iconv.h>
 #include "../include/regfio.h"
 #include "../include/void_stack.h"
@@ -43,4 +44,6 @@
 /* Other globals */
 const char* special_chars = ",\"\\";
+iconv_t conv_desc;
+
 
 void bailOut(int code, char* message)
@@ -54,5 +57,5 @@
  * except for non-printable or special characters are quoted in hex
  * with the syntax '\xQQ' where QQ is the hex ascii value of the quoted
- * character.  A null terminator is added, as only ascii, not binary, 
+ * character.  A null terminator is added, since only ascii, not binary,
  * is returned.
  */
@@ -60,8 +63,10 @@
 			  unsigned int len, const char* special)
 {
-  unsigned int i;
-  unsigned int num_written=0;
-  unsigned int out_len = sizeof(char)*len+1;
-  char* ret_val = malloc(out_len);
+  unsigned int i, added_len;
+  unsigned int num_written = 0;
+
+  unsigned int buf_len = sizeof(char)*(len+1);
+  char* ret_val = malloc(buf_len);
+  char* tmp_buf;
 
   if(ret_val == NULL)
@@ -70,12 +75,34 @@
   for(i=0; i<len; i++)
   {
+    if(buf_len <= (num_written+5))
+    {
+      /* Expand the buffer by the memory consumption rate seen so far 
+       * 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.
+       */
+      added_len = (len-i)*num_written/(i+1);
+      if((buf_len+added_len) > (len*4+1))
+	buf_len = len*4+1;
+      else
+      {
+	if (added_len < 5)
+	  buf_len += 5;
+	else
+	  buf_len += added_len;
+      }
+
+      tmp_buf = realloc(ret_val, buf_len);
+      if(tmp_buf == NULL)
+      {
+	free(ret_val);
+	return NULL;
+      }
+      ret_val = tmp_buf;
+    }
+    
     if(str[i] < 32 || str[i] > 126 || strchr(special, str[i]) != NULL)
     {
-      out_len += 3;
-      /* XXX: may not be the most efficient way of getting enough memory. */
-      ret_val = realloc(ret_val, out_len);
-      if(ret_val == NULL)
-	break;
-      num_written += snprintf(ret_val+num_written, (out_len)-num_written,
+      num_written += snprintf(ret_val + num_written, buf_len - num_written,
 			      "\\x%.2X", str[i]);
     }
@@ -107,21 +134,25 @@
 
 /*
- * Convert from UniCode to Ascii ... Does not take into account other lang
- * Restrict by ascii_max if > 0
+ * Convert from Unicode to ASCII.
  */
-static int uni_to_ascii(unsigned char *uni, unsigned char *ascii, 
-			int ascii_max, int uni_max)
-{
-  int i = 0; 
-
-  while (i < ascii_max && (uni[i*2] || uni[i*2+1]))
-  {
-    if (uni_max > 0 && (i*2) >= uni_max) break;
-    ascii[i] = uni[i*2];
-    i++;
-  }
-  ascii[i] = '\0';
-
-  return i;
+static int uni_to_ascii(unsigned char* uni, char* ascii, 
+			unsigned int uni_max, unsigned int ascii_max)
+{
+  char* inbuf = (char*)uni;
+  char* outbuf = ascii;
+  int ret;
+
+  /* Set up conversion descriptor. */
+  conv_desc = iconv_open("US-ASCII", "UTF-16LE");
+
+  ret = iconv(conv_desc, &inbuf, &uni_max, &outbuf, &ascii_max);
+  if(ret == -1)
+  {
+    iconv_close(conv_desc);
+    return -1;
+  }
+
+  iconv_close(conv_desc);  
+  return strlen(ascii);
 }
 
@@ -130,12 +161,12 @@
  * Convert a data value to a string for display
  */
-static unsigned char* data_to_ascii(unsigned char *datap, int len, int type)
-{
-  unsigned char *asciip;
+static char* data_to_ascii(unsigned char *datap, int len, int type)
+{
+  char* asciip;
   unsigned int i;
   unsigned short num_nulls;
-  unsigned char* ascii;
+  char* ascii;
   unsigned char* cur_str;
-  unsigned char* cur_ascii;
+  char* cur_ascii;
   char* cur_quoted;
   unsigned int cur_str_len;
@@ -145,4 +176,6 @@
   switch (type) 
   {
+    /* REG_LINK is a symbolic link, stored as a unicode string. */
+  case REG_LINK:
   case REG_SZ:
     ascii_max = sizeof(char)*len;
@@ -151,11 +184,17 @@
       return NULL;
     
-    /* XXX: This has to be fixed. It has to be UNICODE */
-    uni_to_ascii(datap, ascii, len, ascii_max);
-    cur_quoted = quote_string((char*)ascii, special_chars);
+    if(uni_to_ascii(datap, ascii, len, ascii_max) < 0)
+    {
+      free(ascii);
+      return NULL;
+    }
+    cur_quoted = quote_string(ascii, special_chars);
     free(ascii);
-    return (unsigned char*)cur_quoted;
+    return cur_quoted;
     break;
 
+    /* XXX: This could be Unicode or ASCII.  Are we processing it 
+     *      correctly in both cases? 
+     */
   case REG_EXPAND_SZ:
     ascii_max = sizeof(char)*len;
@@ -164,8 +203,12 @@
       return NULL;
 
-    uni_to_ascii(datap, ascii, len, ascii_max);
-    cur_quoted = quote_string((char*)ascii, special_chars);
+    if(uni_to_ascii(datap, ascii, len, ascii_max) < 0)
+    {
+      free(ascii);
+      return NULL;
+    }
+    cur_quoted = quote_string(ascii, special_chars);
     free(ascii);
-    return (unsigned char*)cur_quoted;
+    return cur_quoted;
     break;
 
@@ -176,5 +219,5 @@
       return NULL;
 
-    snprintf((char*)ascii, ascii_max, "0x%.2X%.2X%.2X%.2X", 
+    snprintf(ascii, ascii_max, "0x%.2X%.2X%.2X%.2X", 
 	     datap[0], datap[1], datap[2], datap[3]);
     return ascii;
@@ -187,5 +230,5 @@
       return NULL;
 
-    snprintf((char*)ascii, ascii_max, "0x%.2X%.2X%.2X%.2X", 
+    snprintf(ascii, ascii_max, "0x%.2X%.2X%.2X%.2X", 
 	     datap[3], datap[2], datap[1], datap[0]);
     return ascii;
@@ -226,7 +269,14 @@
       if(num_nulls == 2)
       {
-	uni_to_ascii(cur_str, cur_ascii, cur_str_max, 0);
-	cur_quoted = quote_string((char*)cur_ascii, ",|\"\\");
-	alen = snprintf((char*)asciip, str_rem, "%s", cur_quoted);
+	if(uni_to_ascii(cur_str, cur_ascii, cur_str_max, cur_str_max) < 0)
+	{
+	  free(ascii);
+	  free(cur_ascii);
+	  free(cur_str);
+	  return NULL;
+	}
+
+	cur_quoted = quote_string(cur_ascii, ",|\"\\");
+	alen = snprintf(asciip, str_rem, "%s", cur_quoted);
 	asciip += alen;
 	str_rem -= alen;
@@ -237,7 +287,11 @@
 	else
 	{
-	  alen = snprintf((char*)asciip, str_rem, "%c", '|');
-	  asciip += alen;
-	  str_rem -= alen;
+	  if(str_rem > 0)
+	  {
+	    asciip[0] = '|';
+	    asciip[1] = '\0';
+	    asciip++;
+	    str_rem--;
+	  }
 	  memset(cur_str, 0, cur_str_max);
 	  cur_str_len = 0;
@@ -255,4 +309,5 @@
 
   /* XXX: Dont know what to do with these yet, just print as binary... */
+  case REG_NONE:
   case REG_RESOURCE_LIST:
   case REG_FULL_RESOURCE_DESCRIPTOR:
@@ -260,5 +315,5 @@
 
   case REG_BINARY:
-    return (unsigned char*)quote_buffer(datap, len, special_chars);
+    return quote_buffer(datap, len, special_chars);
     break;
 
@@ -369,5 +424,5 @@
   uint32 size;
   uint8 tmp_buf[4];
-  unsigned char* quoted_value;
+  char* quoted_value;
   char* quoted_prefix;
   char* quoted_name;
@@ -397,4 +452,5 @@
       size = 16384;
     }
+
     quoted_value = data_to_ascii(vk->data, vk->data_size, vk->type);
   }
@@ -443,5 +499,10 @@
   time_t tmp_time[1];
   struct tm* tmp_time_s = NULL;
-
+  char* quoted_path = NULL;
+
+  /* XXX: it would be faster to always pass a quoted string to this
+   *      function, instead of re-quoting it every call. */
+  /* XXX: check return of quote_string */
+  quoted_path = quote_string(full_path, special_chars);
   *tmp_time = nt_time_to_unix(&k->mtime);
   tmp_time_s = gmtime(tmp_time);
@@ -463,5 +524,5 @@
       dacl = empty_str;
 
-    printf("%s,KEY,,%s,%s,%s,%s,%s\n", full_path, mtime, 
+    printf("%s,KEY,,%s,%s,%s,%s,%s\n", quoted_path, mtime, 
 	   owner, group, sacl, dacl);
 
@@ -476,5 +537,7 @@
   }
   else
-    printf("%s,KEY,,%s\n", full_path, mtime);
+    printf("%s,KEY,,%s\n", quoted_path, mtime);
+
+  free(quoted_path);
 }
 
@@ -673,9 +736,9 @@
 static void usage(void)
 {
-  fprintf(stderr, "Usage: readreg [-v] [-s]"
+  fprintf(stderr, "Usage: reglookup [-v] [-s]"
 	  " [-p <PATH_FILTER>] [-t <TYPE_FILTER>]"
 	  " <REGISTRY_FILE>\n");
   /* XXX: replace version string with Subversion property? */
-  fprintf(stderr, "Version: 0.2.2\n");
+  fprintf(stderr, "Version: 0.3.0\n");
   fprintf(stderr, "Options:\n");
   fprintf(stderr, "\t-v\t sets verbose mode.\n");
@@ -728,10 +791,9 @@
 	bailOut(1, "ERROR: '-t' option requires parameter.\n");
       }
-      if((type_filter = regfio_type_str2val(argv[argi])) == 0)
+      if((type_filter = regfio_type_str2val(argv[argi])) < 0)
       {
 	fprintf(stderr, "ERROR: Invalid type specified: %s.\n", argv[argi]);
 	bailOut(1, "");
       }
-
       type_filter_enabled = true;
     }
