regedit: Fix exporting of REG_EXPAND_SZ and other 'weird' strings.

REG_EXPAND_SZ must be exported as hexadecimal to preserve the string type.
0-byte strings and those missing a trailing '\0' or with odd sizes must 
be saved as hexadecimal too so they are restored as is.
Move the binary-value export code to the new REGPROC_export_binary() 
function.
This commit is contained in:
Francois Gouget 2008-11-20 20:43:25 +01:00 committed by Alexandre Julliard
parent 3ef0b0ef2d
commit a81bb704df
1 changed files with 92 additions and 79 deletions

View File

@ -925,6 +925,75 @@ static void REGPROC_export_string(WCHAR **line_buf, DWORD *line_buf_size, DWORD
*line_len = pos; *line_len = pos;
} }
static void REGPROC_export_binary(WCHAR **line_buf, DWORD *line_buf_size, DWORD *line_len, DWORD type, BYTE *value, DWORD value_size, BOOL unicode)
{
DWORD i, hex_pos, data_pos, column;
const WCHAR *hex_prefix;
const WCHAR hex[] = {'h','e','x',':',0};
WCHAR hex_buf[17];
const WCHAR format[] = {'%','0','2','x',0};
const WCHAR comma[] = {',',0};
const WCHAR concat[] = {'\\','\n',' ',' ',0};
DWORD concat_prefix, concat_len;
const WCHAR newline[] = {'\n',0};
CHAR* value_multibyte = NULL;
if (type == REG_BINARY) {
hex_prefix = hex;
} else {
const WCHAR hex_format[] = {'h','e','x','(','%','u',')',':',0};
hex_prefix = hex_buf;
wsprintfW(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;
}
}
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) then we may overestimate
* the needed number of lines by one. But that's ok.
* - The trailing linefeed takes the place of a comma so
* it's accounted for already.
*/
*line_len += *line_len / (REG_FILE_HEX_LINE_LEN - concat_prefix) * concat_len;
REGPROC_resize_char_buffer(line_buf, line_buf_size, *line_len);
lstrcpyW(*line_buf + hex_pos, hex_prefix);
column = data_pos; /* no line wrap yet */
i = 0;
while (1)
{
wsprintfW(*line_buf + data_pos, format, (unsigned int)value[i]);
data_pos += 2;
if (++i == value_size)
break;
lstrcpyW(*line_buf + data_pos, comma);
data_pos++;
column += 3;
/* wrap the line */
if (column >= REG_FILE_HEX_LINE_LEN) {
lstrcpyW(*line_buf + data_pos, concat);
data_pos += concat_len;
column = concat_prefix;
}
}
lstrcpyW(*line_buf + data_pos, newline);
if (value_multibyte)
HeapFree(GetProcessHeap(), 0, value_multibyte);
}
/****************************************************************************** /******************************************************************************
* Writes the given line to a file, in multi-byte or wide characters * Writes the given line to a file, in multi-byte or wide characters
*/ */
@ -1030,22 +1099,30 @@ static void export_hkey(FILE *file, HKEY key,
switch (value_type) { switch (value_type) {
case REG_SZ: case REG_SZ:
case REG_EXPAND_SZ:
{ {
const WCHAR start[] = {'"',0}; WCHAR* wstr = (WCHAR*)*val_buf;
const WCHAR end[] = {'"','\n',0};
DWORD len;
len = lstrlenW(start); if (val_size1 < sizeof(WCHAR) || val_size1 % sizeof(WCHAR) ||
REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + len); wstr[val_size1 / sizeof(WCHAR) - 1]) {
lstrcpyW(*line_buf + line_len, start); REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode);
line_len += len; } else {
const WCHAR start[] = {'"',0};
const WCHAR end[] = {'"','\n',0};
DWORD len;
if (val_size1) len = lstrlenW(start);
REGPROC_export_string(line_buf, line_buf_size, &line_len, (WCHAR*)*val_buf, val_size1 / sizeof(WCHAR) - 1); REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + len);
lstrcpyW(*line_buf + line_len, start);
line_len += len;
REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + lstrlenW(end)); /* At this point we know wstr is '\0'-terminated
lstrcpyW(*line_buf + line_len, end); * so we can substract 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; break;
} }
@ -1071,75 +1148,11 @@ static void export_hkey(FILE *file, HKEY key,
HeapFree(GetProcessHeap(), 0, value_nameA); HeapFree(GetProcessHeap(), 0, value_nameA);
} }
/* falls through */ /* falls through */
case REG_EXPAND_SZ:
case REG_MULTI_SZ: case REG_MULTI_SZ:
/* falls through */ /* falls through */
case REG_BINARY: { case REG_BINARY:
DWORD i1; REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode);
const WCHAR *hex_prefix;
WCHAR buf[20];
int hex_pos, data_pos, column;
const WCHAR hex[] = {'h','e','x',':',0};
const WCHAR format[] = {'%','0','2','x',0};
const WCHAR comma[] = {',',0};
const WCHAR concat[] = {'\\','\n',' ',' ',0};
int concat_prefix, concat_len;
const WCHAR newline[] = {'\n',0};
BYTE* val_buf1 = *val_buf;
DWORD val_buf1_size = val_size1;
if (value_type == REG_BINARY) {
hex_prefix = hex;
} else {
const WCHAR hex_format[] = {'h','e','x','(','%','d',')',':',0};
hex_prefix = buf;
wsprintfW(buf, hex_format, value_type);
if(value_type == REG_MULTI_SZ && !unicode)
val_buf1 = (BYTE*)GetMultiByteStringN((WCHAR*)*val_buf, val_size1 / sizeof(WCHAR), &val_buf1_size);
}
concat_len=lstrlenW(concat);
concat_prefix=2;
hex_pos = line_len;
line_len += lstrlenW(hex_prefix);
data_pos = line_len;
line_len += val_buf1_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) then we may overestimate
* the needed number of lines by one. But that's ok.
* - The trailing linefeed takes the place of a comma so
* it's accounted for already.
*/
line_len += line_len / (REG_FILE_HEX_LINE_LEN - concat_prefix) * concat_len;
REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len);
lstrcpyW(*line_buf + hex_pos, hex_prefix);
column = data_pos; /* no line wrap yet */
i1 = 0;
while (1)
{
wsprintfW(*line_buf + data_pos, format, (unsigned int)(val_buf1)[i1]);
data_pos += 2;
if (++i1 == val_buf1_size)
break;
lstrcpyW(*line_buf + data_pos, comma);
data_pos++;
column += 3;
/* wrap the line */
if (column >= REG_FILE_HEX_LINE_LEN) {
lstrcpyW(*line_buf + data_pos, concat);
data_pos += concat_len;
column = concat_prefix;
}
}
lstrcpyW(*line_buf + data_pos, newline);
if(value_type == REG_MULTI_SZ && !unicode)
HeapFree(GetProcessHeap(), 0, val_buf1);
break;
}
} }
REGPROC_write_line(file, *line_buf, unicode); REGPROC_write_line(file, *line_buf, unicode);
} }