* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#ifdef __REACTOS__
+#include <fcntl.h>
+#include <io.h>
#include "regedit.h"
-
-#include <assert.h>
+#else
+#include <errno.h>
#include <fcntl.h>
#include <io.h>
-#include <wine/unicode.h>
-
-#define REG_VAL_BUF_SIZE 4096
+#include <windows.h>
+#include <commctrl.h>
-/* maximal number of characters in hexadecimal data line,
- * including the indentation, but not including the '\' character
- */
-#define REG_FILE_HEX_LINE_LEN (2 + 25 * 3)
+#include "main.h"
+#endif
-const WCHAR* reg_class_namesW[] =
-{
- L"HKEY_LOCAL_MACHINE", L"HKEY_USERS", L"HKEY_CLASSES_ROOT",
- L"HKEY_CURRENT_CONFIG", L"HKEY_CURRENT_USER", L"HKEY_DYN_DATA"
-};
+#define REG_VAL_BUF_SIZE 4096
static HKEY reg_class_keys[] = {
HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_DYN_DATA
};
-#define REG_CLASS_NUMBER (sizeof(reg_class_keys) / sizeof(reg_class_keys[0]))
-
-/* return values */
-#define NOT_ENOUGH_MEMORY 1
-#define IO_ERROR 2
-
-/* processing macros */
-
-/* common check of memory allocation results */
-#define CHECK_ENOUGH_MEMORY(p) \
-if (!(p)) \
-{ \
- fprintf(stderr,"%S: file %s, line %d: Not enough memory\n", \
- getAppName(), __FILE__, __LINE__); \
- exit(NOT_ENOUGH_MEMORY); \
-}
-
/******************************************************************************
* Allocates memory and converts input from multibyte to wide chars
* Returned string must be freed by the caller
*/
-WCHAR* GetWideString(const char* strA)
+static WCHAR* GetWideString(const char* strA)
{
if(strA)
{
WCHAR* strW;
int len = MultiByteToWideChar(CP_ACP, 0, strA, -1, NULL, 0);
- strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
- CHECK_ENOUGH_MEMORY(strW);
+ strW = malloc(len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, strA, -1, strW, len);
return strW;
}
WCHAR* strW;
*len = MultiByteToWideChar(CP_ACP, 0, strA, chars, NULL, 0);
- strW = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(WCHAR));
- CHECK_ENOUGH_MEMORY(strW);
+ strW = malloc(*len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, strA, chars, strW, *len);
return strW;
}
char* strA;
int len = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL);
- strA = HeapAlloc(GetProcessHeap(), 0, len);
- CHECK_ENOUGH_MEMORY(strA);
+ strA = malloc(len);
WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, len, NULL, NULL);
return strA;
}
char* strA;
*len = WideCharToMultiByte(CP_ACP, 0, strW, chars, NULL, 0, NULL, NULL);
- strA = HeapAlloc(GetProcessHeap(), 0, *len);
- CHECK_ENOUGH_MEMORY(strA);
+ strA = malloc(*len);
WideCharToMultiByte(CP_ACP, 0, strW, chars, strA, *len, NULL, NULL);
return strA;
}
return NULL;
}
+static WCHAR *(*get_line)(FILE *);
+
+/* parser definitions */
+enum parser_state
+{
+ HEADER, /* parsing the registry file version header */
+ PARSE_WIN31_LINE, /* parsing a Windows 3.1 registry line */
+ LINE_START, /* at the beginning of a registry line */
+ KEY_NAME, /* parsing a key name */
+ DELETE_KEY, /* deleting a registry key */
+ DEFAULT_VALUE_NAME, /* parsing a default value name */
+ QUOTED_VALUE_NAME, /* parsing a double-quoted value name */
+ DATA_START, /* preparing for data parsing operations */
+ DELETE_VALUE, /* deleting a registry value */
+ DATA_TYPE, /* parsing the registry data type */
+ STRING_DATA, /* parsing REG_SZ data */
+ DWORD_DATA, /* parsing DWORD data */
+ HEX_DATA, /* parsing REG_BINARY, REG_NONE, REG_EXPAND_SZ or REG_MULTI_SZ data */
+ EOL_BACKSLASH, /* preparing to parse multiple lines of hex data */
+ HEX_MULTILINE, /* parsing multiple lines of hex data */
+ UNKNOWN_DATA, /* parsing an unhandled or invalid data type */
+ SET_VALUE, /* adding a value to the registry */
+ NB_PARSER_STATES
+};
+
+struct parser
+{
+ FILE *file; /* pointer to a registry file */
+ WCHAR two_wchars[2]; /* first two characters from the encoding check */
+ BOOL is_unicode; /* parsing Unicode or ASCII data */
+ short int reg_version; /* registry file version */
+ HKEY hkey; /* current registry key */
+ WCHAR *key_name; /* current key name */
+ WCHAR *value_name; /* value name */
+ DWORD parse_type; /* generic data type for parsing */
+ DWORD data_type; /* data type */
+ void *data; /* value data */
+ DWORD data_size; /* size of the data (in bytes) */
+ BOOL backslash; /* TRUE if the current line contains a backslash */
+ enum parser_state state; /* current parser state */
+};
+
+typedef WCHAR *(*parser_state_func)(struct parser *parser, WCHAR *pos);
+
+/* parser state machine functions */
+static WCHAR *header_state(struct parser *parser, WCHAR *pos);
+static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos);
+static WCHAR *line_start_state(struct parser *parser, WCHAR *pos);
+static WCHAR *key_name_state(struct parser *parser, WCHAR *pos);
+static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos);
+static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos);
+static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos);
+static WCHAR *data_start_state(struct parser *parser, WCHAR *pos);
+static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos);
+static WCHAR *data_type_state(struct parser *parser, WCHAR *pos);
+static WCHAR *string_data_state(struct parser *parser, WCHAR *pos);
+static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos);
+static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos);
+static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos);
+static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos);
+static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos);
+static WCHAR *set_value_state(struct parser *parser, WCHAR *pos);
+
+static const parser_state_func parser_funcs[NB_PARSER_STATES] =
+{
+ header_state, /* HEADER */
+ parse_win31_line_state, /* PARSE_WIN31_LINE */
+ line_start_state, /* LINE_START */
+ key_name_state, /* KEY_NAME */
+ delete_key_state, /* DELETE_KEY */
+ default_value_name_state, /* DEFAULT_VALUE_NAME */
+ quoted_value_name_state, /* QUOTED_VALUE_NAME */
+ data_start_state, /* DATA_START */
+ delete_value_state, /* DELETE_VALUE */
+ data_type_state, /* DATA_TYPE */
+ string_data_state, /* STRING_DATA */
+ dword_data_state, /* DWORD_DATA */
+ hex_data_state, /* HEX_DATA */
+ eol_backslash_state, /* EOL_BACKSLASH */
+ hex_multiline_state, /* HEX_MULTILINE */
+ unknown_data_state, /* UNKNOWN_DATA */
+ set_value_state, /* SET_VALUE */
+};
+
+/* set the new parser state and return the previous one */
+static inline enum parser_state set_state(struct parser *parser, enum parser_state state)
+{
+ enum parser_state ret = parser->state;
+ parser->state = state;
+ return ret;
+}
+
/******************************************************************************
* Converts a hex representation of a DWORD into a DWORD.
*/
-static BOOL convertHexToDWord(WCHAR* str, DWORD *dw)
+static BOOL convert_hex_to_dword(WCHAR *str, DWORD *dw)
{
- char buf[9];
- char dummy;
+ WCHAR *p, *end;
+ int count = 0;
- WideCharToMultiByte(CP_ACP, 0, str, -1, buf, 9, NULL, NULL);
- if (lstrlenW(str) > 8 || sscanf(buf, "%lx%c", dw, &dummy) != 1) {
- fprintf(stderr,"%S: ERROR, invalid hex value\n", getAppName());
- return FALSE;
+ while (*str == ' ' || *str == '\t') str++;
+ if (!*str) goto error;
+
+ p = str;
+ while (iswxdigit(*p))
+ {
+ count++;
+ p++;
}
+ if (count > 8) goto error;
+
+ end = p;
+ while (*p == ' ' || *p == '\t') p++;
+ if (*p && *p != ';') goto error;
+
+ *end = 0;
+ *dw = wcstoul(str, &end, 16);
return TRUE;
+
+error:
+ return FALSE;
}
/******************************************************************************
- * Converts a hex comma separated values list into a binary string.
+ * Converts comma-separated hex data into a binary string and modifies
+ * the input parameter to skip the concatenating backslash, if found.
+ *
+ * Returns TRUE or FALSE to indicate whether parsing was successful.
*/
-static BYTE* convertHexCSVToHex(WCHAR *str, DWORD *size)
+static BOOL convert_hex_csv_to_hex(struct parser *parser, WCHAR **str)
{
+ size_t size;
+ BYTE *d;
WCHAR *s;
- BYTE *d, *data;
+
+ parser->backslash = FALSE;
/* The worst case is 1 digit + 1 comma per byte */
- *size=(lstrlenW(str)+1)/2;
- data=HeapAlloc(GetProcessHeap(), 0, *size);
- CHECK_ENOUGH_MEMORY(data);
-
- s = str;
- d = data;
- *size=0;
- while (*s != '\0') {
- UINT wc;
+ size = ((lstrlenW(*str) + 1) / 2) + parser->data_size;
+ parser->data = realloc(parser->data, size);
+
+ s = *str;
+ d = (BYTE *)parser->data + parser->data_size;
+
+ while (*s)
+ {
WCHAR *end;
+ unsigned long wc;
- wc = strtoulW(s,&end,16);
- if (end == s || wc > 0xff || (*end && *end != ',')) {
- char* strA = GetMultiByteString(s);
- fprintf(stderr,"%S: ERROR converting CSV hex stream. Invalid value at '%s'\n",
- getAppName(), strA);
- HeapFree(GetProcessHeap(), 0, data);
- HeapFree(GetProcessHeap(), 0, strA);
- return NULL;
+ wc = wcstoul(s, &end, 16);
+ if (wc > 0xff) return FALSE;
+
+ if (s == end && wc == 0)
+ {
+ while (*end == ' ' || *end == '\t') end++;
+ if (*end == '\\')
+ {
+ parser->backslash = TRUE;
+ *str = end + 1;
+ return TRUE;
+ }
+ else if (*end == ';')
+ return TRUE;
+ return FALSE;
+ }
+
+ *d++ = wc;
+ parser->data_size++;
+
+ if (*end && *end != ',')
+ {
+ while (*end == ' ' || *end == '\t') end++;
+ if (*end && *end != ';') return FALSE;
+ return TRUE;
}
- *d++ =(BYTE)wc;
- (*size)++;
+
if (*end) end++;
s = end;
}
- return data;
+ return TRUE;
}
/******************************************************************************
- * This function returns the HKEY associated with the data type encoded in the
- * value. It modifies the input parameter (key value) in order to skip this
- * "now useless" data type information.
+ * Parses the data type of the registry value being imported and modifies
+ * the input parameter to skip the string representation of the data type.
*
- * Note: Updated based on the algorithm used in 'server/registry.c'
+ * Returns TRUE or FALSE to indicate whether a data type was found.
*/
-static DWORD getDataType(LPWSTR *lpValue, DWORD* parse_type)
+static BOOL parse_data_type(struct parser *parser, WCHAR **line)
{
struct data_type { const WCHAR *tag; int len; int type; int parse_type; };
- static const WCHAR quote[] = {'"'};
- static const WCHAR str[] = {'s','t','r',':','"'};
- static const WCHAR str2[] = {'s','t','r','(','2',')',':','"'};
- static const WCHAR hex[] = {'h','e','x',':'};
- static const WCHAR dword[] = {'d','w','o','r','d',':'};
- static const WCHAR hexp[] = {'h','e','x','('};
-
- static const struct data_type data_types[] = { /* actual type */ /* type to assume for parsing */
- { quote, 1, REG_SZ, REG_SZ },
- { str, 5, REG_SZ, REG_SZ },
- { str2, 8, REG_EXPAND_SZ, REG_SZ },
- { hex, 4, REG_BINARY, REG_BINARY },
- { dword, 6, REG_DWORD, REG_DWORD },
- { hexp, 4, -1, REG_BINARY },
- { NULL, 0, 0, 0 }
- };
+ static const struct data_type data_types[] = {
+ /* tag len type parse type */
+ { L"\"", 1, REG_SZ, REG_SZ },
+ { L"hex:", 4, REG_BINARY, REG_BINARY },
+ { L"dword:", 6, REG_DWORD, REG_DWORD },
+ { L"hex(", 4, -1, REG_BINARY }, /* REG_NONE, REG_EXPAND_SZ, REG_MULTI_SZ */
+ { NULL, 0, 0, 0 }
+ };
const struct data_type *ptr;
- int type;
- for (ptr = data_types; ptr->tag; ptr++) {
- if (strncmpW( ptr->tag, *lpValue, ptr->len ))
+ for (ptr = data_types; ptr->tag; ptr++)
+ {
+ if (wcsncmp(ptr->tag, *line, ptr->len))
continue;
- /* Found! */
- *parse_type = ptr->parse_type;
- type=ptr->type;
- *lpValue+=ptr->len;
- if (type == -1) {
- WCHAR* end;
+ parser->parse_type = ptr->parse_type;
+ parser->data_type = ptr->parse_type;
+ *line += ptr->len;
+
+ if (ptr->type == -1)
+ {
+ WCHAR *end;
+ DWORD val;
+
+ if (!**line || towlower((*line)[1]) == 'x')
+ return FALSE;
/* "hex(xx):" is special */
- type = (int)strtoulW( *lpValue , &end, 16 );
- if (**lpValue=='\0' || *end!=')' || *(end+1)!=':') {
- type=REG_NONE;
- } else {
- *lpValue = end + 2;
- }
+ val = wcstoul(*line, &end, 16);
+#ifdef __REACTOS__
+ /* Up to 8 hex digits, "hex(000000002)" is invalid */
+ if (*end != ')' || *(end + 1) != ':' || (val == ~0u && errno == ERANGE) || end - *line > 8)
+#else
+ if (*end != ')' || *(end + 1) != ':' || (val == ~0u && errno == ERANGE))
+#endif
+ return FALSE;
+
+ parser->data_type = val;
+ *line = end + 2;
}
- return type;
+ return TRUE;
}
- *parse_type=REG_NONE;
- return REG_NONE;
+ return FALSE;
}
/******************************************************************************
- * Replaces escape sequences with the characters.
+ * Replaces escape sequences with their character equivalents and
+ * null-terminates the string on the first non-escaped double quote.
+ *
+ * Assigns a pointer to the remaining unparsed data in the line.
+ * Returns TRUE or FALSE to indicate whether a closing double quote was found.
*/
-static void REGPROC_unescape_string(WCHAR* str)
+static BOOL REGPROC_unescape_string(WCHAR *str, WCHAR **unparsed)
{
int str_idx = 0; /* current character under analysis */
int val_idx = 0; /* the last character of the unescaped string */
int len = lstrlenW(str);
+ BOOL ret;
+
for (str_idx = 0; str_idx < len; str_idx++, val_idx++) {
if (str[str_idx] == '\\') {
str_idx++;
case 'n':
str[val_idx] = '\n';
break;
+ case 'r':
+ str[val_idx] = '\r';
+ break;
+ case '0':
+ return FALSE;
case '\\':
case '"':
str[val_idx] = str[str_idx];
break;
default:
- fprintf(stderr,"Warning! Unrecognized escape sequence: \\%c'\n",
- str[str_idx]);
+ if (!str[str_idx]) return FALSE;
+ output_message(STRING_ESCAPE_SEQUENCE, str[str_idx]);
str[val_idx] = str[str_idx];
break;
}
+ } else if (str[str_idx] == '"') {
+ break;
} else {
str[val_idx] = str[str_idx];
}
}
+
+ ret = (str[str_idx] == '"');
+ *unparsed = str + str_idx + 1;
str[val_idx] = '\0';
+ return ret;
}
-static BOOL parseKeyName(LPWSTR lpKeyName, HKEY *hKey, LPWSTR *lpKeyPath)
+static HKEY parse_key_name(WCHAR *key_name, WCHAR **key_path)
{
- WCHAR* lpSlash = NULL;
- unsigned int i, len;
+ unsigned int i;
- if (lpKeyName == NULL)
- return FALSE;
+ if (!key_name) return 0;
- for(i = 0; *(lpKeyName+i) != 0; i++)
+ *key_path = wcschr(key_name, '\\');
+ if (*key_path) (*key_path)++;
+
+ for (i = 0; i < ARRAY_SIZE(reg_class_keys); i++)
{
- if(*(lpKeyName+i) == '\\')
+ int len = lstrlenW(reg_class_namesW[i]);
+#ifdef __REACTOS__
+ if (!_wcsnicmp(key_name, reg_class_namesW[i], len) &&
+#else
+ if (!wcsnicmp(key_name, reg_class_namesW[i], len) &&
+#endif
+ (key_name[len] == 0 || key_name[len] == '\\'))
{
- lpSlash = lpKeyName+i;
- break;
+ return reg_class_keys[i];
}
}
- if (lpSlash)
- {
- len = lpSlash-lpKeyName;
- }
- else
+ return 0;
+}
+
+static void close_key(struct parser *parser)
+{
+ if (parser->hkey)
{
- len = lstrlenW(lpKeyName);
- lpSlash = lpKeyName+len;
- }
- *hKey = NULL;
+ free(parser->key_name);
+ parser->key_name = NULL;
- for (i = 0; i < REG_CLASS_NUMBER; i++) {
- if (CompareStringW(LOCALE_USER_DEFAULT, 0, lpKeyName, len, reg_class_namesW[i], len) == CSTR_EQUAL &&
- len == lstrlenW(reg_class_namesW[i])) {
- *hKey = reg_class_keys[i];
- break;
- }
+ RegCloseKey(parser->hkey);
+ parser->hkey = NULL;
}
-
- if (*hKey == NULL)
- return FALSE;
-
-
- if (*lpSlash != '\0')
- lpSlash++;
- *lpKeyPath = lpSlash;
- return TRUE;
}
-/* Globals used by the setValue() & co */
-static LPSTR currentKeyName;
-static HKEY currentKeyHandle = NULL;
-
/******************************************************************************
- * Sets the value with name val_name to the data in val_data for the currently
- * opened key.
- *
- * Parameters:
- * val_name - name of the registry value
- * val_data - registry value data
+ * Opens the registry key given by the input path.
+ * This key must be closed by calling close_key().
*/
-static LONG setValue(WCHAR* val_name, WCHAR* val_data, BOOL is_unicode)
+static LONG open_key(struct parser *parser, WCHAR *path)
{
+ HKEY key_class;
+ WCHAR *key_path;
LONG res;
- DWORD dwDataType, dwParseType;
- LPBYTE lpbData;
- DWORD dwData, dwLen;
- WCHAR del[] = {'-',0};
- if ( (val_name == NULL) || (val_data == NULL) )
+ close_key(parser);
+
+ /* Get the registry class */
+ if (!path || !(key_class = parse_key_name(path, &key_path)))
return ERROR_INVALID_PARAMETER;
- if (lstrcmpW(val_data, del) == 0)
+ res = RegCreateKeyExW(key_class, key_path, 0, NULL, REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS, NULL, &parser->hkey, NULL);
+
+ if (res == ERROR_SUCCESS)
{
- res=RegDeleteValueW(currentKeyHandle,val_name);
- return (res == ERROR_FILE_NOT_FOUND ? ERROR_SUCCESS : res);
+ parser->key_name = malloc((lstrlenW(path) + 1) * sizeof(WCHAR));
+ lstrcpyW(parser->key_name, path);
}
+ else
+ parser->hkey = NULL;
+
+ return res;
+}
- /* Get the data type stored into the value field */
- dwDataType = getDataType(&val_data, &dwParseType);
+static void free_parser_data(struct parser *parser)
+{
+ if (parser->parse_type == REG_DWORD || parser->parse_type == REG_BINARY)
+ free(parser->data);
+
+ parser->data = NULL;
+ parser->data_size = 0;
+}
- if (dwParseType == REG_SZ) /* no conversion for string */
+static void prepare_hex_string_data(struct parser *parser)
+{
+ if (parser->data_type == REG_EXPAND_SZ || parser->data_type == REG_MULTI_SZ ||
+ parser->data_type == REG_SZ)
{
- REGPROC_unescape_string(val_data);
- /* Compute dwLen after REGPROC_unescape_string because it may
- * have changed the string length and we don't want to store
- * the extra garbage in the registry.
- */
- dwLen = lstrlenW(val_data);
- if(val_data[dwLen-1] != '"')
- return ERROR_INVALID_DATA;
- if (dwLen>0 && val_data[dwLen-1]=='"')
+ if (parser->is_unicode)
{
- dwLen--;
- val_data[dwLen]='\0';
+ WCHAR *data = parser->data;
+ DWORD len = parser->data_size / sizeof(WCHAR);
+
+ if (data[len - 1] != 0)
+ {
+ data[len] = 0;
+ parser->data_size += sizeof(WCHAR);
+ }
+ }
+ else
+ {
+ BYTE *data = parser->data;
+
+ if (data[parser->data_size - 1] != 0)
+ {
+ data[parser->data_size] = 0;
+ parser->data_size++;
+ }
+
+ parser->data = GetWideStringN(parser->data, parser->data_size, &parser->data_size);
+ parser->data_size *= sizeof(WCHAR);
+ free(data);
}
- lpbData = (BYTE*) val_data;
- dwLen++; /* include terminating null */
- dwLen = dwLen * sizeof(WCHAR); /* size is in bytes */
}
- else if (dwParseType == REG_DWORD) /* Convert the dword types */
+}
+
+enum reg_versions {
+ REG_VERSION_31,
+ REG_VERSION_40,
+ REG_VERSION_50,
+ REG_VERSION_FUZZY,
+ REG_VERSION_INVALID
+};
+
+static enum reg_versions parse_file_header(const WCHAR *s)
+{
+ static const WCHAR header_31[] = L"REGEDIT";
+
+ while (*s == ' ' || *s == '\t') s++;
+
+ if (!lstrcmpW(s, header_31))
+ return REG_VERSION_31;
+
+ if (!lstrcmpW(s, L"REGEDIT4"))
+ return REG_VERSION_40;
+
+ if (!lstrcmpW(s, L"Windows Registry Editor Version 5.00"))
+ return REG_VERSION_50;
+
+ /* The Windows version accepts registry file headers beginning with "REGEDIT" and ending
+ * with other characters, as long as "REGEDIT" appears at the start of the line. For example,
+ * "REGEDIT 4", "REGEDIT9" and "REGEDIT4FOO" are all treated as valid file headers.
+ * In all such cases, however, the contents of the registry file are not imported.
+ */
+ if (!wcsncmp(s, header_31, 7)) /* "REGEDIT" without NUL */
+ return REG_VERSION_FUZZY;
+
+ return REG_VERSION_INVALID;
+}
+
+/* handler for parser HEADER state */
+static WCHAR *header_state(struct parser *parser, WCHAR *pos)
+{
+ WCHAR *line, *header;
+
+ if (!(line = get_line(parser->file)))
+ return NULL;
+
+ if (!parser->is_unicode)
{
- if (!convertHexToDWord(val_data, &dwData))
- return ERROR_INVALID_DATA;
- lpbData = (BYTE*)&dwData;
- dwLen = sizeof(dwData);
+ header = malloc((lstrlenW(line) + 3) * sizeof(WCHAR));
+ header[0] = parser->two_wchars[0];
+ header[1] = parser->two_wchars[1];
+ lstrcpyW(header + 2, line);
+ parser->reg_version = parse_file_header(header);
+ free(header);
}
- else if (dwParseType == REG_BINARY) /* Convert the binary data */
- {
- lpbData = convertHexCSVToHex(val_data, &dwLen);
- if (!lpbData)
- return ERROR_INVALID_DATA;
+ else parser->reg_version = parse_file_header(line);
- if((dwDataType == REG_MULTI_SZ || dwDataType == REG_EXPAND_SZ) && !is_unicode)
- {
- LPBYTE tmp = lpbData;
- lpbData = (LPBYTE)GetWideStringN((char*)lpbData, dwLen, &dwLen);
- dwLen *= sizeof(WCHAR);
- HeapFree(GetProcessHeap(), 0, tmp);
- }
- }
- else /* unknown format */
+ switch (parser->reg_version)
{
- fprintf(stderr,"%S: ERROR, unknown data format\n", getAppName());
- return ERROR_INVALID_DATA;
+ case REG_VERSION_31:
+ set_state(parser, PARSE_WIN31_LINE);
+ break;
+ case REG_VERSION_40:
+ case REG_VERSION_50:
+ set_state(parser, LINE_START);
+ break;
+ default:
+ get_line(NULL); /* Reset static variables */
+ return NULL;
}
- res = RegSetValueExW(
- currentKeyHandle,
- val_name,
- 0, /* Reserved */
- dwDataType,
- lpbData,
- dwLen);
- if (dwParseType == REG_BINARY)
- HeapFree(GetProcessHeap(), 0, lpbData);
- return res;
+ return line;
}
-/******************************************************************************
- * A helper function for processRegEntry() that opens the current key.
- * That key must be closed by calling closeKey().
- */
-static LONG openKeyW(WCHAR* stdInput)
+/* handler for parser PARSE_WIN31_LINE state */
+static WCHAR *parse_win31_line_state(struct parser *parser, WCHAR *pos)
{
- HKEY keyClass;
- WCHAR* keyPath;
- DWORD dwDisp;
- LONG res;
+ WCHAR *line, *value;
+ static WCHAR hkcr[] = L"HKEY_CLASSES_ROOT";
+ unsigned int key_end = 0;
- /* Sanity checks */
- if (stdInput == NULL)
- return ERROR_INVALID_PARAMETER;
+ if (!(line = get_line(parser->file)))
+ return NULL;
- /* Get the registry class */
- if (!parseKeyName(stdInput, &keyClass, &keyPath))
- return ERROR_INVALID_PARAMETER;
+ if (wcsncmp(line, hkcr, lstrlenW(hkcr)))
+ return line;
- res = RegCreateKeyExW(
- keyClass, /* Class */
- keyPath, /* Sub Key */
- 0, /* MUST BE 0 */
- NULL, /* object type */
- REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */
- KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */
- NULL, /* security attribute */
- ¤tKeyHandle, /* result */
- &dwDisp); /* disposition, REG_CREATED_NEW_KEY or
- REG_OPENED_EXISTING_KEY */
+ /* get key name */
+ while (line[key_end] && !iswspace(line[key_end])) key_end++;
- if (res == ERROR_SUCCESS)
- currentKeyName = GetMultiByteString(stdInput);
- else
- currentKeyHandle = NULL;
+ value = line + key_end;
+ while (*value == ' ' || *value == '\t') value++;
- return res;
+ if (*value == '=') value++;
+ if (*value == ' ') value++; /* at most one space is skipped */
+
+ line[key_end] = 0;
+
+ if (open_key(parser, line) != ERROR_SUCCESS)
+ {
+ output_message(STRING_OPEN_KEY_FAILED, line);
+ return line;
+ }
+ parser->value_name = NULL;
+ parser->data_type = REG_SZ;
+ parser->data = value;
+ parser->data_size = (lstrlenW(value) + 1) * sizeof(WCHAR);
+
+ set_state(parser, SET_VALUE);
+ return value;
}
-/******************************************************************************
- * Close the currently opened key.
- */
-static void closeKey(void)
+/* handler for parser LINE_START state */
+static WCHAR *line_start_state(struct parser *parser, WCHAR *pos)
{
- if (currentKeyHandle)
+ WCHAR *line, *p;
+
+ if (!(line = get_line(parser->file)))
+ return NULL;
+
+ for (p = line; *p; p++)
{
- HeapFree(GetProcessHeap(), 0, currentKeyName);
- RegCloseKey(currentKeyHandle);
- currentKeyHandle = NULL;
+ switch (*p)
+ {
+ case '[':
+ set_state(parser, KEY_NAME);
+ return p + 1;
+ case '@':
+ set_state(parser, DEFAULT_VALUE_NAME);
+ return p;
+ case '"':
+ set_state(parser, QUOTED_VALUE_NAME);
+ return p + 1;
+ case ' ':
+ case '\t':
+ break;
+ default:
+ return p;
+ }
}
+
+ return p;
}
-/******************************************************************************
- * This function is a wrapper for the setValue function. It prepares the
- * land and cleans the area once completed.
- * Note: this function modifies the line parameter.
- *
- * line - registry file unwrapped line. Should have the registry value name and
- * complete registry value data.
- */
-static void processSetValue(WCHAR* line, BOOL is_unicode)
+/* handler for parser KEY_NAME state */
+static WCHAR *key_name_state(struct parser *parser, WCHAR *pos)
{
- WCHAR* val_name; /* registry value name */
- WCHAR* val_data; /* registry value data */
- int line_idx = 0; /* current character under analysis */
- LONG res;
+ WCHAR *p = pos, *key_end;
- /* get value name */
- while ( isspaceW(line[line_idx]) ) line_idx++;
- if (line[line_idx] == '@' && line[line_idx + 1] == '=') {
- line[line_idx] = '\0';
- val_name = line;
- line_idx++;
- } else if (line[line_idx] == '\"') {
- line_idx++;
- val_name = line + line_idx;
- while (line[line_idx]) {
- if (line[line_idx] == '\\') /* skip escaped character */
- {
- line_idx += 2;
- } else {
- if (line[line_idx] == '\"') {
- line[line_idx] = '\0';
- line_idx++;
- break;
- } else {
- line_idx++;
- }
- }
- }
- while ( isspaceW(line[line_idx]) ) line_idx++;
- if (!line[line_idx]) {
- fprintf(stderr, "%S: warning: unexpected EOL\n", getAppName());
- return;
- }
- if (line[line_idx] != '=') {
- char* lineA;
- line[line_idx] = '\"';
- lineA = GetMultiByteString(line);
- fprintf(stderr,"%S: warning: unrecognized line: '%s'\n", getAppName(), lineA);
- HeapFree(GetProcessHeap(), 0, lineA);
- return;
- }
+ if (*p == ' ' || *p == '\t' || !(key_end = wcsrchr(p, ']')))
+ goto done;
- } else {
- char* lineA = GetMultiByteString(line);
- fprintf(stderr,"%S: warning: unrecognized line: '%s'\n", getAppName(), lineA);
- HeapFree(GetProcessHeap(), 0, lineA);
- return;
- }
- line_idx++; /* skip the '=' character */
-
- while ( isspaceW(line[line_idx]) ) line_idx++;
- val_data = line + line_idx;
- /* trim trailing blanks */
- line_idx = strlenW(val_data);
- while (line_idx > 0 && isspaceW(val_data[line_idx-1])) line_idx--;
- val_data[line_idx] = '\0';
-
- REGPROC_unescape_string(val_name);
- res = setValue(val_name, val_data, is_unicode);
- if ( res != ERROR_SUCCESS )
+ *key_end = 0;
+
+ if (*p == '-')
{
- char* val_nameA = GetMultiByteString(val_name);
- char* val_dataA = GetMultiByteString(val_data);
- fprintf(stderr,"%S: ERROR Key %s not created. Value: %s, Data: %s\n",
- getAppName(),
- currentKeyName,
- val_nameA,
- val_dataA);
- HeapFree(GetProcessHeap(), 0, val_nameA);
- HeapFree(GetProcessHeap(), 0, val_dataA);
+ set_state(parser, DELETE_KEY);
+ return p + 1;
}
+ else if (open_key(parser, p) != ERROR_SUCCESS)
+ output_message(STRING_OPEN_KEY_FAILED, p);
+
+done:
+ set_state(parser, LINE_START);
+ return p;
}
-/******************************************************************************
- * This function receives the currently read entry and performs the
- * corresponding action.
- * isUnicode affects parsing of REG_MULTI_SZ values
- */
-static void processRegEntry(WCHAR* stdInput, BOOL isUnicode)
+/* handler for parser DELETE_KEY state */
+static WCHAR *delete_key_state(struct parser *parser, WCHAR *pos)
{
- /*
- * We encountered the end of the file, make sure we
- * close the opened key and exit
- */
- if (stdInput == NULL) {
- closeKey();
- return;
- }
+ WCHAR *p = pos;
- if ( stdInput[0] == '[') /* We are reading a new key */
- {
- WCHAR* keyEnd;
- closeKey(); /* Close the previous key */
+ close_key(parser);
- /* Get rid of the square brackets */
- stdInput++;
- keyEnd = strrchrW(stdInput, ']');
- if (keyEnd)
- *keyEnd='\0';
+ if (*p == 'H' || *p == 'h')
+ delete_registry_key(p);
- /* delete the key if we encounter '-' at the start of reg key */
- if ( stdInput[0] == '-')
- {
- delete_registry_key(stdInput + 1);
- } else if ( openKeyW(stdInput) != ERROR_SUCCESS )
- {
- char* stdInputA = GetMultiByteString(stdInput);
- fprintf(stderr,"%S: setValue failed to open key %s\n",
- getAppName(), stdInputA);
- HeapFree(GetProcessHeap(), 0, stdInputA);
- }
- } else if( currentKeyHandle &&
- (( stdInput[0] == '@') || /* reading a default @=data pair */
- ( stdInput[0] == '\"'))) /* reading a new value=data pair */
+ set_state(parser, LINE_START);
+ return p;
+}
+
+/* handler for parser DEFAULT_VALUE_NAME state */
+static WCHAR *default_value_name_state(struct parser *parser, WCHAR *pos)
+{
+ free(parser->value_name);
+ parser->value_name = NULL;
+
+ set_state(parser, DATA_START);
+ return pos + 1;
+}
+
+/* handler for parser QUOTED_VALUE_NAME state */
+static WCHAR *quoted_value_name_state(struct parser *parser, WCHAR *pos)
+{
+ WCHAR *val_name = pos, *p;
+
+ free(parser->value_name);
+ parser->value_name = NULL;
+
+ if (!REGPROC_unescape_string(val_name, &p))
+ goto invalid;
+
+ /* copy the value name in case we need to parse multiple lines and the buffer is overwritten */
+ parser->value_name = malloc((lstrlenW(val_name) + 1) * sizeof(WCHAR));
+ lstrcpyW(parser->value_name, val_name);
+
+ set_state(parser, DATA_START);
+ return p;
+
+invalid:
+ set_state(parser, LINE_START);
+ return val_name;
+}
+
+/* handler for parser DATA_START state */
+static WCHAR *data_start_state(struct parser *parser, WCHAR *pos)
+{
+ WCHAR *p = pos;
+ unsigned int len;
+
+ while (*p == ' ' || *p == '\t') p++;
+ if (*p != '=') goto done;
+ p++;
+ while (*p == ' ' || *p == '\t') p++;
+
+ /* trim trailing whitespace */
+ len = lstrlenW(p);
+ while (len > 0 && (p[len - 1] == ' ' || p[len - 1] == '\t')) len--;
+ p[len] = 0;
+
+ if (*p == '-')
+ set_state(parser, DELETE_VALUE);
+ else
+ set_state(parser, DATA_TYPE);
+ return p;
+
+done:
+ set_state(parser, LINE_START);
+ return p;
+}
+
+/* handler for parser DELETE_VALUE state */
+static WCHAR *delete_value_state(struct parser *parser, WCHAR *pos)
+{
+ WCHAR *p = pos + 1;
+
+ while (*p == ' ' || *p == '\t') p++;
+ if (*p && *p != ';') goto done;
+
+ RegDeleteValueW(parser->hkey, parser->value_name);
+
+done:
+ set_state(parser, LINE_START);
+ return p;
+}
+
+/* handler for parser DATA_TYPE state */
+static WCHAR *data_type_state(struct parser *parser, WCHAR *pos)
+{
+ WCHAR *line = pos;
+
+ if (!parse_data_type(parser, &line))
{
- processSetValue(stdInput, isUnicode);
- } else
+ set_state(parser, LINE_START);
+ return line;
+ }
+
+ switch (parser->parse_type)
{
- /* Since we are assuming that the file format is valid we must be
- * reading a blank line which indicates the end of this key processing
- */
- closeKey();
+ case REG_SZ:
+ set_state(parser, STRING_DATA);
+ break;
+ case REG_DWORD:
+ set_state(parser, DWORD_DATA);
+ break;
+ case REG_BINARY: /* all hex data types, including undefined */
+ set_state(parser, HEX_DATA);
+ break;
+ default:
+ set_state(parser, UNKNOWN_DATA);
}
+
+ return line;
}
-/******************************************************************************
- * Processes a registry file.
- * Correctly processes comments (in # and ; form), line continuation.
- *
- * Parameters:
- * in - input stream to read from
- * first_chars - beginning of stream, read due to Unicode check
- */
-static void processRegLinesA(FILE *in, char* first_chars)
+/* handler for parser STRING_DATA state */
+static WCHAR *string_data_state(struct parser *parser, WCHAR *pos)
{
- LPSTR line = NULL; /* line read from input stream */
- ULONG lineSize = REG_VAL_BUF_SIZE;
+ WCHAR *line;
- line = HeapAlloc(GetProcessHeap(), 0, lineSize);
- CHECK_ENOUGH_MEMORY(line);
- memcpy(line, first_chars, 2);
+ parser->data = pos;
- while (!feof(in)) {
- LPSTR s; /* The pointer into line for where the current fgets should read */
- WCHAR* lineW;
- s = line;
+ if (!REGPROC_unescape_string(parser->data, &line))
+ goto invalid;
- if(first_chars)
- {
- s += 2;
- first_chars = NULL;
- }
+ while (*line == ' ' || *line == '\t') line++;
+ if (*line && *line != ';') goto invalid;
- for (;;) {
- size_t size_remaining;
- int size_to_get, i;
- char *s_eol; /* various local uses */
+ parser->data_size = (lstrlenW(parser->data) + 1) * sizeof(WCHAR);
- /* 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 */
- {
- char *new_buffer;
- size_t new_size = lineSize + REG_VAL_BUF_SIZE;
- if (new_size > lineSize) /* no arithmetic overflow */
- new_buffer = HeapReAlloc (GetProcessHeap(), 0, line, new_size);
- else
- new_buffer = NULL;
- CHECK_ENOUGH_MEMORY(new_buffer);
- line = new_buffer;
- s = line + lineSize - size_remaining;
- lineSize = new_size;
- size_remaining = lineSize - (s-line);
- }
+ set_state(parser, SET_VALUE);
+ return line;
- /* Get as much as possible into the buffer, terminated either by
- * eof, error, eol or getting the maximum amount. Abort on error.
- */
- size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
-
- /* get a single line. note that `i' must be one past the last
- * meaningful character in `s' when this loop exits */
- for(i = 0; i < size_to_get-1; ++i){
- int xchar;
-
- xchar = fgetc(in);
- s[i] = xchar;
- if(xchar == EOF){
- if(ferror(in)){
- perror("While reading input");
- exit(IO_ERROR);
- }else
- assert(feof(in));
- break;
- }
- if(s[i] == '\r'){
- /* read the next character iff it's \n */
- if(i+2 >= size_to_get){
- /* buffer too short, so put back the EOL char to
- * read next cycle */
- ungetc('\r', in);
- break;
- }
- s[i+1] = fgetc(in);
- if(s[i+1] != '\n'){
- ungetc(s[i+1], in);
- i = i+1;
- }else
- i = i+2;
- break;
- }
- if(s[i] == '\n'){
- i = i+1;
- break;
- }
- }
- s[i] = '\0';
+invalid:
+ free_parser_data(parser);
+ set_state(parser, LINE_START);
+ return line;
+}
- /* If we didn't read the eol nor the eof go around for the rest */
- s_eol = strpbrk (s, "\r\n");
- if (!feof (in) && !s_eol) {
- s = strchr (s, '\0');
- continue;
- }
+/* handler for parser DWORD_DATA state */
+static WCHAR *dword_data_state(struct parser *parser, WCHAR *pos)
+{
+ WCHAR *line = pos;
- /* If it is a comment line then discard it and go around again */
- if (line [0] == '#' || line [0] == ';') {
- s = line;
- continue;
- }
+ parser->data = malloc(sizeof(DWORD));
- /* Remove any line feed. Leave s_eol on the first \0 */
- if (s_eol) {
- if (*s_eol == '\r' && *(s_eol+1) == '\n')
- *(s_eol+1) = '\0';
- *s_eol = '\0';
- } else
- s_eol = strchr (s, '\0');
-
- /* If there is a concatenating \\ then go around again */
- if (s_eol > line && *(s_eol-1) == '\\') {
- int c;
- s = s_eol-1;
-
- do
- {
- c = fgetc(in);
- } while(c == ' ' || c == '\t');
-
- if(c == EOF)
- {
- fprintf(stderr,"%S: ERROR - invalid continuation.\n",
- getAppName());
- }
- else
- {
- *s = c;
- s++;
- }
- continue;
- }
+ if (!convert_hex_to_dword(line, parser->data))
+ goto invalid;
- lineW = GetWideString(line);
+ parser->data_size = sizeof(DWORD);
- break; /* That is the full virtual line */
- }
+ set_state(parser, SET_VALUE);
+ return line;
- processRegEntry(lineW, FALSE);
- HeapFree(GetProcessHeap(), 0, lineW);
+invalid:
+ free_parser_data(parser);
+ set_state(parser, LINE_START);
+ return line;
+}
+
+/* handler for parser HEX_DATA state */
+static WCHAR *hex_data_state(struct parser *parser, WCHAR *pos)
+{
+ WCHAR *line = pos;
+
+ if (!*line)
+ goto set_value;
+
+ if (!convert_hex_csv_to_hex(parser, &line))
+ goto invalid;
+
+ if (parser->backslash)
+ {
+ set_state(parser, EOL_BACKSLASH);
+ return line;
}
- processRegEntry(NULL, FALSE);
- HeapFree(GetProcessHeap(), 0, line);
+ prepare_hex_string_data(parser);
+
+set_value:
+ set_state(parser, SET_VALUE);
+ return line;
+
+invalid:
+ free_parser_data(parser);
+ set_state(parser, LINE_START);
+ return line;
+}
+
+/* handler for parser EOL_BACKSLASH state */
+static WCHAR *eol_backslash_state(struct parser *parser, WCHAR *pos)
+{
+ WCHAR *p = pos;
+
+ while (*p == ' ' || *p == '\t') p++;
+ if (*p && *p != ';') goto invalid;
+
+ set_state(parser, HEX_MULTILINE);
+ return pos;
+
+invalid:
+ free_parser_data(parser);
+ set_state(parser, LINE_START);
+ return p;
}
-static void processRegLinesW(FILE *in)
+/* handler for parser HEX_MULTILINE state */
+static WCHAR *hex_multiline_state(struct parser *parser, WCHAR *pos)
{
- WCHAR* buf = NULL; /* line read from input stream */
- ULONG lineSize = REG_VAL_BUF_SIZE;
- size_t CharsInBuf = -1;
+ WCHAR *line;
+
+ if (!(line = get_line(parser->file)))
+ {
+ prepare_hex_string_data(parser);
+ set_state(parser, SET_VALUE);
+ return pos;
+ }
+
+ while (*line == ' ' || *line == '\t') line++;
+ if (!*line || *line == ';') return line;
+
+ if (!iswxdigit(*line)) goto invalid;
+
+ set_state(parser, HEX_DATA);
+ return line;
+
+invalid:
+ free_parser_data(parser);
+ set_state(parser, LINE_START);
+ return line;
+}
+
+/* handler for parser UNKNOWN_DATA state */
+static WCHAR *unknown_data_state(struct parser *parser, WCHAR *pos)
+{
+ output_message(STRING_UNKNOWN_DATA_FORMAT, parser->data_type);
+
+ set_state(parser, LINE_START);
+ return pos;
+}
+
+/* handler for parser SET_VALUE state */
+static WCHAR *set_value_state(struct parser *parser, WCHAR *pos)
+{
+ RegSetValueExW(parser->hkey, parser->value_name, 0, parser->data_type,
+ parser->data, parser->data_size);
+
+ free_parser_data(parser);
+
+ if (parser->reg_version == REG_VERSION_31)
+ set_state(parser, PARSE_WIN31_LINE);
+ else
+ set_state(parser, LINE_START);
+
+ return pos;
+}
- WCHAR* s; /* The pointer into buf for where the current fgets should read */
- WCHAR* line; /* The start of the current line */
+static WCHAR *get_lineA(FILE *fp)
+{
+ static WCHAR *lineW;
+ static size_t size;
+ static char *buf, *next;
+ char *line;
- buf = HeapAlloc(GetProcessHeap(), 0, lineSize * sizeof(WCHAR));
- CHECK_ENOUGH_MEMORY(buf);
+ free(lineW);
- s = buf;
- line = buf;
+ if (!fp) goto cleanup;
- while(!feof(in)) {
- size_t size_remaining;
- int size_to_get;
- WCHAR *s_eol = NULL; /* various local uses */
+ if (!size)
+ {
+ size = REG_VAL_BUF_SIZE;
+ buf = malloc(size);
+ *buf = 0;
+ next = buf;
+ }
+ line = next;
- /* Do we need to expand the buffer ? */
- assert (s >= buf && s <= buf + lineSize);
- size_remaining = lineSize - (s-buf);
- if (size_remaining < 2) /* room for 1 character and the \0 */
+ while (next)
+ {
+ char *p = strpbrk(line, "\r\n");
+ if (!p)
{
- WCHAR *new_buffer;
- size_t new_size = lineSize + (REG_VAL_BUF_SIZE / sizeof(WCHAR));
- if (new_size > lineSize) /* no arithmetic overflow */
- new_buffer = HeapReAlloc (GetProcessHeap(), 0, buf, new_size * sizeof(WCHAR));
- else
- new_buffer = NULL;
- CHECK_ENOUGH_MEMORY(new_buffer);
- buf = new_buffer;
+ size_t len, count;
+ len = strlen(next);
+ memmove(buf, next, len + 1);
+ if (size - len < 3)
+ {
+ size *= 2;
+ buf = realloc(buf, size);
+ }
+ if (!(count = fread(buf + len, 1, size - len - 1, fp)))
+ {
+ next = NULL;
+ lineW = GetWideString(buf);
+ return lineW;
+ }
+ buf[len + count] = 0;
+ next = buf;
line = buf;
- s = buf + lineSize - size_remaining;
- lineSize = new_size;
- size_remaining = lineSize - (s-buf);
+ continue;
}
+ next = p + 1;
+ if (*p == '\r' && *(p + 1) == '\n') next++;
+ *p = 0;
+ lineW = GetWideString(line);
+ return lineW;
+ }
- /* Get as much as possible into the buffer, terminated either by
- * eof, error or getting the maximum amount. Abort on error.
- */
- size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
-
- CharsInBuf = fread(s, sizeof(WCHAR), size_to_get - 1, in);
- s[CharsInBuf] = 0;
-
- if (CharsInBuf == 0) {
- if (ferror(in)) {
- perror ("While reading input");
- exit (IO_ERROR);
- } else {
- assert (feof(in));
- *s = '\0';
- /* It is not clear to me from the definition that the
- * contents of the buffer are well defined on detecting
- * an eof without managing to read anything.
- */
- }
- }
+cleanup:
+ lineW = NULL;
+ if (size) free(buf);
+ size = 0;
+ return NULL;
+}
+
+static WCHAR *get_lineW(FILE *fp)
+{
+ static size_t size;
+ static WCHAR *buf, *next;
+ WCHAR *line;
+
+ if (!fp) goto cleanup;
+
+ if (!size)
+ {
+ size = REG_VAL_BUF_SIZE;
+ buf = malloc(size * sizeof(WCHAR));
+ *buf = 0;
+ next = buf;
+ }
+ line = next;
- /* If we didn't read the eol nor the eof go around for the rest */
- while(1)
+ while (next)
+ {
+ WCHAR *p = wcspbrk(line, L"\r\n");
+ if (!p)
{
- const WCHAR line_endings[] = {'\r','\n',0};
- s_eol = strpbrkW(line, line_endings);
-
- if(!s_eol) {
- /* Move the stub of the line to the start of the buffer so
- * we get the maximum space to read into, and so we don't
- * have to recalculate 'line' if the buffer expands */
- MoveMemory(buf, line, (strlenW(line)+1) * sizeof(WCHAR));
- line = buf;
- s = strchrW(line, '\0');
- break;
+ size_t len, count;
+ len = lstrlenW(next);
+ memmove(buf, next, (len + 1) * sizeof(WCHAR));
+ if (size - len < 3)
+ {
+ size *= 2;
+ buf = realloc(buf, size * sizeof(WCHAR));
}
-
- /* If it is a comment line then discard it and go around again */
- if (*line == '#' || *line == ';') {
- if (*s_eol == '\r' && *(s_eol+1) == '\n')
- line = s_eol + 2;
- else
- line = s_eol + 1;
- continue;
+ if (!(count = fread(buf + len, sizeof(WCHAR), size - len - 1, fp)))
+ {
+ next = NULL;
+ return buf;
}
+ buf[len + count] = 0;
+ next = buf;
+ line = buf;
+ continue;
+ }
+ next = p + 1;
+ if (*p == '\r' && *(p + 1) == '\n') next++;
+ *p = 0;
+ return line;
+ }
- /* If there is a concatenating \\ then go around again */
- if (*(s_eol-1) == '\\') {
- WCHAR* NextLine = s_eol + 1;
+cleanup:
+ if (size) free(buf);
+ size = 0;
+ return NULL;
+}
- if(*s_eol == '\r' && *(s_eol+1) == '\n')
- NextLine++;
+/******************************************************************************
+ * Reads contents of the specified file into the registry.
+ */
+BOOL import_registry_file(FILE *reg_file)
+{
+ BYTE s[2];
+ struct parser parser;
+ WCHAR *pos;
- while(*(NextLine+1) == ' ' || *(NextLine+1) == '\t')
- NextLine++;
+ if (!reg_file || (fread(s, 2, 1, reg_file) != 1))
+ return FALSE;
- MoveMemory(s_eol - 1, NextLine, (CharsInBuf - (NextLine - s) + 1)*sizeof(WCHAR));
- CharsInBuf -= NextLine - s_eol + 1;
- s_eol = 0;
- continue;
- }
+ parser.is_unicode = (s[0] == 0xff && s[1] == 0xfe);
+ get_line = parser.is_unicode ? get_lineW : get_lineA;
- /* Remove any line feed. Leave s_eol on the last \0 */
- if (*s_eol == '\r' && *(s_eol + 1) == '\n')
- *s_eol++ = '\0';
- *s_eol = '\0';
+ parser.file = reg_file;
+ parser.two_wchars[0] = s[0];
+ parser.two_wchars[1] = s[1];
+ parser.reg_version = -1;
+ parser.hkey = NULL;
+ parser.key_name = NULL;
+ parser.value_name = NULL;
+ parser.parse_type = 0;
+ parser.data_type = 0;
+ parser.data = NULL;
+ parser.data_size = 0;
+ parser.backslash = FALSE;
+ parser.state = HEADER;
- processRegEntry(line, TRUE);
- line = s_eol + 1;
- s_eol = 0;
- continue; /* That is the full virtual line */
- }
- }
+ pos = parser.two_wchars;
- processRegEntry(NULL, TRUE);
+ /* parser main loop */
+ while (pos)
+ pos = (parser_funcs[parser.state])(&parser, pos);
- HeapFree(GetProcessHeap(), 0, buf);
-}
+ if (parser.reg_version == REG_VERSION_FUZZY || parser.reg_version == REG_VERSION_INVALID)
+ return parser.reg_version == REG_VERSION_FUZZY;
-/****************************************************************************
- * REGPROC_print_error
- *
- * Print the message for GetLastError
- */
+ free(parser.value_name);
+ close_key(&parser);
-static void REGPROC_print_error(void)
-{
- LPVOID lpMsgBuf;
- DWORD error_code;
- int status;
-
- error_code = GetLastError ();
- status = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, error_code, 0, (LPSTR) &lpMsgBuf, 0, NULL);
- if (!status) {
- fprintf(stderr,"%S: Cannot display message for error %lu, status %lu\n",
- getAppName(), error_code, GetLastError());
- exit(1);
- }
- puts(lpMsgBuf);
- LocalFree(lpMsgBuf);
- exit(1);
+ return TRUE;
}
/******************************************************************************
- * Checks whether the buffer has enough room for the string or required size.
- * Resizes the buffer if necessary.
+ * Removes the registry key with all subkeys. Parses full key name.
*
* Parameters:
- * buffer - pointer to a buffer for string
- * len - current length of the buffer in characters.
- * required_len - length of the string to place to the buffer in characters.
- * The length does not include the terminating null character.
+ * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
+ * empty, points to register key class, does not exist.
*/
-static void REGPROC_resize_char_buffer(WCHAR **buffer, DWORD *len, DWORD required_len)
+void delete_registry_key(WCHAR *reg_key_name)
{
- required_len++;
- if (required_len > *len) {
- *len = required_len;
- if (!*buffer)
- *buffer = HeapAlloc(GetProcessHeap(), 0, *len * sizeof(**buffer));
- else
- *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *len * sizeof(**buffer));
- CHECK_ENOUGH_MEMORY(*buffer);
+ WCHAR *key_name = NULL;
+ HKEY key_class;
+
+ if (!reg_key_name || !reg_key_name[0])
+ return;
+
+ if (!(key_class = parse_key_name(reg_key_name, &key_name)))
+ {
+ if (key_name) *(key_name - 1) = 0;
+#ifdef __REACTOS__
+ output_message(STRING_INVALID_SYSTEM_KEY, reg_key_name);
+ return;
+#else
+ error_exit(STRING_INVALID_SYSTEM_KEY, reg_key_name);
+#endif
+ }
+
+ if (!key_name || !*key_name)
+#ifdef __REACTOS__
+ {
+ output_message(STRING_DELETE_FAILED, reg_key_name);
+ return;
}
+#else
+ error_exit(STRING_DELETE_FAILED, reg_key_name);
+#endif
+
+#ifdef __REACTOS__
+ SHDeleteKey(key_class, key_name);
+#else
+ RegDeleteTreeW(key_class, key_name);
+#endif
}
-/******************************************************************************
- * Same as REGPROC_resize_char_buffer() but on a regular buffer.
- *
- * Parameters:
- * buffer - pointer to a buffer
- * len - current size of the buffer in bytes
- * required_size - size of the data to place in the buffer in bytes
- */
-static void REGPROC_resize_binary_buffer(BYTE **buffer, DWORD *size, DWORD required_size)
+static void REGPROC_write_line(FILE *fp, const WCHAR *str, BOOL unicode)
{
- if (required_size > *size) {
- *size = required_size;
- if (!*buffer)
- *buffer = HeapAlloc(GetProcessHeap(), 0, *size);
- else
- *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *size);
- CHECK_ENOUGH_MEMORY(*buffer);
+ if (unicode)
+ fwrite(str, sizeof(WCHAR), lstrlenW(str), fp);
+ else
+ {
+ char *strA = GetMultiByteString(str);
+ fputs(strA, fp);
+ free(strA);
}
}
-/******************************************************************************
- * Prints string str to file
- */
-static void REGPROC_export_string(WCHAR **line_buf, DWORD *line_buf_size, DWORD *line_len, WCHAR *str, DWORD str_len)
+static WCHAR *REGPROC_escape_string(WCHAR *str, size_t str_len, size_t *line_len)
{
- DWORD i, pos;
- DWORD extra = 0;
+ size_t i, escape_count, pos;
+ WCHAR *buf;
+
+ for (i = 0, escape_count = 0; i < str_len; i++)
+ {
+ WCHAR c = str[i];
+
+ if (!c) break;
+
+ if (c == '\r' || c == '\n' || c == '\\' || c == '"')
+ escape_count++;
+ }
- REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + 10);
+ buf = malloc((str_len + escape_count + 1) * sizeof(WCHAR));
- /* escaping characters */
- pos = *line_len;
- for (i = 0; i < str_len; i++) {
+ for (i = 0, pos = 0; i < str_len; i++, pos++)
+ {
WCHAR c = str[i];
- switch (c) {
+
+ if (!c) break;
+
+ switch (c)
+ {
+ case '\r':
+ buf[pos++] = '\\';
+ buf[pos] = 'r';
+ break;
case '\n':
- extra++;
- REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + extra);
- (*line_buf)[pos++] = '\\';
- (*line_buf)[pos++] = 'n';
+ buf[pos++] = '\\';
+ buf[pos] = 'n';
break;
-
case '\\':
+ buf[pos++] = '\\';
+ buf[pos] = '\\';
+ break;
case '"':
- extra++;
- REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len + str_len + extra);
- (*line_buf)[pos++] = '\\';
- /* Fall through */
-
- default:
- (*line_buf)[pos++] = c;
+ buf[pos++] = '\\';
+ buf[pos] = '"';
break;
+ default:
+ buf[pos] = c;
}
}
- (*line_buf)[pos] = '\0';
+
+ buf[pos] = 0;
*line_len = pos;
+ return buf;
}
-static void REGPROC_export_binary(WCHAR **line_buf, DWORD *line_buf_size, DWORD *line_len, DWORD type, BYTE *value, DWORD value_size, BOOL unicode)
+static size_t export_value_name(FILE *fp, WCHAR *name, size_t len, BOOL unicode)
{
- DWORD hex_pos, data_pos;
- const WCHAR *hex_prefix;
- const WCHAR hex[] = {'h','e','x',':',0};
- WCHAR hex_buf[17];
- const WCHAR concat[] = {'\\','\r','\n',' ',' ',0};
- DWORD concat_prefix, concat_len;
- const WCHAR newline[] = {'\r','\n',0};
- CHAR* value_multibyte = NULL;
-
- if (type == REG_BINARY) {
- hex_prefix = hex;
- } else {
- const WCHAR hex_format[] = {'h','e','x','(','%','x',')',':',0};
- hex_prefix = hex_buf;
- sprintfW(hex_buf, hex_format, type);
- if ((type == REG_SZ || type == REG_EXPAND_SZ || type == REG_MULTI_SZ) && !unicode)
- {
- value_multibyte = GetMultiByteStringN((WCHAR*)value, value_size / sizeof(WCHAR), &value_size);
- value = (BYTE*)value_multibyte;
- }
+ static const WCHAR default_name[] = L"@=";
+ size_t line_len;
+
+ if (name && *name)
+ {
+ WCHAR *str = REGPROC_escape_string(name, len, &line_len);
+ WCHAR *buf = malloc((line_len + 4) * sizeof(WCHAR));
+#ifdef __REACTOS__
+ StringCchPrintfW(buf, line_len + 4, L"\"%s\"=", str);
+ line_len = wcslen(buf);
+#else
+ line_len = swprintf(buf, line_len + 4, L"\"%s\"=", str);
+#endif
+ REGPROC_write_line(fp, buf, unicode);
+ free(buf);
+ free(str);
+ }
+ else
+ {
+ line_len = lstrlenW(default_name);
+ REGPROC_write_line(fp, default_name, unicode);
}
- concat_len = lstrlenW(concat);
- concat_prefix = 2;
-
- hex_pos = *line_len;
- *line_len += lstrlenW(hex_prefix);
- data_pos = *line_len;
- *line_len += value_size * 3;
- /* - The 2 spaces that concat places at the start of the
- * line effectively reduce the space available for data.
- * - If the value name and hex prefix are very long
- * ( > REG_FILE_HEX_LINE_LEN) or *line_len divides
- * without a remainder then we may overestimate
- * the needed number of lines by one. But that's ok.
- * - The trailing '\r' takes the place of a comma so
- * we only need to add 1 for the trailing '\n'
- */
- *line_len += *line_len / (REG_FILE_HEX_LINE_LEN - concat_prefix) * concat_len + 1;
- REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len);
- lstrcpyW(*line_buf + hex_pos, hex_prefix);
- if (value_size)
+ return line_len;
+}
+
+static void export_string_data(WCHAR **buf, WCHAR *data, size_t size)
+{
+ size_t len = 0, line_len;
+ WCHAR *str;
+
+ if (size)
+ len = size / sizeof(WCHAR) - 1;
+ str = REGPROC_escape_string(data, len, &line_len);
+ *buf = malloc((line_len + 3) * sizeof(WCHAR));
+#ifdef __REACTOS__
+ StringCchPrintfW(*buf, line_len + 3, L"\"%s\"", str);
+#else
+ swprintf(*buf, line_len + 3, L"\"%s\"", str);
+#endif
+ free(str);
+}
+
+static void export_dword_data(WCHAR **buf, DWORD *data)
+{
+ *buf = malloc(15 * sizeof(WCHAR));
+#ifdef __REACTOS__
+ StringCchPrintfW(*buf, 15, L"dword:%08x", *data);
+#else
+ swprintf(*buf, 15, L"dword:%08x", *data);
+#endif
+}
+
+static size_t export_hex_data_type(FILE *fp, DWORD type, BOOL unicode)
+{
+ static const WCHAR hex[] = L"hex:";
+ size_t line_len;
+
+ if (type == REG_BINARY)
+ {
+ line_len = lstrlenW(hex);
+ REGPROC_write_line(fp, hex, unicode);
+ }
+ else
{
- const WCHAR format[] = {'%','0','2','x',0};
- DWORD i, column;
+ WCHAR *buf = malloc(15 * sizeof(WCHAR));
+#ifdef __REACTOS__
+ StringCchPrintfW(buf, 15, L"hex(%x):", type);
+ line_len = wcslen(buf);
+#else
+ line_len = swprintf(buf, 15, L"hex(%x):", type);
+#endif
+ REGPROC_write_line(fp, buf, unicode);
+ free(buf);
+ }
- column = data_pos; /* no line wrap yet */
- i = 0;
- while (1)
- {
- sprintfW(*line_buf + data_pos, format, (unsigned int)value[i]);
- data_pos += 2;
- if (++i == value_size)
- break;
+ return line_len;
+}
- (*line_buf)[data_pos++] = ',';
- column += 3;
+#define MAX_HEX_CHARS 77
- /* wrap the line */
- if (column >= REG_FILE_HEX_LINE_LEN) {
- lstrcpyW(*line_buf + data_pos, concat);
- data_pos += concat_len;
- column = concat_prefix;
- }
+static void export_hex_data(FILE *fp, WCHAR **buf, DWORD type, DWORD line_len,
+ void *data, DWORD size, BOOL unicode)
+{
+ size_t num_commas, i, pos;
+
+ line_len += export_hex_data_type(fp, type, unicode);
+
+ if (!size) return;
+
+ if (!unicode && (type == REG_EXPAND_SZ || type == REG_MULTI_SZ))
+ data = GetMultiByteStringN(data, size / sizeof(WCHAR), &size);
+
+ num_commas = size - 1;
+ *buf = malloc(size * 3 * sizeof(WCHAR));
+
+ for (i = 0, pos = 0; i < size; i++)
+ {
+#ifdef __REACTOS__
+ StringCchPrintfW(*buf + pos, 3, L"%02x", ((BYTE *)data)[i]);
+ pos += wcslen(*buf + pos);
+#else
+ pos += swprintf(*buf + pos, 3, L"%02x", ((BYTE *)data)[i]);
+#endif
+ if (i == num_commas) break;
+ (*buf)[pos++] = ',';
+ (*buf)[pos] = 0;
+ line_len += 3;
+
+ if (line_len >= MAX_HEX_CHARS)
+ {
+ REGPROC_write_line(fp, *buf, unicode);
+ REGPROC_write_line(fp, L"\\\r\n ", unicode);
+ line_len = 2;
+ pos = 0;
}
}
- lstrcpyW(*line_buf + data_pos, newline);
- HeapFree(GetProcessHeap(), 0, value_multibyte);
}
-/******************************************************************************
- * Writes the given line to a file, in multi-byte or wide characters
- */
-static void REGPROC_write_line(FILE *file, const WCHAR* str, BOOL unicode)
+static void export_newline(FILE *fp, BOOL unicode)
{
- if(unicode)
+ REGPROC_write_line(fp, L"\r\n", unicode);
+}
+
+static void export_data(FILE *fp, WCHAR *value_name, DWORD value_len, DWORD type,
+ void *data, size_t size, BOOL unicode)
+{
+ WCHAR *buf = NULL;
+ size_t line_len = export_value_name(fp, value_name, value_len, unicode);
+
+ switch (type)
{
- fwrite(str, sizeof(WCHAR), lstrlenW(str), file);
- } else
+ case REG_SZ:
+ export_string_data(&buf, data, size);
+ break;
+ case REG_DWORD:
+ if (size)
+ {
+ export_dword_data(&buf, data);
+ break;
+ }
+ /* fall through */
+ case REG_NONE:
+ case REG_EXPAND_SZ:
+ case REG_BINARY:
+ case REG_MULTI_SZ:
+ default:
+ export_hex_data(fp, &buf, type, line_len, data, size, unicode);
+ break;
+ }
+
+ if (size || type == REG_SZ)
{
- char* strA = GetMultiByteString(str);
- fputs(strA, file);
- HeapFree(GetProcessHeap(), 0, strA);
+ REGPROC_write_line(fp, buf, unicode);
+ free(buf);
}
+
+ export_newline(fp, unicode);
}
-/******************************************************************************
- * Writes contents of the registry key to the specified file stream.
- *
- * Parameters:
- * file - writable file stream to export registry branch to.
- * key - registry branch to export.
- * reg_key_name_buf - name of the key with registry class.
- * Is resized if necessary.
- * reg_key_name_size - length of the buffer for the registry class in characters.
- * val_name_buf - buffer for storing value name.
- * Is resized if necessary.
- * val_name_size - length of the buffer for storing value names in characters.
- * val_buf - buffer for storing values while extracting.
- * Is resized if necessary.
- * val_size - size of the buffer for storing values in bytes.
- */
-static void export_hkey(FILE *file, HKEY key,
- WCHAR **reg_key_name_buf, DWORD *reg_key_name_size,
- WCHAR **val_name_buf, DWORD *val_name_size,
- BYTE **val_buf, DWORD *val_size,
- WCHAR **line_buf, DWORD *line_buf_size,
- BOOL unicode)
+static WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len)
{
- DWORD max_sub_key_len;
- DWORD max_val_name_len;
- DWORD max_val_size;
- DWORD curr_len;
- DWORD i;
- BOOL more_data;
- LONG ret;
- WCHAR key_format[] = {'\r','\n','[','%','s',']','\r','\n',0};
-
- /* get size information and resize the buffers if necessary */
- if (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL,
- &max_sub_key_len, NULL,
- NULL, &max_val_name_len, &max_val_size, NULL, NULL
- ) != ERROR_SUCCESS) {
- REGPROC_print_error();
- }
- curr_len = strlenW(*reg_key_name_buf);
- REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_size,
- max_sub_key_len + curr_len + 1);
- REGPROC_resize_char_buffer(val_name_buf, val_name_size,
- max_val_name_len);
- REGPROC_resize_binary_buffer(val_buf, val_size, max_val_size);
- REGPROC_resize_char_buffer(line_buf, line_buf_size, lstrlenW(*reg_key_name_buf) + 4);
- /* output data for the current key */
- sprintfW(*line_buf, key_format, *reg_key_name_buf);
- REGPROC_write_line(file, *line_buf, unicode);
-
- /* print all the values */
- i = 0;
- more_data = TRUE;
- while(more_data) {
- DWORD value_type;
- DWORD val_name_size1 = *val_name_size;
- DWORD val_size1 = *val_size;
- ret = RegEnumValueW(key, i, *val_name_buf, &val_name_size1, NULL,
- &value_type, *val_buf, &val_size1);
- if (ret == ERROR_MORE_DATA) {
- /* Increase the size of the buffers and retry */
- REGPROC_resize_char_buffer(val_name_buf, val_name_size, val_name_size1);
- REGPROC_resize_binary_buffer(val_buf, val_size, val_size1);
- } else if (ret != ERROR_SUCCESS) {
- more_data = FALSE;
- if (ret != ERROR_NO_MORE_ITEMS) {
- REGPROC_print_error();
- }
- } else {
- DWORD line_len;
- i++;
+ WCHAR *subkey_path;
- if ((*val_name_buf)[0]) {
- const WCHAR val_start[] = {'"','%','s','"','=',0};
-
- line_len = 0;
- REGPROC_export_string(line_buf, line_buf_size, &line_len, *val_name_buf, lstrlenW(*val_name_buf));
- REGPROC_resize_char_buffer(val_name_buf, val_name_size, lstrlenW(*line_buf) + 1);
- lstrcpyW(*val_name_buf, *line_buf);
-
- line_len = 3 + lstrlenW(*val_name_buf);
- REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len);
- sprintfW(*line_buf, val_start, *val_name_buf);
- } else {
- const WCHAR std_val[] = {'@','=',0};
- line_len = 2;
- REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len);
- lstrcpyW(*line_buf, std_val);
- }
+ subkey_path = malloc((path_len + subkey_len + 2) * sizeof(WCHAR));
+#ifdef __REACTOS__
+ StringCchPrintfW(subkey_path, path_len + subkey_len + 2, L"%s\\%s", path, subkey_name);
+#else
+ swprintf(subkey_path, path_len + subkey_len + 2, L"%s\\%s", path, subkey_name);
+#endif
- switch (value_type) {
- case REG_SZ:
- {
- WCHAR* wstr = (WCHAR*)*val_buf;
-
- if (val_size1 < sizeof(WCHAR) || val_size1 % sizeof(WCHAR) ||
- wstr[val_size1 / sizeof(WCHAR) - 1]) {
- REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode);
- } else {
- const WCHAR start[] = {'"',0};
- const WCHAR end[] = {'"','\r','\n',0};
- DWORD len;
-
- len = lstrlenW(start);
- REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + len);
- lstrcpyW(*line_buf + line_len, start);
- line_len += len;
-
- /* At this point we know wstr is '\0'-terminated
- * so we can subtract 1 from the size
- */
- REGPROC_export_string(line_buf, line_buf_size, &line_len, wstr, val_size1 / sizeof(WCHAR) - 1);
-
- REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + lstrlenW(end));
- lstrcpyW(*line_buf + line_len, end);
- }
- break;
- }
+ return subkey_path;
+}
- case REG_DWORD:
- {
- WCHAR format[] = {'d','w','o','r','d',':','%','0','8','x','\r','\n',0};
+static void export_key_name(FILE *fp, WCHAR *name, BOOL unicode)
+{
+ WCHAR *buf;
+
+ buf = malloc((lstrlenW(name) + 7) * sizeof(WCHAR));
+#ifdef __REACTOS__
+ StringCchPrintfW(buf, lstrlenW(name) + 7, L"\r\n[%s]\r\n", name);
+#else
+ swprintf(buf, lstrlenW(name) + 7, L"\r\n[%s]\r\n", name);
+#endif
+ REGPROC_write_line(fp, buf, unicode);
+ free(buf);
+}
- REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + 15);
- sprintfW(*line_buf + line_len, format, *((DWORD *)*val_buf));
- break;
- }
+#define MAX_SUBKEY_LEN 257
- default:
+static void export_registry_data(FILE *fp, HKEY key, WCHAR *path, BOOL unicode)
+{
+ LONG rc;
+ DWORD max_value_len = 256, value_len;
+ DWORD max_data_bytes = 2048, data_size;
+ DWORD subkey_len;
+ DWORD i, type, path_len;
+ WCHAR *value_name, *subkey_name, *subkey_path;
+ BYTE *data;
+ HKEY subkey;
+
+ export_key_name(fp, path, unicode);
+
+ value_name = malloc(max_value_len * sizeof(WCHAR));
+ data = malloc(max_data_bytes);
+
+ i = 0;
+ for (;;)
+ {
+ value_len = max_value_len;
+ data_size = max_data_bytes;
+ rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size);
+ if (rc == ERROR_SUCCESS)
+ {
+ export_data(fp, value_name, value_len, type, data, data_size, unicode);
+ i++;
+ }
+ else if (rc == ERROR_MORE_DATA)
+ {
+ if (data_size > max_data_bytes)
{
- char* key_nameA = GetMultiByteString(*reg_key_name_buf);
- char* value_nameA = GetMultiByteString(*val_name_buf);
- fprintf(stderr,"%S: warning - unsupported registry format '%ld', "
- "treat as binary\n",
- getAppName(), value_type);
- fprintf(stderr,"key name: \"%s\"\n", key_nameA);
- fprintf(stderr,"value name:\"%s\"\n\n", value_nameA);
- HeapFree(GetProcessHeap(), 0, key_nameA);
- HeapFree(GetProcessHeap(), 0, value_nameA);
+ max_data_bytes = data_size;
+ data = realloc(data, max_data_bytes);
}
- /* falls through */
- case REG_EXPAND_SZ:
- case REG_MULTI_SZ:
- /* falls through */
- case REG_BINARY:
- REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode);
+ else
+ {
+ max_value_len *= 2;
+ value_name = realloc(value_name, max_value_len * sizeof(WCHAR));
}
- REGPROC_write_line(file, *line_buf, unicode);
}
+ else break;
}
- i = 0;
- more_data = TRUE;
- (*reg_key_name_buf)[curr_len] = '\\';
- while(more_data) {
- DWORD buf_size = *reg_key_name_size - curr_len - 1;
-
- ret = RegEnumKeyExW(key, i, *reg_key_name_buf + curr_len + 1, &buf_size,
- NULL, NULL, NULL, NULL);
- if (ret == ERROR_MORE_DATA) {
- /* Increase the size of the buffer and retry */
- REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_size, curr_len + 1 + buf_size);
- } else if (ret != ERROR_SUCCESS) {
- more_data = FALSE;
- if (ret != ERROR_NO_MORE_ITEMS) {
- REGPROC_print_error();
- }
- } else {
- HKEY subkey;
+ free(data);
+ free(value_name);
- i++;
- if (RegOpenKeyW(key, *reg_key_name_buf + curr_len + 1,
- &subkey) == ERROR_SUCCESS) {
- export_hkey(file, subkey, reg_key_name_buf, reg_key_name_size,
- val_name_buf, val_name_size, val_buf, val_size,
- line_buf, line_buf_size, unicode);
+ subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
+
+ path_len = lstrlenW(path);
+
+ i = 0;
+ for (;;)
+ {
+ subkey_len = MAX_SUBKEY_LEN;
+ rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
+ if (rc == ERROR_SUCCESS)
+ {
+ subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
+ if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey))
+ {
+ export_registry_data(fp, subkey, subkey_path, unicode);
RegCloseKey(subkey);
- } else {
- REGPROC_print_error();
}
+ free(subkey_path);
+ i++;
}
+ else break;
}
- (*reg_key_name_buf)[curr_len] = '\0';
+
+ free(subkey_name);
}
-/******************************************************************************
- * Open file in binary mode for export.
- */
static FILE *REGPROC_open_export_file(WCHAR *file_name, BOOL unicode)
{
FILE *file;
- WCHAR dash = '-';
- if (strncmpW(file_name,&dash,1)==0) {
- file=stdout;
+ if (!lstrcmpW(file_name, L"-"))
+ {
+ file = stdout;
_setmode(_fileno(file), _O_BINARY);
- } else
+ }
+ else
{
- CHAR* file_nameA = GetMultiByteString(file_name);
- file = fopen(file_nameA, "wb");
- if (!file) {
- perror("");
- fprintf(stderr,"%S: Can't open file \"%s\"\n", getAppName(), file_nameA);
- HeapFree(GetProcessHeap(), 0, file_nameA);
- exit(1);
+ file = _wfopen(file_name, L"wb");
+ if (!file)
+ {
+ _wperror(L"regedit");
+#ifdef __REACTOS__
+ output_message(STRING_CANNOT_OPEN_FILE, file_name);
+ return NULL;
+#else
+ error_exit(STRING_CANNOT_OPEN_FILE, file_name);
+#endif
}
- HeapFree(GetProcessHeap(), 0, file_nameA);
}
- if(unicode)
- {
- const BYTE unicode_seq[] = {0xff,0xfe};
- const WCHAR header[] = {'W','i','n','d','o','w','s',' ','R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ','V','e','r','s','i','o','n',' ','5','.','0','0','\r','\n'};
- fwrite(unicode_seq, sizeof(BYTE), sizeof(unicode_seq)/sizeof(unicode_seq[0]), file);
- fwrite(header, sizeof(WCHAR), sizeof(header)/sizeof(header[0]), file);
- } else
+
+ if (unicode)
{
- fputs("REGEDIT4\r\n", file);
+ static const BYTE bom[] = {0xff,0xfe};
+ static const WCHAR header[] = L"Windows Registry Editor Version 5.00\r\n";
+
+ fwrite(bom, sizeof(BYTE), ARRAY_SIZE(bom), file);
+ fwrite(header, sizeof(WCHAR), lstrlenW(header), file);
}
+ else
+ fputs("REGEDIT4\r\n", file);
return file;
}
-/******************************************************************************
- * Writes contents of the registry key to the specified file stream.
- *
- * Parameters:
- * file_name - name of a file to export registry branch to.
- * reg_key_name - registry branch to export. The whole registry is exported if
- * reg_key_name is NULL or contains an empty string.
- */
-BOOL export_registry_key(WCHAR *file_name, WCHAR *reg_key_name, DWORD format)
+static HKEY open_export_key(HKEY key_class, WCHAR *subkey, WCHAR *path)
{
- WCHAR *reg_key_name_buf;
- WCHAR *val_name_buf;
- BYTE *val_buf;
- WCHAR *line_buf;
- DWORD reg_key_name_size = KEY_MAX_LEN;
- DWORD val_name_size = KEY_MAX_LEN;
- DWORD val_size = REG_VAL_BUF_SIZE;
- DWORD line_buf_size = KEY_MAX_LEN + REG_VAL_BUF_SIZE;
- FILE *file = NULL;
- BOOL unicode = (format == REG_FORMAT_5);
+ HKEY key;
- reg_key_name_buf = HeapAlloc(GetProcessHeap(), 0,
- reg_key_name_size * sizeof(*reg_key_name_buf));
- val_name_buf = HeapAlloc(GetProcessHeap(), 0,
- val_name_size * sizeof(*val_name_buf));
- val_buf = HeapAlloc(GetProcessHeap(), 0, val_size);
- line_buf = HeapAlloc(GetProcessHeap(), 0, line_buf_size * sizeof(*line_buf));
- CHECK_ENOUGH_MEMORY(reg_key_name_buf && val_name_buf && val_buf && line_buf);
-
- if (reg_key_name && reg_key_name[0]) {
- HKEY reg_key_class;
- WCHAR *branch_name = NULL;
- HKEY key;
-
- REGPROC_resize_char_buffer(®_key_name_buf, ®_key_name_size,
- lstrlenW(reg_key_name));
- lstrcpyW(reg_key_name_buf, reg_key_name);
-
- /* open the specified key */
- if (!parseKeyName(reg_key_name, ®_key_class, &branch_name)) {
- CHAR* key_nameA = GetMultiByteString(reg_key_name);
- fprintf(stderr,"%S: Incorrect registry class specification in '%s'\n",
- getAppName(), key_nameA);
- HeapFree(GetProcessHeap(), 0, key_nameA);
- exit(1);
- }
- if (!branch_name[0]) {
- /* no branch - registry class is specified */
- file = REGPROC_open_export_file(file_name, unicode);
- export_hkey(file, reg_key_class,
- ®_key_name_buf, ®_key_name_size,
- &val_name_buf, &val_name_size,
- &val_buf, &val_size, &line_buf,
- &line_buf_size, unicode);
- } else if (RegOpenKeyW(reg_key_class, branch_name, &key) == ERROR_SUCCESS) {
- file = REGPROC_open_export_file(file_name, unicode);
- export_hkey(file, key,
- ®_key_name_buf, ®_key_name_size,
- &val_name_buf, &val_name_size,
- &val_buf, &val_size, &line_buf,
- &line_buf_size, unicode);
- RegCloseKey(key);
- } else {
- CHAR* key_nameA = GetMultiByteString(reg_key_name);
- fprintf(stderr,"%S: Can't export. Registry key '%s' does not exist!\n",
- getAppName(), key_nameA);
- HeapFree(GetProcessHeap(), 0, key_nameA);
- REGPROC_print_error();
- }
- } else {
- unsigned int i;
-
- /* export all registry classes */
- file = REGPROC_open_export_file(file_name, unicode);
- for (i = 0; i < REG_CLASS_NUMBER; i++) {
- /* do not export HKEY_CLASSES_ROOT */
- if (reg_class_keys[i] != HKEY_CLASSES_ROOT &&
- reg_class_keys[i] != HKEY_CURRENT_USER &&
- reg_class_keys[i] != HKEY_CURRENT_CONFIG &&
- reg_class_keys[i] != HKEY_DYN_DATA) {
- lstrcpyW(reg_key_name_buf, reg_class_namesW[i]);
- export_hkey(file, reg_class_keys[i],
- ®_key_name_buf, ®_key_name_size,
- &val_name_buf, &val_name_size,
- &val_buf, &val_size, &line_buf,
- &line_buf_size, unicode);
- }
- }
- }
+ if (!RegOpenKeyExW(key_class, subkey, 0, KEY_READ, &key))
+ return key;
+
+ output_message(STRING_OPEN_KEY_FAILED, path);
+ return NULL;
+}
+
+static BOOL export_key(WCHAR *file_name, WCHAR *path, BOOL unicode)
+{
+ HKEY key_class, key;
+ WCHAR *subkey;
+ FILE *fp;
- if (file) {
- fclose(file);
+ if (!(key_class = parse_key_name(path, &subkey)))
+ {
+ if (subkey) *(subkey - 1) = 0;
+ output_message(STRING_INVALID_SYSTEM_KEY, path);
+ return FALSE;
}
- HeapFree(GetProcessHeap(), 0, reg_key_name);
- HeapFree(GetProcessHeap(), 0, val_name_buf);
- HeapFree(GetProcessHeap(), 0, val_buf);
- HeapFree(GetProcessHeap(), 0, line_buf);
+
+ if (!(key = open_export_key(key_class, subkey, path)))
+ return FALSE;
+
+ fp = REGPROC_open_export_file(file_name, unicode);
+#ifdef __REACTOS__
+ if (!fp)
+ return TRUE; /* Error message is already displayed */
+#endif
+ export_registry_data(fp, key, path, unicode);
+ export_newline(fp, unicode);
+ fclose(fp);
+
+ RegCloseKey(key);
return TRUE;
}
-/******************************************************************************
- * Reads contents of the specified file into the registry.
- */
-BOOL import_registry_file(FILE* reg_file)
+static BOOL export_all(WCHAR *file_name, WCHAR *path, BOOL unicode)
{
- if (reg_file)
+ FILE *fp;
+ int i;
+ HKEY classes[] = {HKEY_LOCAL_MACHINE, HKEY_USERS}, key;
+ WCHAR *class_name;
+
+ fp = REGPROC_open_export_file(file_name, unicode);
+#ifdef __REACTOS__
+ if (!fp)
+ return TRUE; /* Error message is already displayed */
+#endif
+
+ for (i = 0; i < ARRAY_SIZE(classes); i++)
{
- BYTE s[2];
- if (fread( s, 2, 1, reg_file) == 1)
+ if (!(key = open_export_key(classes[i], NULL, path)))
{
- if (s[0] == 0xff && s[1] == 0xfe)
- {
- processRegLinesW(reg_file);
- } else
- {
- processRegLinesA(reg_file, (char*)s);
- }
+ fclose(fp);
+ return FALSE;
}
- return TRUE;
- }
- return FALSE;
-}
-/******************************************************************************
- * Removes the registry key with all subkeys. Parses full key name.
- *
- * Parameters:
- * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
- * empty, points to register key class, does not exist.
- */
-void delete_registry_key(WCHAR *reg_key_name)
-{
- WCHAR *key_name = NULL;
- HKEY key_class;
+ class_name = malloc((lstrlenW(reg_class_namesW[i]) + 1) * sizeof(WCHAR));
+ lstrcpyW(class_name, reg_class_namesW[i]);
- if (!reg_key_name || !reg_key_name[0])
- return;
+ export_registry_data(fp, classes[i], class_name, unicode);
- if (!parseKeyName(reg_key_name, &key_class, &key_name)) {
- char* reg_key_nameA = GetMultiByteString(reg_key_name);
- fprintf(stderr,"%S: Incorrect registry class specification in '%s'\n",
- getAppName(), reg_key_nameA);
- HeapFree(GetProcessHeap(), 0, reg_key_nameA);
- exit(1);
- }
- if (!*key_name) {
- char* reg_key_nameA = GetMultiByteString(reg_key_name);
- fprintf(stderr,"%S: Can't delete registry class '%s'\n",
- getAppName(), reg_key_nameA);
- HeapFree(GetProcessHeap(), 0, reg_key_nameA);
- exit(1);
+ free(class_name);
+ RegCloseKey(key);
}
- SHDeleteKey(key_class, key_name);
+ export_newline(fp, unicode);
+ fclose(fp);
+
+ return TRUE;
+}
+
+BOOL export_registry_key(WCHAR *file_name, WCHAR *path, DWORD format)
+{
+ BOOL unicode = (format == REG_FORMAT_5);
+
+ if (path && *path)
+ return export_key(file_name, path, unicode);
+ else
+ return export_all(file_name, path, unicode);
}