- Rework the line reading. This version uses a single expanding

buffer rather than a main buffer and a "next line" buffer.  This
  version does not overflow the allocated memory (hopefully).  The
  previous version did when concatenating the continuation lines.
- Add protection to the HexCSVToHex to prevent overflow.
- Allow for conversion of larger hex values.  Tested on a real 2.6KB
  value.
This commit is contained in:
Bill Medland 2002-06-21 20:12:02 +00:00 committed by Alexandre Julliard
parent 6a948491e8
commit 530b4e9aca
1 changed files with 111 additions and 77 deletions

View File

@ -23,10 +23,12 @@
#include "config.h" #include "config.h"
#include "wine/port.h" #include "wine/port.h"
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <windows.h> #include <windows.h>
#include <winnt.h> #include <winnt.h>
#include <winreg.h> #include <winreg.h>
#include <assert.h>
#include "regproc.h" #include "regproc.h"
#define REG_VAL_BUF_SIZE 4096 #define REG_VAL_BUF_SIZE 4096
@ -36,8 +38,7 @@
/* maximal number of characters in hexadecimal data line, /* maximal number of characters in hexadecimal data line,
not including '\' character */ not including '\' character */
/*#define REG_FILE_HEX_LINE_LEN 77*/ #define REG_FILE_HEX_LINE_LEN 76
#define REG_FILE_HEX_LINE_LEN 75
/* Globals used by the api setValue, queryValue */ /* Globals used by the api setValue, queryValue */
static LPSTR currentKeyName = NULL; static LPSTR currentKeyName = NULL;
@ -61,6 +62,7 @@ static HKEY reg_class_keys[REG_CLASS_NUMBER] = {
/* return values */ /* return values */
#define NOT_ENOUGH_MEMORY 1 #define NOT_ENOUGH_MEMORY 1
#define IO_ERROR 2
/* processing macros */ /* processing macros */
@ -235,6 +237,7 @@ char* convertHexToDWORDStr(BYTE *buf, ULONG bufLen)
/****************************************************************************** /******************************************************************************
* Converts a hex comma separated values list into a hex list. * Converts a hex comma separated values list into a hex list.
* The Hex input string must be in exactly the correct form.
*/ */
DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen) DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen)
{ {
@ -251,9 +254,11 @@ DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen)
* warn the user if we are here with a string longer than 2 bytes that does * warn the user if we are here with a string longer than 2 bytes that does
* not contains ",". It is more likely because the data is invalid. * not contains ",". It is more likely because the data is invalid.
*/ */
if ( ( strlen(str) > 2) && ( strchr(str, ',') == NULL) ) if ( ( strLen > 2) && ( strchr(str, ',') == NULL) )
printf("%s: WARNING converting CSV hex stream with no comma, " printf("%s: WARNING converting CSV hex stream with no comma, "
"input data seems invalid.\n", getAppName()); "input data seems invalid.\n", getAppName());
if (strLen > 3*bufLen)
printf ("%s: ERROR converting CSV hex stream. Too long\n", getAppName());
while (strPos < strLen) while (strPos < strLen)
{ {
@ -262,7 +267,8 @@ DWORD convertHexCSVToHex(char *str, BYTE *buf, ULONG bufLen)
memcpy(xbuf,s,2); xbuf[3]='\0'; memcpy(xbuf,s,2); xbuf[3]='\0';
sscanf(xbuf,"%02x",(UINT*)&wc); sscanf(xbuf,"%02x",(UINT*)&wc);
*b++ =(unsigned char)wc; if (byteCount < bufLen)
*b++ =(unsigned char)wc;
s+=3; s+=3;
strPos+=3; strPos+=3;
@ -398,6 +404,7 @@ HRESULT setValue(LPSTR val_name, LPSTR val_data)
DWORD dwDataType, dwParseType; DWORD dwDataType, dwParseType;
LPBYTE lpbData; LPBYTE lpbData;
BYTE convert[KEY_MAX_LEN]; BYTE convert[KEY_MAX_LEN];
BYTE *bBigBuffer = 0;
DWORD dwLen; DWORD dwLen;
if ( (val_name == NULL) || (val_data == NULL) ) if ( (val_name == NULL) || (val_data == NULL) )
@ -425,8 +432,19 @@ HRESULT setValue(LPSTR val_name, LPSTR val_data)
} }
else /* Convert the hexadecimal types */ else /* Convert the hexadecimal types */
{ {
dwLen = convertHexCSVToHex(val_data, convert, KEY_MAX_LEN); int b_len = strlen (val_data)+2/3;
lpbData = convert; if (b_len > KEY_MAX_LEN)
{
bBigBuffer = HeapAlloc (GetProcessHeap(), 0, b_len);
CHECK_ENOUGH_MEMORY(bBigBuffer);
dwLen = convertHexCSVToHex(val_data, bBigBuffer, b_len);
lpbData = bBigBuffer;
}
else
{
dwLen = convertHexCSVToHex(val_data, convert, KEY_MAX_LEN);
lpbData = convert;
}
} }
hRes = RegSetValueEx( hRes = RegSetValueEx(
@ -437,6 +455,8 @@ HRESULT setValue(LPSTR val_name, LPSTR val_data)
lpbData, lpbData,
dwLen); dwLen);
if (bBigBuffer)
HeapFree (GetProcessHeap(), 0, bBigBuffer);
return hRes; return hRes;
} }
@ -892,43 +912,6 @@ void processQueryValue(LPSTR cmdline)
#endif #endif
} }
/******************************************************************************
* Reads one phisical line from the stream, removes newline.
* Removes newline character, resizes the buffer if necessary.
*
* Parameters:
* in - input stream to read from
* pLine - pointer to the buffer to read the line to.
* pSize - pointer to the variable which contains size of the buffer.
*/
void readLine(FILE *in, LPSTR *pLine, ULONG *pLineSize)
{
(*pLine)[0] = 0;
if (!feof(in))
{
LPSTR readRes = ""; /* result of the last read */
ULONG curLen = 0; /* length of a read string */
while ( readRes )
{
if (strchr(*pLine, '\n'))
{
(*pLine)[curLen - 1] = '\0'; /* get rid of new line */
curLen--;
break;
}
readRes = fgets(*pLine + curLen, *pLineSize - curLen, in);
curLen = strlen(*pLine);
if (curLen == *pLineSize - 1)
{
*pLineSize += REG_VAL_BUF_SIZE;
*pLine = HeapReAlloc(GetProcessHeap(), 0, *pLine, *pLineSize);
CHECK_ENOUGH_MEMORY(*pLine);
}
}
}
}
/****************************************************************************** /******************************************************************************
* Calls command for each line of a registry file. * Calls command for each line of a registry file.
* Correctly processes comments (in # form), line continuation. * Correctly processes comments (in # form), line continuation.
@ -940,58 +923,109 @@ void readLine(FILE *in, LPSTR *pLine, ULONG *pLineSize)
void processRegLines(FILE *in, CommandAPI command) void processRegLines(FILE *in, CommandAPI command)
{ {
LPSTR line = NULL; /* line read from input stream */ LPSTR line = NULL; /* line read from input stream */
LPSTR nextLine = NULL;
ULONG lineSize = REG_VAL_BUF_SIZE; ULONG lineSize = REG_VAL_BUF_SIZE;
ULONG nextLineSize = REG_VAL_BUF_SIZE;
line = HeapAlloc(GetProcessHeap(), 0, lineSize); line = HeapAlloc(GetProcessHeap(), 0, lineSize);
nextLine = HeapAlloc(GetProcessHeap(), 0, nextLineSize); CHECK_ENOUGH_MEMORY(line);
if (!line || !nextLine)
{
printf("%s: file %s, line %d: Not enough memory",
getAppName(), __FILE__, __LINE__);
exit(NOT_ENOUGH_MEMORY);
}
while (!feof(in)) while (!feof(in))
{ {
ULONG curLen; LPSTR s; /* The pointer into line for where the current fgets should read */
s = line;
readLine(in, &line, &lineSize); for (;;)
curLen = strlen(line);
if ( curLen )
{ {
if( line[0] == '#' ) /* this is a comment */ size_t size_remaining;
continue; int size_to_get;
char *s_eol; /* various local uses */
/* a '\' char in the end of the current line means */ /* Do we need to expand the buffer ? */
/* that this line is not complete and we have to get */ assert (s >= line && s <= line + lineSize);
/* the rest in the next lines */ size_remaining = lineSize - (s-line);
while( line[curLen - 1] == '\\' && !feof(in)) if (size_remaining < 2) /* room for 1 character and the \0 */
{ {
line[curLen - 1]= '\0'; char *new_buffer;
readLine(in, &nextLine, &nextLineSize); size_t new_size = lineSize + REG_VAL_BUF_SIZE;
strcat(line, nextLine + 2); if (new_size > lineSize) /* no arithmetic overflow */
curLen = strlen(line); 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);
} }
/* 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);
if (NULL == fgets (s, size_to_get, in))
{
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.
*/
}
}
/* If we didn't read the eol nor the eof go around for the rest */
s_eol = strchr (s, '\n');
if (!feof (in) && !s_eol)
{
s = strchr (s, '\0');
/* It should be s + size_to_get - 1 but this is safer */
continue;
}
/* If it is a comment line then discard it and go around again */
if (line [0] == '#')
{
s = line;
continue;
}
/* Remove any line feed. Leave s_eol on the \0 */
if (s_eol)
{
*s_eol = '\0';
if (s_eol > line && *(s_eol-1) == '\r')
*--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;
/* The following error protection could be made more self-
* correcting but I thought it not worth trying.
*/
if ((c = fgetc (in)) == EOF || c != ' ' ||
(c = fgetc (in)) == EOF || c != ' ')
printf ("%s: ERROR - invalid continuation.\n", getAppName());
continue;
}
break; /* That is the full virtual line */
} }
command(line); command(line);
} }
command(NULL); command(NULL);
#if 0
/*
* Save the registry only if it was modified
*/
if ( commandSaveRegistry[cmdIndex] )
SHELL_SaveRegistry();
#endif
HeapFree(GetProcessHeap(), 0, line); HeapFree(GetProcessHeap(), 0, line);
HeapFree(GetProcessHeap(), 0, nextLine);
} }
/****************************************************************************** /******************************************************************************