2214 lines
42 KiB
C
2214 lines
42 KiB
C
#include <windows.h>
|
|
#include <shellapi.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifndef CHAR
|
|
#define CHAR char
|
|
#endif // ifndef CHAR
|
|
// from winreg.h:
|
|
// HKEY_CLASSES_ROOT already defined
|
|
#define HKEY_CURRENT_USER (( HKEY ) 0x80000001 )
|
|
#define HKEY_LOCAL_MACHINE (( HKEY ) 0x80000002 )
|
|
#define HKEY_USERS (( HKEY ) 0x80000003 )
|
|
#define HKEY_PERFORMANCE_DATA (( HKEY ) 0x80000004 )
|
|
#define HKEY_CURRENT_CONFIG (( HKEY ) 0x80000005 )
|
|
#define HKEY_DYN_DATA (( HKEY ) 0x80000006 )
|
|
|
|
#include "regdef.h" // regdef.h from \\guilo\slm\src\dev\inc)
|
|
|
|
//from pch.h, remove extern
|
|
CHAR g_ValueNameBuffer[MAXVALUENAME_LENGTH];
|
|
BYTE g_ValueDataBuffer[MAXDATA_LENGTH];
|
|
|
|
// interface to regmain values
|
|
extern LPSTR lpMerge;
|
|
|
|
#include "reg1632.h"
|
|
#include "regporte.h"
|
|
#include "regresid.h"
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORP., 1993-1994
|
|
*
|
|
* TITLE: REGPORTE.C
|
|
*
|
|
* VERSION: 4.01
|
|
*
|
|
* AUTHOR: Tracy Sharpe
|
|
*
|
|
* DATE: 06 Apr 1994
|
|
*
|
|
* File import and export engine routines for the Registry Editor.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
//#include "pch.h"
|
|
//#include "regresid.h"
|
|
//#include "reg1632.h"
|
|
|
|
// When building for the Registry Editor, put all of the following constants
|
|
// in a read-only data section.
|
|
#ifdef WIN32
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
#endif
|
|
|
|
// Association between the ASCII name and the handle of the registry key.
|
|
const REGISTRY_ROOT g_RegistryRoots[] = {
|
|
"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT,
|
|
"HKEY_CURRENT_USER", HKEY_CURRENT_USER,
|
|
"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE,
|
|
"HKEY_USERS", HKEY_USERS,
|
|
// "HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA,
|
|
"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG,
|
|
"HKEY_DYN_DATA", HKEY_DYN_DATA
|
|
};
|
|
|
|
const CHAR s_RegistryHeader[] = "REGEDIT";
|
|
|
|
const CHAR s_OldWin31RegFileRoot[] = ".classes";
|
|
|
|
const CHAR s_Win40RegFileHeader[] = "REGEDIT4\n\n";
|
|
|
|
const CHAR s_HexPrefix[] = "hex";
|
|
const CHAR s_DwordPrefix[] = "dword:";
|
|
const CHAR g_HexConversion[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
|
|
'9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
|
const CHAR s_FileLineBreak[] = ",\\\n ";
|
|
|
|
#ifdef WIN32
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
#define SIZE_FILE_IO_BUFFER 512
|
|
|
|
typedef struct _FILE_IO {
|
|
CHAR Buffer[SIZE_FILE_IO_BUFFER];
|
|
FILE_HANDLE hFile;
|
|
int BufferOffset;
|
|
int CurrentColumn;
|
|
int CharsAvailable;
|
|
DWORD FileSizeDiv100;
|
|
DWORD FileOffset;
|
|
UINT LastPercentage;
|
|
#ifdef DEBUG
|
|
BOOL fValidateUngetChar;
|
|
#endif
|
|
} FILE_IO;
|
|
|
|
FILE_IO s_FileIo;
|
|
|
|
UINT g_FileErrorStringID;
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
ImportWin31RegFile(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
ImportWin40RegFile(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
ParseHeader(
|
|
LPHKEY lphKey
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
ParseValuename(
|
|
HKEY hKey
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
ParseDefaultValue(
|
|
HKEY hKey
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseString(
|
|
LPSTR lpString,
|
|
LPDWORD cbStringData
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseHexSequence(
|
|
LPBYTE lpHexData,
|
|
LPDWORD lpcbHexData
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseHexDword(
|
|
LPDWORD lpDword
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseHexByte(
|
|
LPBYTE lpByte
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseHexDigit(
|
|
LPBYTE lpDigit
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseEndOfLine(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
SkipWhitespace(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
SkipPastEndOfLine(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
GetChar(
|
|
LPCHAR lpChar
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
UngetChar(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
MatchChar(
|
|
CHAR CharToMatch
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
IsWhitespace(
|
|
CHAR Char
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
IsNewLine(
|
|
CHAR Char
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutBranch(
|
|
HKEY hKey,
|
|
LPSTR lpKeyName
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutLiteral(
|
|
LPCSTR lpString
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutString(
|
|
LPCSTR lpString
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutBinary(
|
|
CONST BYTE FAR* lpBuffer,
|
|
DWORD Type,
|
|
DWORD cbBytes
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutDword(
|
|
DWORD Dword,
|
|
BOOL fLeadingZeroes
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutChar(
|
|
CHAR Char
|
|
);
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
FlushIoBuffer(
|
|
VOID
|
|
);
|
|
|
|
#ifdef DBCS
|
|
#ifndef WIN32
|
|
LPSTR
|
|
NEAR PASCAL
|
|
DBCSStrChr(
|
|
LPSTR string,
|
|
CHAR chr
|
|
);
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
IsDBCSLeadByte(
|
|
BYTE chr
|
|
);
|
|
#endif
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* CreateRegistryKey
|
|
*
|
|
* DESCRIPTION:
|
|
* Parses the pFullKeyName string and creates a handle to the registry key.
|
|
*
|
|
* PARAMETERS:
|
|
* lphKey, location to store handle to registry key.
|
|
* lpFullKeyName, string of form "HKEY_LOCAL_MACHINE\Subkey1\Subkey2".
|
|
* fCreate, TRUE if key should be created, else FALSE for open only.
|
|
* (returns), ERROR_SUCCESS, no errors occurred, phKey is valid,
|
|
* ERROR_CANTOPEN, registry access error of some form,
|
|
* ERROR_BADKEY, incorrectly formed pFullKeyName.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
DWORD
|
|
PASCAL
|
|
CreateRegistryKey(
|
|
LPHKEY lphKey,
|
|
LPSTR lpFullKeyName,
|
|
BOOL fCreate
|
|
)
|
|
{
|
|
|
|
LPSTR lpSubKeyName;
|
|
CHAR PrevChar;
|
|
HKEY hRootKey;
|
|
UINT Counter;
|
|
DWORD Result;
|
|
|
|
if ((lpSubKeyName = (LPSTR) STRCHR(lpFullKeyName, '\\')) != NULL) {
|
|
|
|
PrevChar = *lpSubKeyName;
|
|
*lpSubKeyName++ = '\0';
|
|
|
|
}
|
|
|
|
CHARUPPERSTRING(lpFullKeyName);
|
|
|
|
hRootKey = NULL;
|
|
|
|
for (Counter = 0; Counter < NUMBER_REGISTRY_ROOTS; Counter++) {
|
|
|
|
if (STRCMP(g_RegistryRoots[Counter].lpKeyName, lpFullKeyName) == 0) {
|
|
|
|
hRootKey = g_RegistryRoots[Counter].hKey;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (hRootKey) {
|
|
|
|
Result = ERROR_CANTOPEN;
|
|
|
|
if (fCreate) {
|
|
|
|
if (RegCreateKey(hRootKey, lpSubKeyName, lphKey) == ERROR_SUCCESS)
|
|
Result = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (RegOpenKey(hRootKey, lpSubKeyName, lphKey) == ERROR_SUCCESS)
|
|
Result = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
Result = ERROR_BADKEY;
|
|
|
|
if (lpSubKeyName != NULL) {
|
|
|
|
lpSubKeyName--;
|
|
*lpSubKeyName = PrevChar;
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ImportRegFile
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
* lpFileName, address of name of file to be imported.
|
|
*
|
|
*******************************************************************************/
|
|
#ifdef WIN95
|
|
VOID
|
|
PASCAL
|
|
ImportRegFile(
|
|
LPSTR lpFileName
|
|
)
|
|
{
|
|
|
|
CHAR Char;
|
|
LPCCH lpHeader;
|
|
BOOL fNewRegistryFile;
|
|
#ifdef WIN32
|
|
OFSTRUCT OFStruct;
|
|
#endif
|
|
|
|
g_FileErrorStringID = IDS_IMPFILEERRSUCCESS;
|
|
|
|
if (OPENREADFILE(lpFileName, s_FileIo.hFile)) {
|
|
|
|
s_FileIo.FileSizeDiv100 = GETFILESIZE(s_FileIo.hFile) / 100;
|
|
s_FileIo.FileOffset = 0;
|
|
s_FileIo.LastPercentage = 0;
|
|
|
|
//
|
|
// The following will force GetChar to read in the first block of data.
|
|
//
|
|
|
|
s_FileIo.BufferOffset = SIZE_FILE_IO_BUFFER;
|
|
|
|
SkipWhitespace();
|
|
|
|
lpHeader = s_RegistryHeader;
|
|
|
|
while (*lpHeader != '\0') {
|
|
|
|
if (MatchChar(*lpHeader))
|
|
lpHeader++;
|
|
|
|
else
|
|
break;
|
|
|
|
}
|
|
|
|
if (*lpHeader == '\0') {
|
|
|
|
fNewRegistryFile = MatchChar('4');
|
|
|
|
SkipWhitespace();
|
|
|
|
if (GetChar(&Char) && IsNewLine(Char)) {
|
|
|
|
if (fNewRegistryFile)
|
|
ImportWin40RegFile();
|
|
|
|
else
|
|
ImportWin31RegFile();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
g_FileErrorStringID = IDS_IMPFILEERRFORMATBAD;
|
|
|
|
CLOSEFILE(s_FileIo.hFile);
|
|
|
|
}
|
|
|
|
else
|
|
g_FileErrorStringID = IDS_IMPFILEERRFILEOPEN;
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ImportWin31RegFile
|
|
*
|
|
* DESCRIPTION:
|
|
* Imports the contents of a Windows 3.1 style registry file into the
|
|
* registry.
|
|
*
|
|
* We scan over the file looking for lines of the following type:
|
|
* HKEY_CLASSES_ROOT\keyname = value_data
|
|
* HKEY_CLASSES_ROOT\keyname =value_data
|
|
* HKEY_CLASSES_ROOT\keyname value_data
|
|
* HKEY_CLASSES_ROOT\keyname (null value data)
|
|
*
|
|
* In all cases, any number of spaces may follow 'keyname'. Although we
|
|
* only document the first syntax, the Windows 3.1 Regedit handled all of
|
|
* these formats as valid, so this version will as well (fortunately, it
|
|
* doesn't make the parsing any more complex!).
|
|
*
|
|
* Note, we also support replacing HKEY_CLASSES_ROOT with \.classes above
|
|
* which must come from some early releases of Windows.
|
|
*
|
|
* PARAMETERS:
|
|
* (none).
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
ImportWin31RegFile(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
HKEY hKey;
|
|
CHAR Char;
|
|
BOOL fSuccess;
|
|
LPCSTR lpClassesRoot;
|
|
CHAR KeyName[MAXKEYNAME];
|
|
UINT Index;
|
|
|
|
//
|
|
// Keep an open handle to the classes root. We may prevent some
|
|
// unneccessary flushing.
|
|
//
|
|
|
|
if (RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey) != ERROR_SUCCESS) {
|
|
|
|
g_FileErrorStringID = IDS_IMPFILEERRREGOPEN;
|
|
return;
|
|
|
|
}
|
|
|
|
while (TRUE) {
|
|
|
|
//
|
|
// Check for the end of file condition.
|
|
//
|
|
|
|
if (!GetChar(&Char))
|
|
break;
|
|
|
|
UngetChar(); // Not efficient, but works for now.
|
|
|
|
//
|
|
// Match the beginning of the line against one of the two aliases for
|
|
// HKEY_CLASSES_ROOT.
|
|
//
|
|
|
|
if (MatchChar('\\'))
|
|
lpClassesRoot = s_OldWin31RegFileRoot;
|
|
|
|
else
|
|
lpClassesRoot = g_RegistryRoots[INDEX_HKEY_CLASSES_ROOT].lpKeyName;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
while (*lpClassesRoot != '\0') {
|
|
|
|
if (!MatchChar(*lpClassesRoot++)) {
|
|
|
|
fSuccess = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Make sure that we have a backslash seperating one of the aliases
|
|
// from the keyname.
|
|
//
|
|
|
|
if (fSuccess)
|
|
fSuccess = MatchChar('\\');
|
|
|
|
if (fSuccess) {
|
|
|
|
//
|
|
// We've found one of the valid aliases, so read in the keyname.
|
|
//
|
|
|
|
// fSuccess = TRUE; // Must be TRUE if we're in this block
|
|
Index = 0;
|
|
|
|
while (GetChar(&Char)) {
|
|
|
|
if (Char == ' ' || IsNewLine(Char))
|
|
break;
|
|
|
|
//
|
|
// Make sure that the keyname buffer doesn't overflow. We must
|
|
// leave room for a terminating null.
|
|
//
|
|
|
|
if (Index >= sizeof(KeyName) - 1) {
|
|
|
|
fSuccess = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
KeyName[Index++] = Char;
|
|
|
|
}
|
|
|
|
if (fSuccess) {
|
|
|
|
KeyName[Index] = '\0';
|
|
|
|
//
|
|
// Now see if we have a value to assign to this keyname.
|
|
//
|
|
|
|
SkipWhitespace();
|
|
|
|
if (MatchChar('='))
|
|
MatchChar(' ');
|
|
|
|
// fSuccess = TRUE; // Must be TRUE if we're in this block
|
|
Index = 0;
|
|
|
|
while (GetChar(&Char)) {
|
|
|
|
if (IsNewLine(Char))
|
|
break;
|
|
|
|
//
|
|
// Make sure that the value data buffer doesn't overflow.
|
|
// Because this is always string data, we must leave room
|
|
// for a terminating null.
|
|
//
|
|
|
|
if (Index >= MAXDATA_LENGTH - 1) {
|
|
|
|
fSuccess = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
g_ValueDataBuffer[Index++] = Char;
|
|
|
|
}
|
|
|
|
if (fSuccess) {
|
|
|
|
g_ValueDataBuffer[Index] = '\0';
|
|
|
|
if (RegSetValue(hKey, KeyName, REG_SZ, g_ValueDataBuffer,
|
|
Index) != ERROR_SUCCESS)
|
|
g_FileErrorStringID = IDS_IMPFILEERRREGSET;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Somewhere along the line, we had a parsing error, so resynchronize
|
|
// on the next line.
|
|
//
|
|
|
|
if (!fSuccess)
|
|
SkipPastEndOfLine();
|
|
|
|
}
|
|
|
|
RegFlushKey(hKey);
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
#endif // ifdef WIN95
|
|
/*******************************************************************************
|
|
*
|
|
* ImportWin40RegFile
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
ImportWin40RegFile(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
HKEY hLocalMachineKey;
|
|
HKEY hUsersKey;
|
|
HKEY hKey;
|
|
CHAR Char;
|
|
|
|
//
|
|
// Keep open handles for the predefined roots to prevent the registry
|
|
// library from flushing after every single RegOpenKey/RegCloseKey
|
|
// operation.
|
|
//
|
|
|
|
RegOpenKey(HKEY_LOCAL_MACHINE, NULL, &hLocalMachineKey);
|
|
RegOpenKey(HKEY_USERS, NULL, &hUsersKey);
|
|
|
|
#ifdef DEBUG
|
|
if (hLocalMachineKey == NULL)
|
|
OutputDebugString("Unable to open HKEY_LOCAL_MACHINE\n\r");
|
|
if (hUsersKey == NULL)
|
|
OutputDebugString("Unable to open HKEY_USERS\n\r");
|
|
#endif
|
|
|
|
hKey = NULL;
|
|
|
|
while (TRUE) {
|
|
|
|
SkipWhitespace();
|
|
|
|
//
|
|
// Check for the end of file condition.
|
|
//
|
|
|
|
if (!GetChar(&Char))
|
|
break;
|
|
|
|
switch (Char) {
|
|
|
|
case '[':
|
|
//
|
|
// If a registry key is currently open, we must close it first.
|
|
// If ParseHeader happens to fail (for example, no closing
|
|
// bracket), then hKey will be NULL and any values that we
|
|
// parse must be ignored.
|
|
//
|
|
|
|
if (hKey != NULL) {
|
|
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
|
|
}
|
|
|
|
ParseHeader(&hKey);
|
|
|
|
break;
|
|
|
|
case '"':
|
|
//
|
|
// As noted above, if we don't have an open registry key, then
|
|
// just skip the line.
|
|
//
|
|
|
|
if (hKey != NULL)
|
|
ParseValuename(hKey);
|
|
|
|
else
|
|
SkipPastEndOfLine();
|
|
|
|
break;
|
|
|
|
case '@':
|
|
//
|
|
//
|
|
//
|
|
|
|
if (hKey != NULL)
|
|
ParseDefaultValue(hKey);
|
|
|
|
else
|
|
SkipPastEndOfLine();
|
|
|
|
break;
|
|
|
|
case ';':
|
|
//
|
|
// This line is a comment so just dump the rest of it.
|
|
//
|
|
|
|
SkipPastEndOfLine();
|
|
|
|
break;
|
|
|
|
default:
|
|
if (IsNewLine(Char))
|
|
break;
|
|
|
|
SkipPastEndOfLine();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (hKey != NULL)
|
|
RegCloseKey(hKey);
|
|
|
|
if (hUsersKey != NULL)
|
|
RegCloseKey(hUsersKey);
|
|
|
|
if (hLocalMachineKey != NULL)
|
|
RegCloseKey(hLocalMachineKey);
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ParseHeader
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#define SIZE_FULL_KEYNAME (MAXKEYNAME + 40)
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
ParseHeader(
|
|
LPHKEY lphKey
|
|
)
|
|
{
|
|
|
|
CHAR FullKeyName[SIZE_FULL_KEYNAME];
|
|
int CurrentIndex;
|
|
int LastRightBracketIndex;
|
|
CHAR Char;
|
|
|
|
CurrentIndex = 0;
|
|
LastRightBracketIndex = -1;
|
|
|
|
while (GetChar(&Char)) {
|
|
|
|
if (IsNewLine(Char))
|
|
break;
|
|
|
|
if (Char == ']')
|
|
LastRightBracketIndex = CurrentIndex;
|
|
|
|
FullKeyName[CurrentIndex++] = Char;
|
|
|
|
if (CurrentIndex == SIZE_FULL_KEYNAME) {
|
|
|
|
do {
|
|
|
|
if (Char == ']')
|
|
LastRightBracketIndex = -1;
|
|
|
|
if (IsNewLine(Char))
|
|
break;
|
|
|
|
} while (GetChar(&Char));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (LastRightBracketIndex != -1) {
|
|
|
|
FullKeyName[LastRightBracketIndex] = '\0';
|
|
|
|
switch (CreateRegistryKey(lphKey, FullKeyName, TRUE)) {
|
|
|
|
case ERROR_CANTOPEN:
|
|
g_FileErrorStringID = IDS_IMPFILEERRREGOPEN;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ParseValuename
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
ParseValuename(
|
|
HKEY hKey
|
|
)
|
|
{
|
|
|
|
DWORD Type;
|
|
CHAR ValueName[MAXVALUENAME_LENGTH];
|
|
DWORD cbData;
|
|
LPCSTR lpPrefix;
|
|
|
|
cbData = sizeof(ValueName);
|
|
|
|
if (!ParseString(ValueName, &cbData))
|
|
goto ParseError;
|
|
|
|
SkipWhitespace();
|
|
|
|
if (!MatchChar('='))
|
|
goto ParseError;
|
|
|
|
SkipWhitespace();
|
|
|
|
//
|
|
// REG_SZ.
|
|
//
|
|
// "ValueName" = "string of text"
|
|
//
|
|
|
|
if (MatchChar('"')) {
|
|
|
|
// LATER: Line continuations for strings?
|
|
|
|
cbData = MAXDATA_LENGTH;
|
|
|
|
if (!ParseString(g_ValueDataBuffer, &cbData) || !ParseEndOfLine())
|
|
goto ParseError;
|
|
|
|
Type = REG_SZ;
|
|
|
|
}
|
|
|
|
//
|
|
// REG_DWORD.
|
|
//
|
|
// "ValueName" = dword: 12345678
|
|
//
|
|
|
|
else if (MatchChar(s_DwordPrefix[0])) {
|
|
|
|
lpPrefix = &s_DwordPrefix[1];
|
|
|
|
while (*lpPrefix != '\0')
|
|
if (!MatchChar(*lpPrefix++))
|
|
goto ParseError;
|
|
|
|
SkipWhitespace();
|
|
|
|
if (!ParseHexDword((LPDWORD) g_ValueDataBuffer) || !ParseEndOfLine())
|
|
goto ParseError;
|
|
|
|
Type = REG_DWORD;
|
|
cbData = sizeof(DWORD);
|
|
|
|
}
|
|
|
|
//
|
|
// REG_BINARY and other.
|
|
//
|
|
// "ValueName" = hex: 00 , 11 , 22
|
|
// "ValueName" = hex(12345678): 00, 11, 22
|
|
//
|
|
|
|
else {
|
|
|
|
lpPrefix = s_HexPrefix;
|
|
|
|
while (*lpPrefix != '\0')
|
|
if (!MatchChar(*lpPrefix++))
|
|
goto ParseError;
|
|
|
|
//
|
|
// Check if this is a type of registry data that we don't directly
|
|
// support. If so, then it's just a dump of hex data of the specified
|
|
// type.
|
|
//
|
|
|
|
if (MatchChar('(')) {
|
|
|
|
if (!ParseHexDword(&Type) || !MatchChar(')'))
|
|
goto ParseError;
|
|
|
|
}
|
|
|
|
else
|
|
Type = REG_BINARY;
|
|
|
|
if (!MatchChar(':') || !ParseHexSequence(g_ValueDataBuffer, &cbData) ||
|
|
!ParseEndOfLine())
|
|
goto ParseError;
|
|
|
|
}
|
|
|
|
if (RegSetValueEx(hKey, ValueName, 0, Type, g_ValueDataBuffer, cbData) !=
|
|
ERROR_SUCCESS)
|
|
g_FileErrorStringID = IDS_IMPFILEERRREGSET;
|
|
|
|
return;
|
|
|
|
ParseError:
|
|
SkipPastEndOfLine();
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ParseDefaultValue
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
ParseDefaultValue(
|
|
HKEY hKey
|
|
)
|
|
{
|
|
|
|
BOOL fSuccess;
|
|
DWORD cbData;
|
|
|
|
fSuccess = FALSE;
|
|
|
|
SkipWhitespace();
|
|
|
|
if (MatchChar('=')) {
|
|
|
|
SkipWhitespace();
|
|
|
|
if (MatchChar('"')) {
|
|
|
|
// LATER: Line continuations for strings?
|
|
|
|
cbData = MAXDATA_LENGTH;
|
|
|
|
if (ParseString(g_ValueDataBuffer, &cbData) && ParseEndOfLine()) {
|
|
|
|
if (RegSetValue(hKey, NULL, REG_SZ, g_ValueDataBuffer,
|
|
cbData) != ERROR_SUCCESS)
|
|
g_FileErrorStringID = IDS_IMPFILEERRREGSET;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!fSuccess)
|
|
SkipPastEndOfLine();
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ParseString
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseString(
|
|
LPSTR lpString,
|
|
LPDWORD lpcbStringData
|
|
)
|
|
{
|
|
|
|
CHAR Char;
|
|
DWORD cbMaxStringData;
|
|
DWORD cbStringData;
|
|
|
|
cbMaxStringData = *lpcbStringData;
|
|
cbStringData = 1; // Account for the null terminator
|
|
|
|
while (GetChar(&Char)) {
|
|
|
|
if (cbStringData >= cbMaxStringData)
|
|
return FALSE;
|
|
|
|
switch (Char) {
|
|
|
|
case '\\':
|
|
if (!GetChar(&Char))
|
|
return FALSE;
|
|
|
|
switch (Char) {
|
|
|
|
case '\\':
|
|
*lpString++ = '\\';
|
|
break;
|
|
|
|
case '"':
|
|
*lpString++ = '"';
|
|
break;
|
|
|
|
default:
|
|
OutputDebugString("ParseString: Invalid escape sequence");
|
|
return FALSE;
|
|
|
|
}
|
|
break;
|
|
|
|
case '"':
|
|
*lpString = '\0';
|
|
*lpcbStringData = cbStringData;
|
|
return TRUE;
|
|
|
|
default:
|
|
if (IsNewLine(Char))
|
|
return FALSE;
|
|
|
|
*lpString++ = Char;
|
|
|
|
#ifdef DBCS
|
|
if (IsDBCSLeadByte((BYTE)Char))
|
|
{
|
|
if (!GetChar(&Char))
|
|
return FALSE;
|
|
*lpString++ = Char;
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cbStringData++;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ParseHexSequence
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseHexSequence(
|
|
LPBYTE lpHexData,
|
|
LPDWORD lpcbHexData
|
|
)
|
|
{
|
|
|
|
DWORD cbHexData;
|
|
|
|
cbHexData = 0;
|
|
|
|
do {
|
|
|
|
if (cbHexData >= MAXDATA_LENGTH)
|
|
return FALSE;
|
|
|
|
SkipWhitespace();
|
|
|
|
if (MatchChar('\\') && !ParseEndOfLine())
|
|
return FALSE;
|
|
|
|
SkipWhitespace();
|
|
|
|
if (!ParseHexByte(lpHexData++))
|
|
break;
|
|
|
|
cbHexData++;
|
|
|
|
SkipWhitespace();
|
|
|
|
} while (MatchChar(','));
|
|
|
|
*lpcbHexData = cbHexData;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ParseHexDword
|
|
*
|
|
* DESCRIPTION:
|
|
* Parses a one dword hexadecimal string from the registry file stream and
|
|
* converts it to a binary number. A maximum of eight hex digits will be
|
|
* parsed from the stream.
|
|
*
|
|
* PARAMETERS:
|
|
* lpByte, location to store binary number.
|
|
* (returns), TRUE if a hexadecimal dword was parsed, else FALSE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseHexDword(
|
|
LPDWORD lpDword
|
|
)
|
|
{
|
|
|
|
UINT CountDigits;
|
|
DWORD Dword;
|
|
BYTE Byte;
|
|
|
|
Dword = 0;
|
|
CountDigits = 0;
|
|
|
|
while (TRUE) {
|
|
|
|
if (!ParseHexDigit(&Byte))
|
|
break;
|
|
|
|
Dword = (Dword << 4) + (DWORD) Byte;
|
|
|
|
if (++CountDigits == 8)
|
|
break;
|
|
|
|
}
|
|
|
|
*lpDword = Dword;
|
|
|
|
return CountDigits != 0;
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ParseHexByte
|
|
*
|
|
* DESCRIPTION:
|
|
* Parses a one byte hexadecimal string from the registry file stream and
|
|
* converts it to a binary number.
|
|
*
|
|
* PARAMETERS:
|
|
* lpByte, location to store binary number.
|
|
* (returns), TRUE if a hexadecimal byte was parsed, else FALSE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseHexByte(
|
|
LPBYTE lpByte
|
|
)
|
|
{
|
|
|
|
BYTE SecondDigit;
|
|
|
|
if (ParseHexDigit(lpByte)) {
|
|
|
|
if (ParseHexDigit(&SecondDigit))
|
|
*lpByte = (BYTE) ((*lpByte << 4) | SecondDigit);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ParseHexDigit
|
|
*
|
|
* DESCRIPTION:
|
|
* Parses a hexadecimal character from the registry file stream and converts
|
|
* it to a binary number.
|
|
*
|
|
* PARAMETERS:
|
|
* lpDigit, location to store binary number.
|
|
* (returns), TRUE if a hexadecimal digit was parsed, else FALSE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseHexDigit(
|
|
LPBYTE lpDigit
|
|
)
|
|
{
|
|
|
|
CHAR Char;
|
|
BYTE Digit;
|
|
|
|
if (GetChar(&Char)) {
|
|
|
|
if (Char >= '0' && Char <= '9')
|
|
Digit = (BYTE) (Char - '0');
|
|
|
|
else if (Char >= 'a' && Char <= 'f')
|
|
Digit = (BYTE) (Char - 'a' + 10);
|
|
|
|
else if (Char >= 'A' && Char <= 'F')
|
|
Digit = (BYTE) (Char - 'A' + 10);
|
|
|
|
else {
|
|
|
|
UngetChar();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
*lpDigit = Digit;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* ParseEndOfLine
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
ParseEndOfLine(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
CHAR Char;
|
|
BOOL fComment;
|
|
BOOL fFoundOneEndOfLine;
|
|
|
|
fComment = FALSE;
|
|
fFoundOneEndOfLine = FALSE;
|
|
|
|
while (GetChar(&Char)) {
|
|
|
|
if (IsWhitespace(Char))
|
|
continue;
|
|
|
|
if (IsNewLine(Char)) {
|
|
|
|
fComment = FALSE;
|
|
fFoundOneEndOfLine = TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// Like .INIs and .INFs, comments begin with a semicolon character.
|
|
//
|
|
|
|
else if (Char == ';')
|
|
fComment = TRUE;
|
|
|
|
else if (!fComment) {
|
|
|
|
UngetChar();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fFoundOneEndOfLine;
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SkipWhitespace
|
|
*
|
|
* DESCRIPTION:
|
|
* Advances the registry file pointer to the first character past any
|
|
* detected whitespace.
|
|
*
|
|
* PARAMETERS:
|
|
* (none).
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
SkipWhitespace(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
CHAR Char;
|
|
|
|
while (GetChar(&Char)) {
|
|
|
|
if (!IsWhitespace(Char)) {
|
|
|
|
UngetChar();
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SkipPastEndOfLine
|
|
*
|
|
* DESCRIPTION:
|
|
* Advances the registry file pointer to the first character past the first
|
|
* detected new line character.
|
|
*
|
|
* PARAMETERS:
|
|
* (none).
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
SkipPastEndOfLine(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
CHAR Char;
|
|
|
|
while (GetChar(&Char)) {
|
|
|
|
if (IsNewLine(Char))
|
|
break;
|
|
|
|
}
|
|
|
|
while (GetChar(&Char)) {
|
|
|
|
if (!IsNewLine(Char)) {
|
|
|
|
UngetChar();
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* GetChar
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
GetChar(
|
|
LPCHAR lpChar
|
|
)
|
|
{
|
|
#ifdef WIN95
|
|
|
|
FILE_NUMBYTES NumberOfBytesRead;
|
|
UINT NewPercentage;
|
|
|
|
if (s_FileIo.BufferOffset == SIZE_FILE_IO_BUFFER) {
|
|
|
|
if (!READFILE(s_FileIo.hFile, s_FileIo.Buffer,
|
|
sizeof(s_FileIo.Buffer), &NumberOfBytesRead)) {
|
|
|
|
g_FileErrorStringID = IDS_IMPFILEERRFILEREAD;
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
s_FileIo.BufferOffset = 0;
|
|
s_FileIo.CharsAvailable = ((int) NumberOfBytesRead);
|
|
|
|
s_FileIo.FileOffset += NumberOfBytesRead;
|
|
|
|
if (s_FileIo.FileSizeDiv100 != 0) {
|
|
|
|
NewPercentage = ((UINT) (s_FileIo.FileOffset /
|
|
s_FileIo.FileSizeDiv100));
|
|
|
|
if (NewPercentage > 100)
|
|
NewPercentage = 100;
|
|
|
|
}
|
|
|
|
else
|
|
NewPercentage = 100;
|
|
|
|
if (s_FileIo.LastPercentage != NewPercentage) {
|
|
|
|
s_FileIo.LastPercentage = NewPercentage;
|
|
ImportRegFileUICallback(NewPercentage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (s_FileIo.BufferOffset >= s_FileIo.CharsAvailable)
|
|
return FALSE;
|
|
|
|
*lpChar = s_FileIo.Buffer[s_FileIo.BufferOffset++];
|
|
|
|
return TRUE;
|
|
#else
|
|
if (*lpMerge) {
|
|
*lpChar=*lpMerge++;
|
|
return TRUE;
|
|
} else
|
|
return FALSE;
|
|
#endif // ifdef WIN95
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* UngetChar
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
UngetChar(
|
|
VOID
|
|
)
|
|
{
|
|
#ifdef WIN95
|
|
#ifdef DEBUG
|
|
if (s_FileIo.fValidateUngetChar)
|
|
OutputDebugString("REGEDIT ERROR: Too many UngetChar's called!\n\r");
|
|
#endif // ifdef DEBUG
|
|
|
|
s_FileIo.BufferOffset--;
|
|
#else
|
|
lpMerge--;
|
|
#endif // ifdef WIN95
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* MatchChar
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
MatchChar(
|
|
CHAR CharToMatch
|
|
)
|
|
{
|
|
|
|
BOOL fMatch;
|
|
CHAR NextChar;
|
|
|
|
fMatch = FALSE;
|
|
|
|
if (GetChar(&NextChar)) {
|
|
|
|
if (CharToMatch == NextChar)
|
|
fMatch = TRUE;
|
|
|
|
else
|
|
UngetChar();
|
|
|
|
}
|
|
|
|
return fMatch;
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* IsWhitespace
|
|
*
|
|
* DESCRIPTION:
|
|
* Checks if the given character is whitespace.
|
|
*
|
|
* PARAMETERS:
|
|
* Char, character to check.
|
|
* (returns), TRUE if character is whitespace, else FALSE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
IsWhitespace(
|
|
CHAR Char
|
|
)
|
|
{
|
|
|
|
return Char == ' ' || Char == '\t';
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* IsNewLine
|
|
*
|
|
* DESCRIPTION:
|
|
* Checks if the given character is a new line character.
|
|
*
|
|
* PARAMETERS:
|
|
* Char, character to check.
|
|
* (returns), TRUE if character is a new line, else FALSE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
IsNewLine(
|
|
CHAR Char
|
|
)
|
|
{
|
|
|
|
return Char == '\n' || Char == '\r';
|
|
|
|
}
|
|
#ifdef WIN95
|
|
/*******************************************************************************
|
|
*
|
|
* ExportWin40RegFile
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
PASCAL
|
|
ExportWin40RegFile(
|
|
LPSTR lpFileName,
|
|
LPSTR lpSelectedPath
|
|
)
|
|
{
|
|
|
|
HKEY hKey;
|
|
CHAR SelectedPath[SIZE_SELECTED_PATH];
|
|
|
|
g_FileErrorStringID = IDS_EXPFILEERRSUCCESS;
|
|
|
|
if (lpSelectedPath != NULL && CreateRegistryKey(&hKey, lpSelectedPath,
|
|
FALSE) != ERROR_SUCCESS) {
|
|
|
|
g_FileErrorStringID = IDS_EXPFILEERRBADREGPATH;
|
|
return;
|
|
|
|
}
|
|
|
|
if (OPENWRITEFILE(lpFileName, s_FileIo.hFile)) {
|
|
|
|
s_FileIo.BufferOffset = 0;
|
|
s_FileIo.CurrentColumn = 0;
|
|
|
|
PutLiteral(s_Win40RegFileHeader);
|
|
|
|
if (lpSelectedPath != NULL) {
|
|
|
|
STRCPY(SelectedPath, lpSelectedPath);
|
|
PutBranch(hKey, SelectedPath);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
STRCPY(SelectedPath,
|
|
g_RegistryRoots[INDEX_HKEY_LOCAL_MACHINE].lpKeyName);
|
|
PutBranch(HKEY_LOCAL_MACHINE, SelectedPath);
|
|
|
|
STRCPY(SelectedPath,
|
|
g_RegistryRoots[INDEX_HKEY_USERS].lpKeyName);
|
|
PutBranch(HKEY_USERS, SelectedPath);
|
|
|
|
}
|
|
|
|
FlushIoBuffer();
|
|
|
|
CLOSEFILE(s_FileIo.hFile);
|
|
|
|
}
|
|
|
|
else
|
|
g_FileErrorStringID = IDS_EXPFILEERRFILEOPEN;
|
|
|
|
if (lpSelectedPath != NULL)
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* PutBranch
|
|
*
|
|
* DESCRIPTION:
|
|
* Writes out all of the value names and their data and recursively calls
|
|
* this routine for all of the key's subkeys to the registry file stream.
|
|
*
|
|
* PARAMETERS:
|
|
* hKey, registry key to write to file.
|
|
* lpFullKeyName, string that gives the full path, including the root key
|
|
* name, of the hKey.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutBranch(
|
|
HKEY hKey,
|
|
LPSTR lpFullKeyName
|
|
)
|
|
{
|
|
|
|
LONG RegError;
|
|
DWORD EnumIndex;
|
|
DWORD cbValueName;
|
|
DWORD cbValueData;
|
|
DWORD Type;
|
|
LPSTR lpSubKeyName;
|
|
int MaximumSubKeyLength;
|
|
HKEY hSubKey;
|
|
|
|
//
|
|
// Write out the section header.
|
|
//
|
|
|
|
PutChar('[');
|
|
PutLiteral(lpFullKeyName);
|
|
PutLiteral("]\n");
|
|
|
|
//
|
|
// Write out all of the value names and their data.
|
|
//
|
|
|
|
EnumIndex = 0;
|
|
|
|
while (TRUE) {
|
|
|
|
cbValueName = sizeof(g_ValueNameBuffer);
|
|
cbValueData = MAXDATA_LENGTH;
|
|
|
|
if ((RegError = RegEnumValue(hKey, EnumIndex++, g_ValueNameBuffer,
|
|
&cbValueName, NULL, &Type, g_ValueDataBuffer, &cbValueData))
|
|
!= ERROR_SUCCESS)
|
|
break;
|
|
|
|
//
|
|
// If cbValueName is zero, then this is the default value of
|
|
// the key, or the Windows 3.1 compatible key value.
|
|
//
|
|
|
|
if (cbValueName)
|
|
PutString(g_ValueNameBuffer);
|
|
|
|
else
|
|
PutChar('@');
|
|
|
|
PutChar('=');
|
|
|
|
switch (Type) {
|
|
|
|
case REG_SZ:
|
|
PutString((LPSTR) g_ValueDataBuffer);
|
|
break;
|
|
|
|
case REG_DWORD:
|
|
if (cbValueData == sizeof(DWORD)) {
|
|
|
|
PutLiteral(s_DwordPrefix);
|
|
PutDword(*((LPDWORD) g_ValueDataBuffer), TRUE);
|
|
break;
|
|
|
|
}
|
|
// FALL THROUGH
|
|
|
|
case REG_BINARY:
|
|
default:
|
|
PutBinary((LPBYTE) g_ValueDataBuffer, Type, cbValueData);
|
|
break;
|
|
|
|
}
|
|
|
|
PutChar('\n');
|
|
|
|
if (g_FileErrorStringID == IDS_EXPFILEERRFILEWRITE)
|
|
return;
|
|
|
|
}
|
|
|
|
PutChar('\n');
|
|
|
|
if (RegError != ERROR_NO_MORE_ITEMS)
|
|
g_FileErrorStringID = IDS_EXPFILEERRREGENUM;
|
|
|
|
//
|
|
// Write out all of the subkeys and recurse into them.
|
|
//
|
|
|
|
lpSubKeyName = lpFullKeyName + STRLEN(lpFullKeyName);
|
|
*lpSubKeyName++ = '\\';
|
|
MaximumSubKeyLength = MAXKEYNAME - STRLEN(lpSubKeyName);
|
|
|
|
EnumIndex = 0;
|
|
|
|
while (TRUE) {
|
|
|
|
if ((RegError = RegEnumKey(hKey, EnumIndex++, lpSubKeyName,
|
|
MaximumSubKeyLength)) != ERROR_SUCCESS)
|
|
break;
|
|
|
|
if (RegOpenKey(hKey, lpSubKeyName, &hSubKey) == ERROR_SUCCESS) {
|
|
|
|
PutBranch(hSubKey, lpFullKeyName);
|
|
|
|
RegCloseKey(hSubKey);
|
|
|
|
if (g_FileErrorStringID == IDS_EXPFILEERRFILEWRITE)
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
g_FileErrorStringID = IDS_EXPFILEERRREGOPEN;
|
|
|
|
}
|
|
|
|
if (RegError != ERROR_NO_MORE_ITEMS)
|
|
g_FileErrorStringID = IDS_EXPFILEERRREGENUM;
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* PutLiteral
|
|
*
|
|
* DESCRIPTION:
|
|
* Writes a literal string to the registry file stream. No special handling
|
|
* is done for the string-- it is written out as is.
|
|
*
|
|
* PARAMETERS:
|
|
* lpLiteral, null-terminated literal to write to file.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutLiteral(
|
|
LPCSTR lpLiteral
|
|
)
|
|
{
|
|
|
|
while (*lpLiteral != '\0')
|
|
PutChar(*lpLiteral++);
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* PutString
|
|
*
|
|
* DESCRIPTION:
|
|
* Writes a string to the registry file stream. A string is surrounded by
|
|
* double quotes and some characters may be translated to escape sequences
|
|
* to enable a parser to read the string back in.
|
|
*
|
|
* PARAMETERS:
|
|
* lpString, null-terminated string to write to file.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutString(
|
|
LPCSTR lpString
|
|
)
|
|
{
|
|
|
|
CHAR Char;
|
|
|
|
PutChar('"');
|
|
|
|
while ((Char = *lpString++) != '\0') {
|
|
|
|
switch (Char) {
|
|
|
|
case '\\':
|
|
case '"':
|
|
PutChar('\\');
|
|
// FALL THROUGH
|
|
|
|
default:
|
|
PutChar(Char);
|
|
#ifdef DBCS
|
|
if (IsDBCSLeadByte((BYTE)Char))
|
|
PutChar(*lpString++);
|
|
#endif
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PutChar('"');
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* PutBinary
|
|
*
|
|
* DESCRIPTION:
|
|
* Writes a sequence of hexadecimal bytes to the registry file stream. The
|
|
* output is formatted such that it doesn't exceed a defined line length.
|
|
*
|
|
* PARAMETERS:
|
|
* lpBuffer, bytes to write to file.
|
|
* Type, value data type.
|
|
* cbBytes, number of bytes to write.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutBinary(
|
|
CONST BYTE FAR* lpBuffer,
|
|
DWORD Type,
|
|
DWORD cbBytes
|
|
)
|
|
{
|
|
|
|
BOOL fFirstByteOnLine;
|
|
BYTE Byte;
|
|
|
|
PutLiteral(s_HexPrefix);
|
|
|
|
if (Type != REG_BINARY) {
|
|
|
|
PutChar('(');
|
|
PutDword(Type, FALSE);
|
|
PutChar(')');
|
|
|
|
}
|
|
|
|
PutChar(':');
|
|
|
|
fFirstByteOnLine = TRUE;
|
|
|
|
while (cbBytes--) {
|
|
|
|
if (s_FileIo.CurrentColumn > 75) {
|
|
|
|
PutLiteral(s_FileLineBreak);
|
|
|
|
fFirstByteOnLine = TRUE;
|
|
|
|
}
|
|
|
|
if (!fFirstByteOnLine)
|
|
PutChar(',');
|
|
|
|
Byte = *lpBuffer++;
|
|
|
|
PutChar(g_HexConversion[Byte >> 4]);
|
|
PutChar(g_HexConversion[Byte & 0x0F]);
|
|
|
|
fFirstByteOnLine = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* PutChar
|
|
*
|
|
* DESCRIPTION:
|
|
* Writes a 32-bit word to the registry file stream.
|
|
*
|
|
* PARAMETERS:
|
|
* Dword, dword to write to file.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutDword(
|
|
DWORD Dword,
|
|
BOOL fLeadingZeroes
|
|
)
|
|
{
|
|
|
|
int CurrentNibble;
|
|
CHAR Char;
|
|
BOOL fWroteNonleadingChar;
|
|
|
|
fWroteNonleadingChar = fLeadingZeroes;
|
|
|
|
for (CurrentNibble = 7; CurrentNibble >= 0; CurrentNibble--) {
|
|
|
|
Char = g_HexConversion[(Dword >> (CurrentNibble * 4)) & 0x0F];
|
|
|
|
if (fWroteNonleadingChar || Char != '0') {
|
|
|
|
PutChar(Char);
|
|
fWroteNonleadingChar = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// We need to write at least one character, so if we haven't written
|
|
// anything yet, just spit out one zero.
|
|
//
|
|
|
|
if (!fWroteNonleadingChar)
|
|
PutChar('0');
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* PutChar
|
|
*
|
|
* DESCRIPTION:
|
|
* Writes one character to the registry file stream using an intermediate
|
|
* buffer.
|
|
*
|
|
* PARAMETERS:
|
|
* Char, character to write to file.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
PutChar(
|
|
CHAR Char
|
|
)
|
|
{
|
|
|
|
//
|
|
// Keep track of what column we're currently at. This is useful in cases
|
|
// such as writing a large binary registry record. Instead of writing one
|
|
// very long line, the other Put* routines can break up their output.
|
|
//
|
|
|
|
if (Char != '\n')
|
|
s_FileIo.CurrentColumn++;
|
|
|
|
else {
|
|
|
|
//
|
|
// Force a carriage-return, line-feed sequence to keep things like, oh,
|
|
// Notepad happy.
|
|
//
|
|
|
|
PutChar('\r');
|
|
|
|
s_FileIo.CurrentColumn = 0;
|
|
|
|
}
|
|
|
|
s_FileIo.Buffer[s_FileIo.BufferOffset++] = Char;
|
|
|
|
if (s_FileIo.BufferOffset == SIZE_FILE_IO_BUFFER)
|
|
FlushIoBuffer();
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FlushIoBuffer
|
|
*
|
|
* DESCRIPTION:
|
|
* Flushes the contents of the registry file stream to the disk and resets
|
|
* the buffer pointer.
|
|
*
|
|
* PARAMETERS:
|
|
* (none).
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
NEAR PASCAL
|
|
FlushIoBuffer(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
FILE_NUMBYTES NumberOfBytesWritten;
|
|
|
|
if (s_FileIo.BufferOffset) {
|
|
|
|
if (!WRITEFILE(s_FileIo.hFile, s_FileIo.Buffer, s_FileIo.BufferOffset,
|
|
&NumberOfBytesWritten) || (FILE_NUMBYTES) s_FileIo.BufferOffset !=
|
|
NumberOfBytesWritten)
|
|
g_FileErrorStringID = IDS_EXPFILEERRFILEWRITE;
|
|
|
|
}
|
|
|
|
s_FileIo.BufferOffset = 0;
|
|
|
|
}
|
|
#endif // ifdef WIN95
|
|
#ifndef WIN32
|
|
/*******************************************************************************
|
|
*
|
|
* GetFileSize
|
|
*
|
|
* DESCRIPTION:
|
|
* Returns the file size for the given file handle.
|
|
*
|
|
* DESTRUCTIVE: After this call, the file pointer will be set to byte zero.
|
|
*
|
|
* PARAMETERS:
|
|
* hFile, file handle opened via MS-DOS.
|
|
* (returns), size of file.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
DWORD
|
|
NEAR PASCAL
|
|
GetFileSize(
|
|
FILE_HANDLE hFile
|
|
)
|
|
{
|
|
|
|
DWORD FileSize;
|
|
|
|
FileSize = _llseek(hFile, 0, SEEK_END);
|
|
_llseek(hFile, 0, SEEK_SET);
|
|
|
|
return FileSize;
|
|
|
|
}
|
|
#endif
|
|
|
|
#ifdef DBCS
|
|
#ifndef WIN32
|
|
/*******************************************************************************
|
|
*
|
|
* DBCSSTRCHR
|
|
*
|
|
* DESCRIPTION:
|
|
* DBCS enabled STRCHR
|
|
*
|
|
*******************************************************************************/
|
|
|
|
LPSTR
|
|
NEAR PASCAL
|
|
DBCSStrChr(
|
|
LPSTR string,
|
|
CHAR chr
|
|
)
|
|
{
|
|
LPSTR p;
|
|
|
|
p = string;
|
|
while (*p)
|
|
{
|
|
if (IsDBCSLeadByte((BYTE)*p))
|
|
{
|
|
p++;
|
|
if (*p == 0)
|
|
break;
|
|
}
|
|
else if (*p == chr)
|
|
return (p);
|
|
p++;
|
|
}
|
|
if (*p == chr)
|
|
return (p);
|
|
return NULL;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* IsDBCSLeadByte
|
|
*
|
|
* DESCRIPTION:
|
|
* Test if the character is DBCS lead byte
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL
|
|
NEAR PASCAL
|
|
IsDBCSLeadByte(
|
|
BYTE chr
|
|
)
|
|
{
|
|
static unsigned char far *DBCSLeadByteTable = NULL;
|
|
|
|
WORD off,segs;
|
|
LPSTR p;
|
|
|
|
if (DBCSLeadByteTable == NULL)
|
|
{
|
|
_asm {
|
|
push ds
|
|
mov ax,6300h
|
|
int 21h
|
|
mov off,si
|
|
mov segs,ds
|
|
pop ds
|
|
}
|
|
FP_OFF(DBCSLeadByteTable) = off;
|
|
FP_SEG(DBCSLeadByteTable) = segs;
|
|
}
|
|
|
|
p = DBCSLeadByteTable;
|
|
while (p[0] || p[1])
|
|
{
|
|
if (chr >= p[0] && chr <= p[1])
|
|
return TRUE;
|
|
p += 2;
|
|
}
|
|
return FALSE;
|
|
}
|
|
#endif // WIN32
|
|
#endif // DBCS
|