ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

regproc.c
Go to the documentation of this file.
00001 /*
00002  * Registry processing routines. Routines, common for registry
00003  * processing frontends.
00004  *
00005  * Copyright 1999 Sylvain St-Germain
00006  * Copyright 2002 Andriy Palamarchuk
00007  * Copyright 2008 Alexander N. S?rnes <alex@thehandofagony.com>
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00022  */
00023 
00024 #include "regedit.h"
00025 
00026 #define REG_VAL_BUF_SIZE        4096
00027 
00028 /* maximal number of characters in hexadecimal data line,
00029  * including the indentation, but not including the '\' character
00030  */
00031 #define REG_FILE_HEX_LINE_LEN   (2 + 25 * 3)
00032 
00033 static const CHAR *reg_class_names[] =
00034 {
00035     "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CLASSES_ROOT",
00036     "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA"
00037 };
00038 
00039 #define REG_CLASS_NUMBER (sizeof(reg_class_names) / sizeof(reg_class_names[0]))
00040 
00041 const WCHAR* reg_class_namesW[REG_CLASS_NUMBER] =
00042 {
00043     L"HKEY_LOCAL_MACHINE", L"HKEY_USERS", L"HKEY_CLASSES_ROOT",
00044     L"HKEY_CURRENT_CONFIG", L"HKEY_CURRENT_USER", L"HKEY_DYN_DATA"
00045 };
00046 
00047 static HKEY reg_class_keys[REG_CLASS_NUMBER] =
00048 {
00049     HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
00050     HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA
00051 };
00052 
00053 /* return values */
00054 #define NOT_ENOUGH_MEMORY     1
00055 #define IO_ERROR              2
00056 
00057 /* processing macros */
00058 
00059 /* common check of memory allocation results */
00060 #define CHECK_ENOUGH_MEMORY(p) \
00061 if (!(p)) \
00062 { \
00063     fprintf(stderr,"%s: file %s, line %d: Not enough memory\n", \
00064             getAppName(), __FILE__, __LINE__); \
00065     exit(NOT_ENOUGH_MEMORY); \
00066 }
00067 
00068 /******************************************************************************
00069  * Allocates memory and converts input from multibyte to wide chars
00070  * Returned string must be freed by the caller
00071  */
00072 WCHAR* GetWideString(const char* strA)
00073 {
00074     if(strA)
00075     {
00076         WCHAR* strW;
00077         int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0);
00078 
00079         strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
00080         CHECK_ENOUGH_MEMORY(strW);
00081         MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len);
00082         return strW;
00083     }
00084     return NULL;
00085 }
00086 
00087 /******************************************************************************
00088  * Allocates memory and converts input from multibyte to wide chars
00089  * Returned string must be freed by the caller
00090  */
00091 static WCHAR* GetWideStringN(const char* strA, int chars, DWORD *len)
00092 {
00093     if(strA)
00094     {
00095         WCHAR* strW;
00096         *len = MultiByteToWideChar(CP_ACP, 0, strA, chars, NULL, 0);
00097 
00098         strW = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(WCHAR));
00099         CHECK_ENOUGH_MEMORY(strW);
00100         MultiByteToWideChar(CP_ACP, 0, strA, chars, strW, *len);
00101         return strW;
00102     }
00103     *len = 0;
00104     return NULL;
00105 }
00106 
00107 /******************************************************************************
00108  * Allocates memory and converts input from wide chars to multibyte
00109  * Returned string must be freed by the caller
00110  */
00111 char* GetMultiByteString(const WCHAR* strW)
00112 {
00113     if(strW)
00114     {
00115         char* strA;
00116         int len = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL);
00117 
00118         strA = HeapAlloc(GetProcessHeap(), 0, len);
00119         CHECK_ENOUGH_MEMORY(strA);
00120         WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, len, NULL, NULL);
00121         return strA;
00122     }
00123     return NULL;
00124 }
00125 
00126 /******************************************************************************
00127  * Allocates memory and converts input from wide chars to multibyte
00128  * Returned string must be freed by the caller
00129  */
00130 static char* GetMultiByteStringN(const WCHAR* strW, int chars, DWORD* len)
00131 {
00132     if(strW)
00133     {
00134         char* strA;
00135         *len = WideCharToMultiByte(CP_ACP, 0, strW, chars, NULL, 0, NULL, NULL);
00136 
00137         strA = HeapAlloc(GetProcessHeap(), 0, *len);
00138         CHECK_ENOUGH_MEMORY(strA);
00139         WideCharToMultiByte(CP_ACP, 0, strW, chars, strA, *len, NULL, NULL);
00140         return strA;
00141     }
00142     *len = 0;
00143     return NULL;
00144 }
00145 
00146 /******************************************************************************
00147  * Converts a hex representation of a DWORD into a DWORD.
00148  */
00149 static BOOL convertHexToDWord(WCHAR* str, DWORD *dw)
00150 {
00151     char buf[9];
00152     char dummy;
00153 
00154     WideCharToMultiByte(CP_ACP, 0, str, -1, buf, 9, NULL, NULL);
00155     if (lstrlenW(str) > 8 || sscanf(buf, "%lx%c", dw, &dummy) != 1)
00156     {
00157         fprintf(stderr,"%s: ERROR, invalid hex value\n", getAppName());
00158         return FALSE;
00159     }
00160     return TRUE;
00161 }
00162 
00163 /******************************************************************************
00164  * Converts a hex comma separated values list into a binary string.
00165  */
00166 static BYTE* convertHexCSVToHex(WCHAR *str, DWORD *size)
00167 {
00168     WCHAR *s;
00169     BYTE *d, *data;
00170 
00171     /* The worst case is 1 digit + 1 comma per byte */
00172     *size=(lstrlenW(str)+1)/2;
00173     data=HeapAlloc(GetProcessHeap(), 0, *size);
00174     CHECK_ENOUGH_MEMORY(data);
00175 
00176     s = str;
00177     d = data;
00178     *size=0;
00179     while (*s != '\0')
00180     {
00181         UINT wc;
00182         WCHAR *end;
00183 
00184         wc = wcstoul(s,&end, 16);
00185         if (end == s || wc > 0xff || (*end && *end != L','))
00186         {
00187             char* strA = GetMultiByteString(s);
00188             fprintf(stderr,"%s: ERROR converting CSV hex stream. Invalid value at '%s'\n",
00189                     getAppName(), strA);
00190             HeapFree(GetProcessHeap(), 0, data);
00191             HeapFree(GetProcessHeap(), 0, strA);
00192             return NULL;
00193         }
00194         *d++ =(BYTE)wc;
00195         (*size)++;
00196         if (*end) end++;
00197         s = end;
00198     }
00199 
00200     return data;
00201 }
00202 
00203 /******************************************************************************
00204  * This function returns the HKEY associated with the data type encoded in the
00205  * value.  It modifies the input parameter (key value) in order to skip this
00206  * "now useless" data type information.
00207  *
00208  * Note: Updated based on the algorithm used in 'server/registry.c'
00209  */
00210 static DWORD getDataType(LPWSTR *lpValue, DWORD* parse_type)
00211 {
00212     struct data_type
00213     {
00214         const WCHAR *tag;
00215         int len;
00216         int type;
00217         int parse_type;
00218     };
00219 
00220     static const WCHAR quote[] = {'"'};
00221     static const WCHAR str[] = {'s','t','r',':','"'};
00222     static const WCHAR str2[] = {'s','t','r','(','2',')',':','"'};
00223     static const WCHAR hex[] = {'h','e','x',':'};
00224     static const WCHAR dword[] = {'d','w','o','r','d',':'};
00225     static const WCHAR hexp[] = {'h','e','x','('};
00226 
00227     static const struct data_type data_types[] = {                   /* actual type */  /* type to assume for parsing */
00228         { quote,       1,   REG_SZ,              REG_SZ },
00229         { str,         5,   REG_SZ,              REG_SZ },
00230         { str2,        8,   REG_EXPAND_SZ,       REG_SZ },
00231         { hex,         4,   REG_BINARY,          REG_BINARY },
00232         { dword,       6,   REG_DWORD,           REG_DWORD },
00233         { hexp,        4,   -1,                  REG_BINARY },
00234         { NULL,        0,    0,                  0 }
00235     };
00236 
00237     const struct data_type *ptr;
00238     int type;
00239 
00240     for (ptr = data_types; ptr->tag; ptr++)
00241     {
00242         if (wcsncmp(ptr->tag, *lpValue, ptr->len))
00243             continue;
00244 
00245         /* Found! */
00246         *parse_type = ptr->parse_type;
00247         type=ptr->type;
00248         *lpValue+=ptr->len;
00249         if (type == -1)
00250         {
00251             WCHAR* end;
00252 
00253             /* "hex(xx):" is special */
00254             type = (int)wcstoul( *lpValue , &end, 16 );
00255             if (**lpValue=='\0' || *end!=')' || *(end+1)!=':')
00256             {
00257                 type=REG_NONE;
00258             }
00259             else
00260             {
00261                 *lpValue = end + 2;
00262             }
00263         }
00264         return type;
00265     }
00266     *parse_type=REG_NONE;
00267     return REG_NONE;
00268 }
00269 
00270 /******************************************************************************
00271  * Replaces escape sequences with the characters.
00272  */
00273 static void REGPROC_unescape_string(WCHAR* str)
00274 {
00275     int str_idx = 0;            /* current character under analysis */
00276     int val_idx = 0;            /* the last character of the unescaped string */
00277     int len = lstrlenW(str);
00278     for (str_idx = 0; str_idx < len; str_idx++, val_idx++)
00279     {
00280         if (str[str_idx] == '\\')
00281         {
00282             str_idx++;
00283             switch (str[str_idx])
00284             {
00285             case 'n':
00286                 str[val_idx] = '\n';
00287                 break;
00288             case '\\':
00289             case '"':
00290                 str[val_idx] = str[str_idx];
00291                 break;
00292             default:
00293                 fprintf(stderr,"Warning! Unrecognized escape sequence: \\%C'\n",
00294                 str[str_idx]);
00295                 str[val_idx] = str[str_idx];
00296                 break;
00297             }
00298         }
00299         else
00300         {
00301             str[val_idx] = str[str_idx];
00302         }
00303     }
00304     str[val_idx] = '\0';
00305 }
00306 
00307 static BOOL parseKeyName(LPWSTR lpKeyName, HKEY *hKey, LPWSTR *lpKeyPath)
00308 {
00309     WCHAR* lpSlash = NULL;
00310     unsigned int i, len;
00311 
00312     if (lpKeyName == NULL)
00313         return FALSE;
00314 
00315     for(i = 0; *(lpKeyName + i) != 0; i++)
00316     {
00317         if(*(lpKeyName+i) == '\\')
00318         {
00319             lpSlash = lpKeyName + i;
00320             break;
00321         }
00322     }
00323 
00324     if (lpSlash)
00325     {
00326         len = lpSlash-lpKeyName;
00327     }
00328     else
00329     {
00330         len = lstrlenW(lpKeyName);
00331         lpSlash = lpKeyName+len;
00332     }
00333     *hKey = NULL;
00334 
00335     for (i = 0; i < REG_CLASS_NUMBER; i++)
00336     {
00337         if (CompareStringW(LOCALE_USER_DEFAULT, 0, lpKeyName, len, reg_class_namesW[i], len) == CSTR_EQUAL &&
00338         len == lstrlenW(reg_class_namesW[i]))
00339         {
00340             *hKey = reg_class_keys[i];
00341             break;
00342         }
00343     }
00344 
00345     if (*hKey == NULL)
00346         return FALSE;
00347 
00348     if (*lpSlash != '\0')
00349         lpSlash++;
00350     *lpKeyPath = lpSlash;
00351     return TRUE;
00352 }
00353 
00354 /* Globals used by the setValue() & co */
00355 static LPSTR currentKeyName;
00356 static HKEY  currentKeyHandle = NULL;
00357 
00358 /******************************************************************************
00359  * Sets the value with name val_name to the data in val_data for the currently
00360  * opened key.
00361  *
00362  * Parameters:
00363  * val_name - name of the registry value
00364  * val_data - registry value data
00365  */
00366 static LONG setValue(WCHAR* val_name, WCHAR* val_data, BOOL is_unicode)
00367 {
00368     LONG res;
00369     DWORD  dwDataType, dwParseType;
00370     LPBYTE lpbData;
00371     DWORD  dwData, dwLen;
00372     WCHAR del[] = {'-',0};
00373 
00374     if ( (val_name == NULL) || (val_data == NULL) )
00375         return ERROR_INVALID_PARAMETER;
00376 
00377     if (lstrcmpW(val_data, del) == 0)
00378     {
00379         res=RegDeleteValueW(currentKeyHandle,val_name);
00380         return (res == ERROR_FILE_NOT_FOUND ? ERROR_SUCCESS : res);
00381     }
00382 
00383     /* Get the data type stored into the value field */
00384     dwDataType = getDataType(&val_data, &dwParseType);
00385 
00386     if (dwParseType == REG_SZ)          /* no conversion for string */
00387     {
00388         REGPROC_unescape_string(val_data);
00389         /* Compute dwLen after REGPROC_unescape_string because it may
00390          * have changed the string length and we don't want to store
00391          * the extra garbage in the registry.
00392          */
00393         dwLen = lstrlenW(val_data);
00394         if (dwLen>0 && val_data[dwLen-1]=='"')
00395         {
00396             dwLen--;
00397             val_data[dwLen]='\0';
00398         }
00399         lpbData = (BYTE*) val_data;
00400         dwLen++;  /* include terminating null */
00401         dwLen = dwLen * sizeof(WCHAR); /* size is in bytes */
00402     }
00403     else if (dwParseType == REG_DWORD)  /* Convert the dword types */
00404     {
00405         if (!convertHexToDWord(val_data, &dwData))
00406             return ERROR_INVALID_DATA;
00407         lpbData = (BYTE*)&dwData;
00408         dwLen = sizeof(dwData);
00409     }
00410     else if (dwParseType == REG_BINARY) /* Convert the binary data */
00411     {
00412         lpbData = convertHexCSVToHex(val_data, &dwLen);
00413         if (!lpbData)
00414             return ERROR_INVALID_DATA;
00415 
00416         if((dwDataType == REG_MULTI_SZ || dwDataType == REG_EXPAND_SZ) && !is_unicode)
00417         {
00418             LPBYTE tmp = lpbData;
00419             lpbData = (LPBYTE)GetWideStringN((char*)lpbData, dwLen, &dwLen);
00420             dwLen *= sizeof(WCHAR);
00421             HeapFree(GetProcessHeap(), 0, tmp);
00422         }
00423     }
00424     else                                /* unknown format */
00425     {
00426         fprintf(stderr,"%s: ERROR, unknown data format\n", getAppName());
00427         return ERROR_INVALID_DATA;
00428     }
00429 
00430     res = RegSetValueExW(
00431         currentKeyHandle,
00432         val_name,
00433         0,                  /* Reserved */
00434         dwDataType,
00435         lpbData,
00436         dwLen);
00437     if (dwParseType == REG_BINARY)
00438         HeapFree(GetProcessHeap(), 0, lpbData);
00439     return res;
00440 }
00441 
00442 /******************************************************************************
00443  * A helper function for processRegEntry() that opens the current key.
00444  * That key must be closed by calling closeKey().
00445  */
00446 static LONG openKeyW(WCHAR* stdInput)
00447 {
00448     HKEY keyClass;
00449     WCHAR* keyPath;
00450     DWORD dwDisp;
00451     LONG res;
00452 
00453     /* Sanity checks */
00454     if (stdInput == NULL)
00455         return ERROR_INVALID_PARAMETER;
00456 
00457     /* Get the registry class */
00458     if (!parseKeyName(stdInput, &keyClass, &keyPath))
00459         return ERROR_INVALID_PARAMETER;
00460 
00461     res = RegCreateKeyExW(
00462         keyClass,                 /* Class     */
00463         keyPath,                  /* Sub Key   */
00464         0,                        /* MUST BE 0 */
00465         NULL,                     /* object type */
00466         REG_OPTION_NON_VOLATILE,  /* option, REG_OPTION_NON_VOLATILE ... */
00467         KEY_ALL_ACCESS,           /* access mask, KEY_ALL_ACCESS */
00468         NULL,                     /* security attribute */
00469         &currentKeyHandle,        /* result */
00470         &dwDisp);                 /* disposition, REG_CREATED_NEW_KEY or
00471                                                         REG_OPENED_EXISTING_KEY */
00472 
00473     if (res == ERROR_SUCCESS)
00474         currentKeyName = GetMultiByteString(stdInput);
00475     else
00476         currentKeyHandle = NULL;
00477 
00478     return res;
00479 
00480 }
00481 
00482 /******************************************************************************
00483  * Close the currently opened key.
00484  */
00485 static void closeKey(void)
00486 {
00487     if (currentKeyHandle)
00488     {
00489         HeapFree(GetProcessHeap(), 0, currentKeyName);
00490         RegCloseKey(currentKeyHandle);
00491         currentKeyHandle = NULL;
00492     }
00493 }
00494 
00495 /******************************************************************************
00496  * This function is a wrapper for the setValue function.  It prepares the
00497  * land and cleans the area once completed.
00498  * Note: this function modifies the line parameter.
00499  *
00500  * line - registry file unwrapped line. Should have the registry value name and
00501  *      complete registry value data.
00502  */
00503 static void processSetValue(WCHAR* line, BOOL is_unicode)
00504 {
00505     WCHAR* val_name;                   /* registry value name   */
00506     WCHAR* val_data;                   /* registry value data   */
00507     int line_idx = 0;                 /* current character under analysis */
00508     LONG res;
00509 
00510     /* get value name */
00511     while ( iswspace(line[line_idx]) ) line_idx++;
00512     if (line[line_idx] == '@' && line[line_idx + 1] == '=')
00513     {
00514         line[line_idx] = '\0';
00515         val_name = line;
00516         line_idx++;
00517     }
00518     else if (line[line_idx] == '\"')
00519     {
00520         line_idx++;
00521         val_name = line + line_idx;
00522         while (TRUE)
00523         {
00524             if (line[line_idx] == '\\')   /* skip escaped character */
00525             {
00526                 line_idx += 2;
00527             }
00528             else
00529             {
00530                 if (line[line_idx] == '\"')
00531                 {
00532                     line[line_idx] = '\0';
00533                     line_idx++;
00534                     break;
00535                 }
00536                 else
00537                 {
00538                     line_idx++;
00539                 }
00540             }
00541         }
00542         while ( iswspace(line[line_idx]) ) line_idx++;
00543         if (line[line_idx] != '=')
00544         {
00545             char* lineA;
00546             line[line_idx] = '\"';
00547             lineA = GetMultiByteString(line);
00548             fprintf(stderr,"Warning! unrecognized line:\n%s\n", lineA);
00549             HeapFree(GetProcessHeap(), 0, lineA);
00550             return;
00551         }
00552 
00553     }
00554     else
00555     {
00556         char* lineA = GetMultiByteString(line);
00557         fprintf(stderr,"Warning! unrecognized line:\n%s\n", lineA);
00558         HeapFree(GetProcessHeap(), 0, lineA);
00559         return;
00560     }
00561     line_idx++;                   /* skip the '=' character */
00562 
00563     while ( iswspace(line[line_idx]) ) line_idx++;
00564     val_data = line + line_idx;
00565     /* trim trailing blanks */
00566     line_idx = lstrlenW(val_data);
00567     while (line_idx > 0 && iswspace(val_data[line_idx-1])) line_idx--;
00568     val_data[line_idx] = '\0';
00569 
00570     REGPROC_unescape_string(val_name);
00571     res = setValue(val_name, val_data, is_unicode);
00572     if ( res != ERROR_SUCCESS )
00573     {
00574         char* val_nameA = GetMultiByteString(val_name);
00575         char* val_dataA = GetMultiByteString(val_data);
00576         fprintf(stderr,"%s: ERROR Key %s not created. Value: %s, Data: %s\n",
00577         getAppName(),
00578         currentKeyName,
00579         val_nameA,
00580         val_dataA);
00581         HeapFree(GetProcessHeap(), 0, val_nameA);
00582         HeapFree(GetProcessHeap(), 0, val_dataA);
00583     }
00584 }
00585 
00586 /******************************************************************************
00587  * This function receives the currently read entry and performs the
00588  * corresponding action.
00589  * isUnicode affects parsing of REG_MULTI_SZ values
00590  */
00591 static void processRegEntry(WCHAR* stdInput, BOOL isUnicode)
00592 {
00593     /*
00594      * We encountered the end of the file, make sure we
00595      * close the opened key and exit
00596      */
00597     if (stdInput == NULL)
00598     {
00599         closeKey();
00600         return;
00601     }
00602 
00603     if ( stdInput[0] == L'[')           /* We are reading a new key */
00604     {
00605         WCHAR* keyEnd;
00606         closeKey();                     /* Close the previous key */
00607 
00608         /* Get rid of the square brackets */
00609         stdInput++;
00610         keyEnd = wcsrchr(stdInput, L']');
00611         if (keyEnd)
00612             *keyEnd='\0';
00613 
00614         /* delete the key if we encounter '-' at the start of reg key */
00615         if ( stdInput[0] == '-')
00616         {
00617             delete_registry_key(stdInput + 1);
00618         }
00619         else if ( openKeyW(stdInput) != ERROR_SUCCESS )
00620         {
00621             char* stdInputA = GetMultiByteString(stdInput);
00622             fprintf(stderr,"%s: setValue failed to open key %s\n",
00623             getAppName(), stdInputA);
00624             HeapFree(GetProcessHeap(), 0, stdInputA);
00625         }
00626     }
00627     else if( currentKeyHandle &&
00628     (( stdInput[0] == '@') || /* reading a default @=data pair */
00629     ( stdInput[0] == '\"'))) /* reading a new value=data pair */
00630     {
00631         processSetValue(stdInput, isUnicode);
00632     }
00633     else
00634     {
00635         /* Since we are assuming that the file format is valid we must be
00636          * reading a blank line which indicates the end of this key processing
00637          */
00638         closeKey();
00639     }
00640 }
00641 
00642 /******************************************************************************
00643  * Processes a registry file.
00644  * Correctly processes comments (in # form), line continuation.
00645  *
00646  * Parameters:
00647  *   in - input stream to read from
00648  */
00649 static void processRegLinesA(FILE *in)
00650 {
00651     LPSTR line           = NULL;  /* line read from input stream */
00652     ULONG lineSize       = REG_VAL_BUF_SIZE;
00653 
00654     line = HeapAlloc(GetProcessHeap(), 0, lineSize);
00655     CHECK_ENOUGH_MEMORY(line);
00656 
00657     while (!feof(in))
00658     {
00659         LPSTR s; /* The pointer into line for where the current fgets should read */
00660         LPSTR check;
00661         WCHAR* lineW;
00662         s = line;
00663 
00664         for (;;)
00665         {
00666             size_t size_remaining;
00667             int size_to_get;
00668             char *s_eol; /* various local uses */
00669 
00670             /* Do we need to expand the buffer ? */
00671             assert (s >= line && s <= line + lineSize);
00672             size_remaining = lineSize - (s-line);
00673             if (size_remaining < 2) /* room for 1 character and the \0 */
00674             {
00675                 char *new_buffer;
00676                 size_t new_size = lineSize + REG_VAL_BUF_SIZE;
00677                 if (new_size > lineSize) /* no arithmetic overflow */
00678                     new_buffer = HeapReAlloc (GetProcessHeap(), 0, line, new_size);
00679                 else
00680                     new_buffer = NULL;
00681                 CHECK_ENOUGH_MEMORY(new_buffer);
00682                 line = new_buffer;
00683                 s = line + lineSize - size_remaining;
00684                 lineSize = new_size;
00685                 size_remaining = lineSize - (s-line);
00686             }
00687 
00688             /* Get as much as possible into the buffer, terminated either by
00689              * eof, error, eol or getting the maximum amount.  Abort on error.
00690              */
00691             size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
00692 
00693             check = fgets (s, size_to_get, in);
00694 
00695             if (check == NULL)
00696             {
00697                 if (ferror(in))
00698                 {
00699                     perror ("While reading input");
00700                     exit (IO_ERROR);
00701                 }
00702                 else
00703                 {
00704                     assert (feof(in));
00705                     *s = '\0';
00706                     /* It is not clear to me from the definition that the
00707                      * contents of the buffer are well defined on detecting
00708                      * an eof without managing to read anything.
00709                      */
00710                 }
00711             }
00712 
00713             /* If we didn't read the eol nor the eof go around for the rest */
00714             s_eol = strchr (s, '\n');
00715             if (!feof (in) && !s_eol)
00716             {
00717                 s = strchr (s, '\0');
00718                 /* It should be s + size_to_get - 1 but this is safer */
00719                 continue;
00720             }
00721 
00722             /* If it is a comment line then discard it and go around again */
00723             if (line [0] == '#')
00724             {
00725                 s = line;
00726                 continue;
00727             }
00728 
00729             /* Remove any line feed.  Leave s_eol on the \0 */
00730             if (s_eol)
00731             {
00732                 *s_eol = '\0';
00733                 if (s_eol > line && *(s_eol-1) == '\r')
00734                     *--s_eol = '\0';
00735             }
00736             else
00737                 s_eol = strchr (s, '\0');
00738 
00739             /* If there is a concatenating \\ then go around again */
00740             if (s_eol > line && *(s_eol-1) == '\\')
00741             {
00742                 int c;
00743                 s = s_eol-1;
00744 
00745                 do
00746                 {
00747                     c = fgetc(in);
00748                 }
00749                 while(c == ' ' || c == '\t');
00750 
00751                 if(c == EOF)
00752                 {
00753                     fprintf(stderr,"%s: ERROR - invalid continuation.\n",
00754                     getAppName());
00755                 }
00756                 else
00757                 {
00758                     *s = c;
00759                     s++;
00760                 }
00761                 continue;
00762             }
00763 
00764             lineW = GetWideString(line);
00765 
00766             break; /* That is the full virtual line */
00767         }
00768 
00769         processRegEntry(lineW, FALSE);
00770         HeapFree(GetProcessHeap(), 0, lineW);
00771     }
00772     processRegEntry(NULL, FALSE);
00773 
00774     HeapFree(GetProcessHeap(), 0, line);
00775 }
00776 
00777 static void processRegLinesW(FILE *in)
00778 {
00779     WCHAR* buf           = NULL;  /* line read from input stream */
00780     ULONG lineSize       = REG_VAL_BUF_SIZE;
00781     size_t CharsInBuf = -1;
00782 
00783     WCHAR* s; /* The pointer into buf for where the current fgets should read */
00784     WCHAR* line; /* The start of the current line */
00785 
00786     buf = HeapAlloc(GetProcessHeap(), 0, lineSize * sizeof(WCHAR));
00787     CHECK_ENOUGH_MEMORY(buf);
00788 
00789     s = buf;
00790     line = buf;
00791 
00792     while(!feof(in))
00793     {
00794         size_t size_remaining;
00795         int size_to_get;
00796         WCHAR *s_eol = NULL; /* various local uses */
00797 
00798         /* Do we need to expand the buffer ? */
00799         assert (s >= buf && s <= buf + lineSize);
00800         size_remaining = lineSize - (s-buf);
00801         if (size_remaining < 2) /* room for 1 character and the \0 */
00802         {
00803             WCHAR *new_buffer;
00804             size_t new_size = lineSize + (REG_VAL_BUF_SIZE / sizeof(WCHAR));
00805             if (new_size > lineSize) /* no arithmetic overflow */
00806                 new_buffer = HeapReAlloc (GetProcessHeap(), 0, buf, new_size * sizeof(WCHAR));
00807             else
00808                 new_buffer = NULL;
00809             CHECK_ENOUGH_MEMORY(new_buffer);
00810             buf = new_buffer;
00811             line = buf;
00812             s = buf + lineSize - size_remaining;
00813             lineSize = new_size;
00814             size_remaining = lineSize - (s-buf);
00815         }
00816 
00817         /* Get as much as possible into the buffer, terminated either by
00818         * eof, error or getting the maximum amount.  Abort on error.
00819         */
00820         size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
00821 
00822         CharsInBuf = fread(s, sizeof(WCHAR), size_to_get - 1, in);
00823         s[CharsInBuf] = 0;
00824 
00825         if (CharsInBuf == 0)
00826         {
00827             if (ferror(in))
00828             {
00829                 perror ("While reading input");
00830                 exit (IO_ERROR);
00831             }
00832             else
00833             {
00834                 assert (feof(in));
00835                 *s = '\0';
00836                 /* It is not clear to me from the definition that the
00837                 * contents of the buffer are well defined on detecting
00838                 * an eof without managing to read anything.
00839                 */
00840             }
00841         }
00842 
00843         /* If we didn't read the eol nor the eof go around for the rest */
00844         while(1)
00845         {
00846             s_eol = wcschr(line, '\n');
00847 
00848             if(!s_eol)
00849             {
00850                 /* Move the stub of the line to the start of the buffer so
00851                  * we get the maximum space to read into, and so we don't
00852                  * have to recalculate 'line' if the buffer expands */
00853                 MoveMemory(buf, line, (lstrlenW(line) + 1) * sizeof(WCHAR));
00854                 line = buf;
00855                 s = wcschr(line, '\0');
00856                 break;
00857             }
00858 
00859             /* If it is a comment line then discard it and go around again */
00860             if (*line == '#')
00861             {
00862                 line = s_eol + 1;
00863                 continue;
00864             }
00865 
00866             /* If there is a concatenating \\ then go around again */
00867             if ((*(s_eol-1) == '\\') ||
00868             (*(s_eol-1) == '\r' && *(s_eol-2) == '\\'))
00869             {
00870                 WCHAR* NextLine = s_eol;
00871 
00872                 while(*(NextLine+1) == ' ' || *(NextLine+1) == '\t')
00873                     NextLine++;
00874 
00875                 NextLine++;
00876 
00877                 if(*(s_eol-1) == '\r')
00878                     s_eol--;
00879 
00880                 MoveMemory(s_eol - 1, NextLine, (CharsInBuf - (NextLine - s) + 1)*sizeof(WCHAR));
00881                 CharsInBuf -= NextLine - s_eol + 1;
00882                 s_eol = 0;
00883                 continue;
00884             }
00885 
00886             /* Remove any line feed.  Leave s_eol on the \0 */
00887             if (s_eol)
00888             {
00889                 *s_eol = '\0';
00890                 if (s_eol > buf && *(s_eol-1) == '\r')
00891                     *(s_eol-1) = '\0';
00892             }
00893 
00894             if(!s_eol)
00895                 break;
00896 
00897             processRegEntry(line, TRUE);
00898             line = s_eol + 1;
00899             s_eol = 0;
00900             continue; /* That is the full virtual line */
00901         }
00902     }
00903 
00904     processRegEntry(NULL, TRUE);
00905 
00906     HeapFree(GetProcessHeap(), 0, buf);
00907 }
00908 
00909 /****************************************************************************
00910  * REGPROC_print_error
00911  *
00912  * Print the message for GetLastError
00913  */
00914 
00915 static void REGPROC_print_error(void)
00916 {
00917     LPVOID lpMsgBuf;
00918     DWORD error_code;
00919     int status;
00920 
00921     error_code = GetLastError ();
00922     status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00923     NULL, error_code, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
00924     if (!status)
00925     {
00926         fprintf(stderr,"%s: Cannot display message for error %ld, status %ld\n",
00927         getAppName(), error_code, GetLastError());
00928         exit(1);
00929     }
00930     puts(lpMsgBuf);
00931     LocalFree(lpMsgBuf);
00932     exit(1);
00933 }
00934 
00935 /******************************************************************************
00936  * Checks whether the buffer has enough room for the string or required size.
00937  * Resizes the buffer if necessary.
00938  *
00939  * Parameters:
00940  * buffer - pointer to a buffer for string
00941  * len - current length of the buffer in characters.
00942  * required_len - length of the string to place to the buffer in characters.
00943  *   The length does not include the terminating null character.
00944  */
00945 static void REGPROC_resize_char_buffer(WCHAR **buffer, DWORD *len, DWORD required_len)
00946 {
00947     required_len++;
00948     if (required_len > *len)
00949     {
00950         *len = required_len;
00951         if (!*buffer)
00952             *buffer = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(**buffer));
00953         else
00954             *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *len * sizeof(**buffer));
00955         CHECK_ENOUGH_MEMORY(*buffer);
00956     }
00957 }
00958 
00959 /******************************************************************************
00960  * Same as REGPROC_resize_char_buffer() but on a regular buffer.
00961  *
00962  * Parameters:
00963  * buffer - pointer to a buffer
00964  * len - current size of the buffer in bytes
00965  * required_size - size of the data to place in the buffer in bytes
00966  */
00967 static void REGPROC_resize_binary_buffer(BYTE **buffer, DWORD *size, DWORD required_size)
00968 {
00969     if (required_size > *size)
00970     {
00971         *size = required_size;
00972         if (!*buffer)
00973             *buffer = HeapAlloc(GetProcessHeap(), 0, *size);
00974         else
00975             *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *size);
00976         CHECK_ENOUGH_MEMORY(*buffer);
00977     }
00978 }
00979 
00980 /******************************************************************************
00981  * Prints string str to file
00982  */
00983 static void REGPROC_export_string(WCHAR **line_buf, DWORD *line_buf_size, DWORD *line_len, WCHAR *str, DWORD str_len)
00984 {
00985     DWORD i, pos;
00986     DWORD extra = 0;
00987 
00988     REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + 10);
00989 
00990     /* escaping characters */
00991     pos = *line_len;
00992     for (i = 0; i < str_len; i++)
00993     {
00994         WCHAR c = str[i];
00995         switch (c)
00996         {
00997         case '\n':
00998             extra++;
00999             REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + extra);
01000             (*line_buf)[pos++] = '\\';
01001             (*line_buf)[pos++] = 'n';
01002             break;
01003 
01004         case '\\':
01005         case '"':
01006             extra++;
01007             REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + extra);
01008             (*line_buf)[pos++] = '\\';
01009             /* Fall through */
01010 
01011         default:
01012             (*line_buf)[pos++] = c;
01013             break;
01014         }
01015     }
01016     (*line_buf)[pos] = '\0';
01017     *line_len = pos;
01018 }
01019 
01020 static void REGPROC_export_binary(WCHAR **line_buf, DWORD *line_buf_size, DWORD *line_len, DWORD type, BYTE *value, DWORD value_size, BOOL unicode)
01021 {
01022     DWORD hex_pos, data_pos;
01023     const WCHAR *hex_prefix;
01024     const WCHAR hex[] = {'h','e','x',':',0};
01025     WCHAR hex_buf[17];
01026     const WCHAR concat[] = {'\\','\n',' ',' ',0};
01027     DWORD concat_prefix, concat_len;
01028     const WCHAR newline[] = {'\n',0};
01029     CHAR* value_multibyte = NULL;
01030 
01031     if (type == REG_BINARY)
01032     {
01033         hex_prefix = hex;
01034     }
01035     else
01036     {
01037         const WCHAR hex_format[] = {'h','e','x','(','%','u',')',':',0};
01038         hex_prefix = hex_buf;
01039         wsprintfW(hex_buf, hex_format, type);
01040         if ((type == REG_SZ || type == REG_EXPAND_SZ || type == REG_MULTI_SZ) && !unicode)
01041         {
01042             value_multibyte = GetMultiByteStringN((WCHAR*)value, value_size / sizeof(WCHAR), &value_size);
01043             value = (BYTE*)value_multibyte;
01044         }
01045     }
01046 
01047     concat_len = lstrlenW(concat);
01048     concat_prefix = 2;
01049 
01050     hex_pos = *line_len;
01051     *line_len += lstrlenW(hex_prefix);
01052     data_pos = *line_len;
01053     *line_len += value_size * 3;
01054     /* - The 2 spaces that concat places at the start of the
01055      *   line effectively reduce the space available for data.
01056      * - If the value name and hex prefix are very long
01057      *   ( > REG_FILE_HEX_LINE_LEN) then we may overestimate
01058      *   the needed number of lines by one. But that's ok.
01059      * - The trailing linefeed takes the place of a comma so
01060      *   it's accounted for already.
01061      */
01062     *line_len += *line_len / (REG_FILE_HEX_LINE_LEN - concat_prefix) * concat_len;
01063     REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len);
01064     lstrcpyW(*line_buf + hex_pos, hex_prefix);
01065     if (value_size)
01066     {
01067         const WCHAR format[] = {'%','0','2','x',0};
01068         DWORD i, column;
01069 
01070         column = data_pos; /* no line wrap yet */
01071         i = 0;
01072         while (1)
01073         {
01074             wsprintfW(*line_buf + data_pos, format, (unsigned int)value[i]);
01075             data_pos += 2;
01076             if (++i == value_size)
01077                 break;
01078 
01079             (*line_buf)[data_pos++] = ',';
01080             column += 3;
01081 
01082             /* wrap the line */
01083             if (column >= REG_FILE_HEX_LINE_LEN)
01084             {
01085                 lstrcpyW(*line_buf + data_pos, concat);
01086                 data_pos += concat_len;
01087                 column = concat_prefix;
01088             }
01089         }
01090     }
01091     lstrcpyW(*line_buf + data_pos, newline);
01092     HeapFree(GetProcessHeap(), 0, value_multibyte);
01093 }
01094 
01095 /******************************************************************************
01096  * Writes the given line to a file, in multi-byte or wide characters
01097  */
01098 static void REGPROC_write_line(FILE *file, const WCHAR* str, BOOL unicode)
01099 {
01100     int i;
01101     if (unicode)
01102     {
01103         for(i = 0; str[i]; i++)
01104         {
01105             if (str[i] == L'\n')
01106                 fputwc(L'\r', file);
01107             fputwc(str[i], file);
01108         }
01109     }
01110     else
01111     {
01112         char* strA = GetMultiByteString(str);
01113         fputs(strA, file);
01114         HeapFree(GetProcessHeap(), 0, strA);
01115     }
01116 }
01117 
01118 /******************************************************************************
01119  * Writes contents of the registry key to the specified file stream.
01120  *
01121  * Parameters:
01122  * file - writable file stream to export registry branch to.
01123  * key - registry branch to export.
01124  * reg_key_name_buf - name of the key with registry class.
01125  *      Is resized if necessary.
01126  * reg_key_name_size - length of the buffer for the registry class in characters.
01127  * val_name_buf - buffer for storing value name.
01128  *      Is resized if necessary.
01129  * val_name_size - length of the buffer for storing value names in characters.
01130  * val_buf - buffer for storing values while extracting.
01131  *      Is resized if necessary.
01132  * val_size - size of the buffer for storing values in bytes.
01133  */
01134 static void export_hkey(FILE *file, HKEY key,
01135 WCHAR **reg_key_name_buf, DWORD *reg_key_name_size,
01136 WCHAR **val_name_buf, DWORD *val_name_size,
01137 BYTE **val_buf, DWORD *val_size,
01138 WCHAR **line_buf, DWORD *line_buf_size,
01139 BOOL unicode)
01140 {
01141     DWORD max_sub_key_len;
01142     DWORD max_val_name_len;
01143     DWORD max_val_size;
01144     DWORD curr_len;
01145     DWORD i;
01146     BOOL more_data;
01147     LONG ret;
01148     WCHAR key_format[] = {'\n','[','%','s',']','\n',0};
01149 
01150     /* get size information and resize the buffers if necessary */
01151     if (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL,
01152     &max_sub_key_len, NULL,
01153     NULL, &max_val_name_len, &max_val_size, NULL, NULL
01154                         ) != ERROR_SUCCESS)
01155     {
01156         REGPROC_print_error();
01157     }
01158     curr_len = lstrlenW(*reg_key_name_buf);
01159     REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_size,
01160     max_sub_key_len + curr_len + 1);
01161     REGPROC_resize_char_buffer(val_name_buf, val_name_size,
01162     max_val_name_len);
01163     REGPROC_resize_binary_buffer(val_buf, val_size, max_val_size);
01164     REGPROC_resize_char_buffer(line_buf, line_buf_size, lstrlenW(*reg_key_name_buf) + 4);
01165     /* output data for the current key */
01166     wsprintfW(*line_buf, key_format, *reg_key_name_buf);
01167     REGPROC_write_line(file, *line_buf, unicode);
01168 
01169     /* print all the values */
01170     i = 0;
01171     more_data = TRUE;
01172     while(more_data)
01173     {
01174         DWORD value_type;
01175         DWORD val_name_size1 = *val_name_size;
01176         DWORD val_size1 = *val_size;
01177         ret = RegEnumValueW(key, i, *val_name_buf, &val_name_size1, NULL,
01178         &value_type, *val_buf, &val_size1);
01179         if (ret == ERROR_MORE_DATA)
01180         {
01181             /* Increase the size of the buffers and retry */
01182             REGPROC_resize_char_buffer(val_name_buf, val_name_size, val_name_size1);
01183             REGPROC_resize_binary_buffer(val_buf, val_size, val_size1);
01184         }
01185         else if (ret != ERROR_SUCCESS)
01186         {
01187             more_data = FALSE;
01188             if (ret != ERROR_NO_MORE_ITEMS)
01189             {
01190                 REGPROC_print_error();
01191             }
01192         }
01193         else
01194         {
01195             DWORD line_len;
01196             i++;
01197 
01198             if ((*val_name_buf)[0])
01199             {
01200                 const WCHAR val_start[] = {'"','%','s','"','=',0};
01201 
01202                 line_len = 0;
01203                 REGPROC_export_string(line_buf, line_buf_size, &line_len, *val_name_buf, lstrlenW(*val_name_buf));
01204                 REGPROC_resize_char_buffer(val_name_buf, val_name_size, lstrlenW(*line_buf) + 1);
01205                 lstrcpyW(*val_name_buf, *line_buf);
01206 
01207                 line_len = 3 + lstrlenW(*val_name_buf);
01208                 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len);
01209                 wsprintfW(*line_buf, val_start, *val_name_buf);
01210             }
01211             else
01212             {
01213                 const WCHAR std_val[] = {'@','=',0};
01214                 line_len = 2;
01215                 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len);
01216                 lstrcpyW(*line_buf, std_val);
01217             }
01218 
01219             switch (value_type)
01220             {
01221             case REG_SZ:
01222             {
01223                 WCHAR* wstr = (WCHAR*)*val_buf;
01224 
01225                 if (val_size1 < sizeof(WCHAR) || val_size1 % sizeof(WCHAR) ||
01226                 wstr[val_size1 / sizeof(WCHAR) - 1])
01227                 {
01228                     REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode);
01229                 }
01230                 else
01231                 {
01232                     const WCHAR start[] = {'"',0};
01233                     const WCHAR end[] = {'"','\n',0};
01234                     DWORD len;
01235 
01236                     len = lstrlenW(start);
01237                     REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + len);
01238                     lstrcpyW(*line_buf + line_len, start);
01239                     line_len += len;
01240 
01241                     /* At this point we know wstr is '\0'-terminated
01242                      * so we can substract 1 from the size
01243                      */
01244                     REGPROC_export_string(line_buf, line_buf_size, &line_len, wstr, val_size1 / sizeof(WCHAR) - 1);
01245 
01246                     REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + lstrlenW(end));
01247                     lstrcpyW(*line_buf + line_len, end);
01248                 }
01249                 break;
01250             }
01251 
01252             case REG_DWORD:
01253             {
01254                 WCHAR format[] = {'d','w','o','r','d',':','%','0','8','x','\n',0};
01255 
01256                 REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + 15);
01257                 wsprintfW(*line_buf + line_len, format, *((DWORD *)*val_buf));
01258                 break;
01259             }
01260 
01261             default:
01262             {
01263                 char* key_nameA = GetMultiByteString(*reg_key_name_buf);
01264                 char* value_nameA = GetMultiByteString(*val_name_buf);
01265                 fprintf(stderr,"%s: warning - unsupported registry format '%ld', "
01266                 "treat as binary\n",
01267                 getAppName(), value_type);
01268                 fprintf(stderr,"key name: \"%s\"\n", key_nameA);
01269                 fprintf(stderr,"value name:\"%s\"\n\n", value_nameA);
01270                 HeapFree(GetProcessHeap(), 0, key_nameA);
01271                 HeapFree(GetProcessHeap(), 0, value_nameA);
01272             }
01273             /* falls through */
01274             case REG_EXPAND_SZ:
01275             case REG_MULTI_SZ:
01276                 /* falls through */
01277             case REG_BINARY:
01278                 REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode);
01279             }
01280             REGPROC_write_line(file, *line_buf, unicode);
01281         }
01282     }
01283 
01284     i = 0;
01285     more_data = TRUE;
01286     (*reg_key_name_buf)[curr_len] = '\\';
01287     while(more_data)
01288     {
01289         DWORD buf_size = *reg_key_name_size - curr_len - 1;
01290 
01291         ret = RegEnumKeyExW(key, i, *reg_key_name_buf + curr_len + 1, &buf_size,
01292         NULL, NULL, NULL, NULL);
01293         if (ret == ERROR_MORE_DATA)
01294         {
01295             /* Increase the size of the buffer and retry */
01296             REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_size, curr_len + 1 + buf_size);
01297         }
01298         else if (ret != ERROR_SUCCESS)
01299         {
01300             more_data = FALSE;
01301             if (ret != ERROR_NO_MORE_ITEMS)
01302             {
01303                 REGPROC_print_error();
01304             }
01305         }
01306         else
01307         {
01308             HKEY subkey;
01309 
01310             i++;
01311             if (RegOpenKeyW(key, *reg_key_name_buf + curr_len + 1,
01312             &subkey) == ERROR_SUCCESS)
01313             {
01314                 export_hkey(file, subkey, reg_key_name_buf, reg_key_name_size,
01315                 val_name_buf, val_name_size, val_buf, val_size,
01316                 line_buf, line_buf_size, unicode);
01317                 RegCloseKey(subkey);
01318             }
01319             else
01320             {
01321                 REGPROC_print_error();
01322             }
01323         }
01324     }
01325     (*reg_key_name_buf)[curr_len] = '\0';
01326 }
01327 
01328 /******************************************************************************
01329  * Open file for export.
01330  */
01331 static FILE *REGPROC_open_export_file(WCHAR *file_name, BOOL unicode)
01332 {
01333     FILE *file;
01334     WCHAR dash = '-';
01335 
01336     if (wcsncmp(file_name, &dash, 1) == 0)
01337         file = stdout;
01338     else
01339     {
01340         if (unicode)
01341             file = _wfopen(file_name, L"wb");
01342         else
01343             file = _wfopen(file_name, L"w");
01344         if (!file)
01345         {
01346             CHAR* file_nameA = GetMultiByteString(file_name);
01347             perror("");
01348             fprintf(stderr,"%s: Can't open file \"%s\"\n", getAppName(), file_nameA);
01349             HeapFree(GetProcessHeap(), 0, file_nameA);
01350             exit(1);
01351         }
01352     }
01353     if (unicode)
01354     {
01355         const BYTE unicode_seq[] = {0xff,0xfe};
01356         const WCHAR header[] = L"Windows Registry Editor Version 5.00\r\n";
01357         fwrite(unicode_seq, sizeof(BYTE), COUNT_OF(unicode_seq), file);
01358         fwrite(header, sizeof(WCHAR), lstrlenW(header), file);
01359     }
01360     else
01361     {
01362         fputs("REGEDIT4\n", file);
01363     }
01364 
01365     return file;
01366 }
01367 
01368 /******************************************************************************
01369  * Writes contents of the registry key to the specified file stream.
01370  *
01371  * Parameters:
01372  * file_name - name of a file to export registry branch to.
01373  * reg_key_name - registry branch to export. The whole registry is exported if
01374  *      reg_key_name is NULL or contains an empty string.
01375  */
01376 BOOL export_registry_key(WCHAR *file_name, WCHAR *reg_key_name, DWORD format)
01377 {
01378     WCHAR *reg_key_name_buf;
01379     WCHAR *val_name_buf;
01380     BYTE *val_buf;
01381     WCHAR *line_buf;
01382     DWORD reg_key_name_size = KEY_MAX_LEN;
01383     DWORD val_name_size = KEY_MAX_LEN;
01384     DWORD val_size = REG_VAL_BUF_SIZE;
01385     DWORD line_buf_size = KEY_MAX_LEN + REG_VAL_BUF_SIZE;
01386     FILE *file = NULL;
01387     BOOL unicode = (format == REG_FORMAT_5);
01388 
01389     reg_key_name_buf = HeapAlloc(GetProcessHeap(), 0,
01390     reg_key_name_size  * sizeof(*reg_key_name_buf));
01391     val_name_buf = HeapAlloc(GetProcessHeap(), 0,
01392     val_name_size * sizeof(*val_name_buf));
01393     val_buf = HeapAlloc(GetProcessHeap(), 0, val_size);
01394     line_buf = HeapAlloc(GetProcessHeap(), 0, line_buf_size * sizeof(*line_buf));
01395     CHECK_ENOUGH_MEMORY(reg_key_name_buf && val_name_buf && val_buf && line_buf);
01396 
01397     if (reg_key_name && reg_key_name[0])
01398     {
01399         HKEY reg_key_class;
01400         WCHAR *branch_name = NULL;
01401         HKEY key;
01402 
01403         REGPROC_resize_char_buffer(&reg_key_name_buf, &reg_key_name_size,
01404         lstrlenW(reg_key_name));
01405         lstrcpyW(reg_key_name_buf, reg_key_name);
01406 
01407         /* open the specified key */
01408         if (!parseKeyName(reg_key_name, &reg_key_class, &branch_name))
01409         {
01410             CHAR* key_nameA = GetMultiByteString(reg_key_name);
01411             fprintf(stderr,"%s: Incorrect registry class specification in '%s'\n",
01412             getAppName(), key_nameA);
01413             HeapFree(GetProcessHeap(), 0, key_nameA);
01414             exit(1);
01415         }
01416         if (!branch_name[0])
01417         {
01418             /* no branch - registry class is specified */
01419             file = REGPROC_open_export_file(file_name, unicode);
01420             export_hkey(file, reg_key_class,
01421             &reg_key_name_buf, &reg_key_name_size,
01422             &val_name_buf, &val_name_size,
01423             &val_buf, &val_size, &line_buf,
01424             &line_buf_size, unicode);
01425         }
01426         else if (RegOpenKeyW(reg_key_class, branch_name, &key) == ERROR_SUCCESS)
01427         {
01428             file = REGPROC_open_export_file(file_name, unicode);
01429             export_hkey(file, key,
01430             &reg_key_name_buf, &reg_key_name_size,
01431             &val_name_buf, &val_name_size,
01432             &val_buf, &val_size, &line_buf,
01433             &line_buf_size, unicode);
01434             RegCloseKey(key);
01435         }
01436         else
01437         {
01438             CHAR* key_nameA = GetMultiByteString(reg_key_name);
01439             fprintf(stderr,"%s: Can't export. Registry key '%s' does not exist!\n",
01440             getAppName(), key_nameA);
01441             HeapFree(GetProcessHeap(), 0, key_nameA);
01442             REGPROC_print_error();
01443         }
01444     }
01445     else
01446     {
01447         unsigned int i;
01448 
01449         /* export all registry classes */
01450         file = REGPROC_open_export_file(file_name, unicode);
01451         for (i = 0; i < REG_CLASS_NUMBER; i++)
01452         {
01453             /* do not export HKEY_CLASSES_ROOT */
01454             if (reg_class_keys[i] != HKEY_CLASSES_ROOT &&
01455             reg_class_keys[i] != HKEY_CURRENT_USER &&
01456             reg_class_keys[i] != HKEY_CURRENT_CONFIG &&
01457             reg_class_keys[i] != HKEY_DYN_DATA)
01458             {
01459                 lstrcpyW(reg_key_name_buf, reg_class_namesW[i]);
01460                 export_hkey(file, reg_class_keys[i],
01461                 &reg_key_name_buf, &reg_key_name_size,
01462                 &val_name_buf, &val_name_size,
01463                 &val_buf, &val_size, &line_buf,
01464                 &line_buf_size, unicode);
01465             }
01466         }
01467     }
01468 
01469     if (file)
01470     {
01471         fclose(file);
01472     }
01473     HeapFree(GetProcessHeap(), 0, reg_key_name);
01474     HeapFree(GetProcessHeap(), 0, val_name_buf);
01475     HeapFree(GetProcessHeap(), 0, val_buf);
01476     HeapFree(GetProcessHeap(), 0, line_buf);
01477     return TRUE;
01478 }
01479 
01480 /******************************************************************************
01481  * Reads contents of the specified file into the registry.
01482  */
01483 BOOL import_registry_file(FILE* reg_file)
01484 {
01485     if (reg_file)
01486     {
01487         BYTE s[2];
01488         if (fread( s, 2, 1, reg_file) == 1)
01489         {
01490             if (s[0] == 0xff && s[1] == 0xfe)
01491             {
01492                 processRegLinesW(reg_file);
01493             }
01494             else
01495             {
01496                 fseek(reg_file, 0, SEEK_SET);
01497                 processRegLinesA(reg_file);
01498             }
01499         }
01500         return TRUE;
01501     }
01502     return FALSE;
01503 }
01504 
01505 /******************************************************************************
01506  * Removes the registry key with all subkeys. Parses full key name.
01507  *
01508  * Parameters:
01509  * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
01510  *      empty, points to register key class, does not exist.
01511  */
01512 void delete_registry_key(WCHAR *reg_key_name)
01513 {
01514     WCHAR *key_name = NULL;
01515     HKEY key_class;
01516 
01517     if (!reg_key_name || !reg_key_name[0])
01518         return;
01519 
01520     if (!parseKeyName(reg_key_name, &key_class, &key_name))
01521     {
01522         char* reg_key_nameA = GetMultiByteString(reg_key_name);
01523         fprintf(stderr,"%s: Incorrect registry class specification in '%s'\n",
01524         getAppName(), reg_key_nameA);
01525         HeapFree(GetProcessHeap(), 0, reg_key_nameA);
01526         exit(1);
01527     }
01528     if (!*key_name)
01529     {
01530         char* reg_key_nameA = GetMultiByteString(reg_key_name);
01531         fprintf(stderr,"%s: Can't delete registry class '%s'\n",
01532         getAppName(), reg_key_nameA);
01533         HeapFree(GetProcessHeap(), 0, reg_key_nameA);
01534         exit(1);
01535     }
01536 
01537     SHDeleteKey(key_class, key_name);
01538 }

Generated on Sun May 27 2012 04:17:41 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.