/*++ Copyright (c) 1998 Microsoft Corporation Module Name: regrep.c Abstract: Implements a registry search/replace tool. Author: Jim Schmidt (jimschm) 19-Apr-1999 Revision History: jimschm 26-May-1999 Moved from win9xupg, ported to use different utilities --*/ #include "pch.h" VOID pUpdateKeyNames ( IN PCWSTR Search, IN PCWSTR Replace, IN PCWSTR RootKey ); VOID pUpdateValueNames ( IN PCWSTR Search, IN PCWSTR Replace, IN PCWSTR RootKey ); VOID pUpdateValueData ( IN PCWSTR Search, IN PCWSTR Replace, IN PCWSTR RootKey ); PWSTR AppendWackW ( IN PWSTR str ) { PCWSTR Last; if (!str) return str; if (*str) { str = GetEndOfStringW (str); Last = str - 1; } else { Last = str; } if (*Last != '\\') { *str = L'\\'; str++; *str = 0; } return str; } VOID RegistrySearchAndReplaceW ( IN PCWSTR Root, IN PCWSTR Search, IN PCWSTR Replace ) { pUpdateKeyNames (Search, Replace, Root); pUpdateValueNames (Search, Replace, Root); pUpdateValueData (Search, Replace, Root); } PCWSTR _wcsistr ( PCWSTR wstrStr, PCWSTR wstrSubStr ) { PCWSTR wstrStart, wstrStrPos, wstrSubStrPos; PCWSTR wstrEnd; wstrEnd = (PWSTR) ((LPBYTE) wstrStr + ByteCountW (wstrStr) - ByteCountW (wstrSubStr)); for (wstrStart = wstrStr ; wstrStart <= wstrEnd ; wstrStart++) { wstrStrPos = wstrStart; wstrSubStrPos = wstrSubStr; while (*wstrSubStrPos && towlower (*wstrSubStrPos) == towlower (*wstrStrPos)) { wstrStrPos++; wstrSubStrPos++; } if (!(*wstrSubStrPos)) return wstrStart; } return NULL; } #define DEFAULT_GROW_SIZE 8192 PBYTE GrowBuffer ( IN OUT PGROWBUFFER GrowBuf, IN DWORD SpaceNeeded ) /*++ Routine Description: GrowBuffer makes sure there is enough bytes in the buffer to accomodate SpaceNeeded. It allocates an initial buffer when no buffer is allocated, and it reallocates the buffer in increments of GrowBuf->Size (or DEFAULT_GROW_SIZE) when needed. Arguments: GrowBuf - A pointer to a GROWBUFFER structure. Initialize this structure to zero for the first call to GrowBuffer. SpaceNeeded - The number of free bytes needed in the buffer Return Value: A pointer to the SpaceNeeded bytes, or NULL if a memory allocation error occurred. --*/ { PBYTE NewBuffer; DWORD TotalSpaceNeeded; DWORD GrowTo; if (!GrowBuf->Buf) { GrowBuf->Size = 0; GrowBuf->End = 0; } if (!GrowBuf->GrowSize) { GrowBuf->GrowSize = DEFAULT_GROW_SIZE; } TotalSpaceNeeded = GrowBuf->End + SpaceNeeded; if (TotalSpaceNeeded > GrowBuf->Size) { GrowTo = (TotalSpaceNeeded + GrowBuf->GrowSize) - (TotalSpaceNeeded % GrowBuf->GrowSize); } else { GrowTo = 0; } if (!GrowBuf->Buf) { GrowBuf->Buf = (PBYTE) MemAlloc (GrowTo); if (!GrowBuf->Buf) { DEBUGMSG ((DM_WARNING, "GrowBuffer: Initial alloc failed")); return NULL; } GrowBuf->Size = GrowTo; } else if (GrowTo) { NewBuffer = MemReAlloc (GrowBuf->Buf, GrowTo); if (!NewBuffer) { DEBUGMSG ((DM_WARNING, "GrowBuffer: Realloc failed")); return NULL; } GrowBuf->Size = GrowTo; GrowBuf->Buf = NewBuffer; } NewBuffer = GrowBuf->Buf + GrowBuf->End; GrowBuf->End += SpaceNeeded; return NewBuffer; } VOID FreeGrowBuffer ( IN PGROWBUFFER GrowBuf ) /*++ Routine Description: FreeGrowBuffer frees a buffer allocated by GrowBuffer. Arguments: GrowBuf - A pointer to the same structure passed to GrowBuffer Return Value: none --*/ { if (GrowBuf->Buf) { MemFree (GrowBuf->Buf); ZeroMemory (GrowBuf, sizeof (GROWBUFFER)); } } #define INSERT_LAST 0xffffffff PBYTE pGrowListAdd ( IN OUT PGROWLIST GrowList, IN UINT InsertBefore, IN PBYTE DataToAdd, OPTIONAL IN UINT SizeOfData, IN UINT NulBytesToAdd ) /*++ Routine Description: pGrowListAdd allocates memory for a binary block by using a pool, and then expands an array of pointers, maintaining a quick-access list. Arguments: GrowList - Specifies the list to add the entry to InsertBefore - Specifies the index of the array element to insert before, or INSERT_LIST to append. DataToAdd - Specifies the binary block of data to add. SizeOfData - Specifies the size of data. NulBytesToAdd - Specifies the number of nul bytes to add to the buffer Return Value: A pointer to the binary block if data was copied into the list, 1 if a list item was created but no data was set for the item, or NULL if an error occurred. --*/ { PBYTE *Item; PBYTE *InsertAt; PBYTE Data; UINT OldEnd; UINT Size; UINT TotalSize; TotalSize = SizeOfData + NulBytesToAdd; // // Allocate pool if necessary // if (!GrowList->ListData) { GrowList->ListData = PoolMemInitNamedPool ("GrowList"); if (!GrowList->ListData) { return NULL; } } // // Expand list array // OldEnd = GrowList->ListArray.End; Item = (PBYTE *) GrowBuffer (&GrowList->ListArray, sizeof (PBYTE)); if (!Item) { return NULL; } // // Copy data // if (DataToAdd || NulBytesToAdd) { Data = PoolMemGetAlignedMemory (GrowList->ListData, TotalSize); if (!Data) { GrowList->ListArray.End = OldEnd; return NULL; } if (DataToAdd) { CopyMemory (Data, DataToAdd, SizeOfData); } if (NulBytesToAdd) { ZeroMemory (Data + SizeOfData, NulBytesToAdd); } } else { Data = NULL; } // // Adjust array // Size = GrowListGetSize (GrowList); if (InsertBefore >= Size) { // // Append mode // *Item = Data; } else { // // Insert mode // InsertAt = (PBYTE *) (GrowList->ListArray.Buf) + InsertBefore; MoveMemory (&InsertAt[1], InsertAt, (Size - InsertBefore) * sizeof (PBYTE)); *InsertAt = Data; } return Data ? Data : (PBYTE) 1; } VOID FreeGrowList ( IN PGROWLIST GrowList ) /*++ Routine Description: FreeGrowList frees the resources allocated by a GROWLIST. Arguments: GrowList - Specifies the list to clean up Return Value: none --*/ { FreeGrowBuffer (&GrowList->ListArray); if (GrowList->ListData) { PoolMemDestroyPool (GrowList->ListData); } ZeroMemory (GrowList, sizeof (GROWLIST)); } PBYTE GrowListGetItem ( IN PGROWLIST GrowList, IN UINT Index ) /*++ Routine Description: GrowListGetItem returns a pointer to the block of data for item specified by Index. Arguments: GrowList - Specifies the list to access Index - Specifies zero-based index of item in list to access Return Value: A pointer to the item's data, or NULL if the Index does not represent an actual item. --*/ { PBYTE *ItemPtr; UINT Size; Size = GrowListGetSize (GrowList); if (Index >= Size) { return NULL; } ItemPtr = (PBYTE *) (GrowList->ListArray.Buf); return ItemPtr[Index]; } UINT GrowListGetSize ( IN PGROWLIST GrowList ) /*++ Routine Description: GrowListGetSize calculates the number of items in the list. Arguments: GrowList - Specifies the list to calculate the size of Return Value: The number of items in the list, or zero if the list is empty. --*/ { return GrowList->ListArray.End / sizeof (PBYTE); } PBYTE GrowListAppend ( IN OUT PGROWLIST GrowList, IN PBYTE DataToAppend, OPTIONAL IN UINT SizeOfData ) /*++ Routine Description: GrowListAppend appends a black of data as a new list item. Arguments: GrowList - Specifies the list to modify DataToAppend - Specifies a block of data to be copied SizeOfData - Specifies the number of bytes in DataToAppend Return Value: A pointer to the binary block if data was copied into the list, 1 if a list item was created but no data was set for the item, or NULL if an error occurred. --*/ { return pGrowListAdd (GrowList, INSERT_LAST, DataToAppend, SizeOfData, 0); } VOID pMoveKey ( IN PCWSTR SourceKey, IN PCWSTR DestKey ) { HKEY Src; HKEY Dest; REGVALUE_ENUM e; DWORD Size; PBYTE Data; LONG rc; GROWBUFFER Buf = GROWBUF_INIT; Src = OpenRegKeyStr (SourceKey); Dest = CreateRegKeyStr (DestKey); if (Src && Dest) { if (EnumFirstRegValue (&e, Src)) { Buf.End = 0; Data = GrowBuffer (&Buf, e.DataSize); if (Data) { Size = e.DataSize; rc = RegQueryValueEx ( Src, e.ValueName, NULL, NULL, Data, &Size ); if (rc == ERROR_SUCCESS) { rc = RegSetValueEx (Dest, e.ValueName, 0, e.Type, Data, Size); } } } } CloseRegKey (Src); CloseRegKey (Dest); FreeGrowBuffer (&Buf); } PBYTE RealGrowListAppendAddNul ( IN OUT PGROWLIST GrowList, IN PBYTE DataToAppend, OPTIONAL IN UINT SizeOfData ) /*++ Routine Description: GrowListAppend appends a black of data as a new list item and appends two zero bytes (used for string termination). Arguments: GrowList - Specifies the list to modify DataToAppend - Specifies a block of data to be copied SizeOfData - Specifies the number of bytes in DataToAppend Return Value: A pointer to the binary block if data was copied into the list, 1 if a list item was created but no data was set for the item, or NULL if an error occurred. --*/ { return pGrowListAdd (GrowList, INSERT_LAST, DataToAppend, SizeOfData, 2); } UINT CountInstancesOfSubStringW ( IN PCWSTR SourceString, IN PCWSTR SearchString, IN UINT SearchChars ) { UINT Count; UINT SourceChars; PCWSTR End; Count = 0; SourceChars = lstrlenW (SourceString); End = SourceString + SourceChars - SearchChars; if (!SearchChars) { return 0; } while (SourceString <= End) { if (!_wcsnicmp (SourceString, SearchString, SearchChars)) { Count++; SourceString += SearchChars; } else { SourceString++; } } return Count; } PCWSTR StringSearchAndReplaceW ( IN PCWSTR SourceString, IN PCWSTR SearchString, IN PCWSTR ReplaceString ) { PWSTR NewString; PBYTE p; PBYTE Dest; UINT Count; UINT Size; UINT SearchBytes; UINT ReplaceBytes; UINT SearchChars; // // Count occurances within the string // SearchBytes = ByteCountW (SearchString); SearchChars = SearchBytes / sizeof (WCHAR); ReplaceBytes = ByteCountW (ReplaceString); Count = CountInstancesOfSubStringW ( SourceString, SearchString, SearchChars ); if (!Count) { return NULL; } Size = SizeOfStringW (SourceString) - Count * SearchBytes + Count * ReplaceBytes; NewString = (PWSTR) MemAlloc (Size); if (!NewString) { return NULL; } p = (PBYTE) SourceString; Dest = (PBYTE) NewString; while (*((PWSTR) p)) { if (!_wcsnicmp ((PWSTR) p, SearchString, SearchChars)) { CopyMemory (Dest, ReplaceString, ReplaceBytes); Dest += ReplaceBytes; p += SearchBytes; } else { *((PWSTR) Dest) = *((PWSTR) p); p += sizeof (WCHAR); Dest += sizeof (WCHAR); } } *((PWSTR) Dest) = 0; return NewString; } VOID pMoveKeyTree ( IN PCWSTR SourceKey, IN PCWSTR DestKey ) { REGTREE_ENUM e; WCHAR DestSubKey[MAX_PATH]; PWSTR p; GROWLIST List = GROWLIST_INIT; UINT Count; UINT u; PCWSTR Item; DWORD Len; lstrcpyW (DestSubKey, DestKey); p = AppendWackW (DestSubKey); if (EnumFirstRegKeyInTree (&e, SourceKey)) { do { lstrcpyW (p, (PCWSTR) ((PBYTE) e.FullKeyName + e.EnumBaseBytes)); pMoveKey (e.FullKeyName, DestSubKey); GrowListAppendString (&List, e.FullKeyName); } while (EnumNextRegKeyInTree (&e)); } Count = GrowListGetSize (&List); u = Count; while (u > 0) { u--; Item = GrowListGetString (&List, u); ConvertRootStringToKey (Item, &Len); RegDeleteKey (ConvertRootStringToKey (Item, NULL), Item + Len); } FreeGrowList (&List); } VOID pUpdateKeyNames ( IN PCWSTR Search, IN PCWSTR Replace, IN PCWSTR RootKey ) { REGTREE_ENUM e; GROWLIST List = GROWLIST_INIT; UINT Count; UINT u; PCWSTR OldKey; PCWSTR NewKey; if (EnumFirstRegKeyInTree (&e, RootKey)) { do { if (_wcsistr (e.CurrentKey->KeyName, Search)) { GrowListAppendString (&List, e.FullKeyName); } } while (EnumNextRegKeyInTree (&e)); } Count = GrowListGetSize (&List); u = Count; while (u > 0) { u--; OldKey = GrowListGetString (&List, u); NewKey = StringSearchAndReplaceW ( OldKey, Search, Replace ); pMoveKeyTree (OldKey, NewKey); } FreeGrowList (&List); } VOID pUpdateValueNames ( IN PCWSTR Search, IN PCWSTR Replace, IN PCWSTR RootKey ) { REGTREE_ENUM e; REGVALUE_ENUM ev; GROWLIST List = GROWLIST_INIT; HKEY Key; UINT Count; UINT u; PBYTE Data; DWORD Type; DWORD Size; PCWSTR ValueName; PCWSTR NewValueName; BOOL b; LONG rc; if (EnumFirstRegKeyInTree (&e, RootKey)) { do { Key = OpenRegKeyStr (e.FullKeyName); if (Key) { if (EnumFirstRegValue (&ev, Key)) { do { if (_wcsistr (ev.ValueName, Search)) { GrowListAppendString (&List, ev.ValueName); } } while (EnumNextRegValue (&ev)); Count = GrowListGetSize (&List); u = Count; while (u > 0) { u--; ValueName = GrowListGetString (&List, u); b = FALSE; if (GetRegValueTypeAndSize (Key, ValueName, &Type, &Size)) { Data = GetRegValueData (Key, ValueName); if (Data) { NewValueName = StringSearchAndReplaceW ( ValueName, Search, Replace ); rc = RegSetValueEx (Key, NewValueName, 0, Type, Data, Size); if (rc == ERROR_SUCCESS) { if (lstrcmpiW (ValueName, NewValueName)) { rc = RegDeleteValue (Key, ValueName); } } MemFree (Data); MemFree ((PVOID) NewValueName); SetLastError (rc); b = (rc == ERROR_SUCCESS); } } } } FreeGrowList (&List); CloseRegKey (Key); } } while (EnumNextRegKeyInTree (&e)); } } VOID pUpdateValueData ( IN PCWSTR Search, IN PCWSTR Replace, IN PCWSTR RootKey ) { REGTREE_ENUM e; REGVALUE_ENUM ev; HKEY Key; PCWSTR Data; PCWSTR NewData; LONG rc; if (EnumFirstRegKeyInTree (&e, RootKey)) { do { Key = OpenRegKeyStr (e.FullKeyName); if (Key) { if (EnumFirstRegValue (&ev, Key)) { do { Data = GetRegValueString (Key, ev.ValueName); if (Data) { if (_wcsistr (Data, Search)) { NewData = StringSearchAndReplaceW (Data, Search, Replace); rc = RegSetValueEx (Key, ev.ValueName, 0, ev.Type, (PBYTE) NewData, SizeOfStringW (NewData)); MemFree ((PVOID) NewData); } MemFree ((PVOID) Data); } } while (EnumNextRegValue (&ev)); } CloseRegKey (Key); } } while (EnumNextRegKeyInTree (&e)); } }