Reading Win 2000 registry files

Phillip J Shelton phillips at yourisp.com.au
Sat Jul 15 00:14:33 CDT 2006


Win 2000 registry files are in UCF16 while fgets and fgetc only read single 
byte characters. Thus EOF is returned at the high order byte of the first 
ASCII character. Thus the file is not read.

Added wrappers for fgets and fgetc to allow regedit to read files from win 
2000.

I am not sure about what should be the name of the old file. The file is 
programs/regedit/regproc.c

--- regproc.c.old	2006-06-20 06:16:30.000000000 +1000
+++ regproc.c	2006-07-01 06:54:12.000000000 +1000
@@ -4,6 +4,7 @@
  *
  * Copyright 1999 Sylvain St-Germain
  * Copyright 2002 Andriy Palamarchuk
+ * Copyright 2006 Phillip Shelton
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -27,6 +28,11 @@
 #include <winreg.h>
 #include <assert.h>
 #include "regproc.h"
+/*#include <string.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <stddef.h>
+*/
 
 #define REG_VAL_BUF_SIZE        4096
 
@@ -867,6 +873,132 @@
 }
 
 /******************************************************************************
+ * Wrapper for reading a line from a file.
+ * Will read both Windows 2000 (UCF-16) and ASCII files.
+ *
+ * Parameters:
+ * s - pointer to the buffer to read into
+ * count - size of the buffer s points to
+ * stream - the input stream to read from
+ */
+char * fgetstr (char *s, int count, FILE *stream){
+/* Can not use fgetwc() as we need to read file with fgetc() first and do
+   not know the name of the file at this point. therefore can not use 
freopen()
+   to reset the orientation of the file. */
+    wint_t readchar;
+    char mbchar[MB_LEN_MAX],*linept;
+    static int bom;
+    int len,linelen;
+    unsigned char hob,lob;
+    size_t fp[2];
+    int tic;
+
+    tic=0;
+    linept=s;
+    linelen=0;
+    if (count==1){
+        *s='\0';
+        return s;
+    }
+    if (!ftell(stream)){
+        if (!fread(&lob,sizeof (char),1,stream))return NULL;
+        if (!fread(&hob,sizeof (char),1,stream)){
+            *s=lob;
+            *++linept=='\0';
+            return NULL;
+        }
+        if ((lob==0xff)&&(hob==0xfe)){
+            bom=1;
+        }else if((lob==0xfe)&&(hob==0xff)){
+            bom=0;
+        }else{
+            bom=-1;
+            *linept++=lob;
+            if (count==2){
+                *linept='\0';
+                ungetc(hob,stream);
+                return s;
+            }else if (count==3){
+                *linept++=hob;
+                *linept='\0';
+                return s;
+            }else{
+                count-=2;
+                *linept++=hob;
+                linept=fgets(linept,count,stream);
+                return (linept==NULL)?NULL:s;
+            }
+        }
+    }
+    fp[tic]=ftell(stream);
+    tic=1-tic;
+    do{
+        if (bom==1){
+            if (!fread(&lob,sizeof (char),1,stream))return NULL;
+            if ((fp[tic]=ftell(stream))==(fp[1-tic]+2)){
+                /* The file has been opened in text mode and fread is doing
+                   end of line character translations.
+                   assuming that '\r' is the same in all locals
+                   and there is only ever one at a time */
+                if (!fread(&lob,sizeof (char),1,stream))return NULL;
+                fp[tic]+=1;
+            }   
+            tic=1-tic;
+            if (!fread(&hob,sizeof (char),1,stream))return NULL;
+            if ((fp[tic]=ftell(stream))==(fp[1-tic]+2)){
+                ungetc(hob,stream);
+                hob=0x0d;
+                fp[tic]-=1;
+            }   
+            tic=1-tic;
+        }else if(bom==0){
+            if (!fread(&hob,sizeof (char),1,stream))return NULL;
+            if ((fp[tic]=ftell(stream))==(fp[1-tic]+2)){
+                ungetc(hob,stream);
+                hob=0x0d;
+                fp[tic]-=1;
+            }   
+            tic=1-tic;
+            if (!fread(&lob,sizeof (char),1,stream))return NULL;
+            if ((fp[tic]=ftell(stream))==(fp[1-tic]+2)){
+                 /* assuming that '\r' is the same in all locals */
+                hob=lob;
+                if (!fread(&lob,sizeof (char),1,stream))return NULL;
+                fp[tic]+=1;
+            }   
+            tic=1-tic;
+        }else{
+            return fgets(s,(count<1)?2:count,stream);
+        }
+        readchar=hob;
+        readchar<<=8;
+        readchar+=lob;
+        len=wctomb(mbchar,readchar);
+        if (readchar!=L'\r'){
+            memcpy(linept,mbchar,len);
+            linelen+=len;
+            linept+=len;
+        }
+    }while((readchar!=L'\n')&&(linelen<(count-MB_LEN_MAX))&&(count>1));
+    *linept='\0';
+    return s;
+}
+
+/******************************************************************************
+ * Wrapper for reading a char from a file.
+ * Will read both Windows 2000 (UCF-16) and ASCII files.
+ *
+ * Parameters:
+ * stream - the input stream to read from
+ */
+int fgetcha(FILE *stream){
+    char mbchar[MB_LEN_MAX+1],*linept;
+
+    linept=fgetstr(mbchar,-1,stream);
+    return (linept==NULL)?EOF:*linept;
+}
+
+/******************************************************************************
  * Calls command for each line of a registry file.
  * Correctly processes comments (in # form), line continuation.
  *
@@ -893,7 +1025,7 @@
             /* Do we need to expand the buffer ? */
             assert (s >= line && s <= line + lineSize);
             size_remaining = lineSize - (s-line);
-            if (size_remaining < 2) /* room for 1 character and the \0 */
+            if (size_remaining < (MB_LEN_MAX+1)) /* room for 1 character and 
the \0 */
             {
                 char *new_buffer;
                 size_t new_size = lineSize + REG_VAL_BUF_SIZE;
@@ -912,7 +1044,7 @@
              * eof, error, eol or getting the maximum amount.  Abort on 
error.
              */
             size_to_get = (size_remaining > INT_MAX ? INT_MAX : 
size_remaining);
-            if (NULL == fgets (s, size_to_get, in)) {
+            if (NULL == fgetstr (s, size_to_get, in)) {
                 if (ferror(in)) {
                     perror ("While reading input");
                     exit (IO_ERROR);
@@ -935,7 +1067,7 @@
             }
 
             /* If it is a comment line then discard it and go around again */
-            if (line [0] == '#') {
+            if ((line [0] == '#')||(!strcmp(line,"Windows Registry Editor 
Version 5.00\n"))) {
                 s = line;
                 continue;
             }
@@ -944,6 +1076,7 @@
             if (s_eol) {
                 *s_eol = '\0';
                 if (s_eol > line && *(s_eol-1) == '\r')
+                    /* This should never happen as the file I/O removes it 
for us. */
                     *--s_eol = '\0';
             } else
                 s_eol = strchr (s, '\0');
@@ -955,8 +1088,8 @@
                 /* The following error protection could be made more self-
                  * correcting but I thought it not worth trying.
                  */
-                if ((c = fgetc (in)) == EOF || c != ' ' ||
-                        (c = fgetc (in)) == EOF || c != ' ')
+                if ((c = fgetcha (in)) == EOF || c != ' ' ||
+                        (c = fgetcha (in)) == EOF || c != ' ')
                     fprintf(stderr,"%s: ERROR - invalid continuation.\n",
                             getAppName());
                 continue;



More information about the wine-patches mailing list