#include #include #include #include #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