UTILS.C
/*++ 
 
Copyright (c) 1997 Microsoft Corporation 
 
Module Name: 
 
    utils.c 
 
Abstract: 
 
    This source file implements utility functions used by scrnsave.c. 
 
Author: 
 
    Jim Schmidt (jimschm) 11-Apr-1997 
 
Revision History: 
 
 
--*/ 
 
#include "pch.h" 
 
#ifdef UNICODE 
#error UNICODE cannot be defined 
#endif 
 
// 
// Declare strings 
// 
 
#define DEFMAC(var,str) CHAR var[] = str; 
DEFINE_STRINGS 
#undef DEFMAC 
 
// 
// Temporary buffer 
// 
 
static CHAR g_Data[MAX_PATH]; 
 
// 
// Buffer for string representation of registry keys (for error logging) 
// 
 
typedef struct _tagKEYTOSTR { 
    struct _tagKEYTOSTR *Prev, *Next; 
    HKEY Key; 
    CHAR RegKey[]; 
} KEYTOSTR, *PKEYTOSTR; 
 
static PKEYTOSTR g_Head = NULL; 
 
VOID 
pAddKeyToStrMapping ( 
    IN      HKEY Key, 
    IN      LPCSTR RootStr, 
    IN      LPCSTR KeyStr 
    ) 
{ 
    PKEYTOSTR Node; 
    DWORD Size; 
    CHAR FullKeyStr[MAX_PATH]; 
 
    // We control RootStr and KeyStr, so we know it is less than MAX_PATH in length 
    wsprintf (FullKeyStr, "%s\\%s", RootStr, KeyStr); 
 
    Size = sizeof (KEYTOSTR) + CountStringBytes (FullKeyStr); 
 
    Node = (PKEYTOSTR) HeapAlloc (g_hHeap, 0, Size); 
    if (Node) { 
        Node->Prev = NULL; 
        Node->Next = g_Head; 
        Node->Key = Key; 
        _mbscpy (Node->RegKey, FullKeyStr); 
 
        if (g_Head) { 
            g_Head->Prev = Node; 
        } 
        g_Head = Node; 
    } 
} 
 
PKEYTOSTR 
pFindKeyToStrMapping ( 
    IN      HKEY Key 
    ) 
{ 
    PKEYTOSTR Node; 
 
    Node = g_Head; 
    while (Node) { 
        if (Node->Key == Key) { 
            return Node; 
        } 
        Node = Node->Next; 
    } 
 
    return NULL; 
} 
 
VOID 
pRemoveKeyToStrMapping ( 
    IN      HKEY Key 
    ) 
{ 
    PKEYTOSTR Node; 
 
    Node = pFindKeyToStrMapping (Key); 
    if (!Node) { 
        return; 
    } 
 
    if (Node->Prev) { 
        Node->Prev->Next = Node->Next; 
    } else { 
        g_Head = Node->Next; 
    } 
 
    if (Node->Next) { 
        Node->Next->Prev = Node->Prev; 
    } 
 
    HeapFree (g_hHeap, 0, Node); 
} 
     
 
VOID 
LogRegistryError ( 
    IN      HKEY Key, 
    IN      LPCSTR ValueName 
    ) 
{ 
    DWORD rc = GetLastError(); 
    CHAR Msg[512]; 
    LPCSTR FullKeyStr; 
    PKEYTOSTR Node; 
 
    Node = pFindKeyToStrMapping (Key); 
    if (Node) { 
        FullKeyStr = Node->RegKey; 
    } else { 
        FullKeyStr = S_DEFAULT_KEYSTR; 
    } 
 
    wsprintf (Msg, S_REGISTRY_ERROR, g_User, rc, FullKeyStr, ValueName); 
    SetupLogError (Msg, LogSevError); 
} 
 
 
VOID 
GenerateFilePaths ( 
    VOID 
    ) 
{ 
    INT Len; 
 
    // Safety (unexpected condition) 
    if (!g_WorkingDirectory) { 
        return; 
    } 
 
    Len = CountStringBytes (g_WorkingDirectory) + sizeof(S_SETTINGS_MASK); 
    g_SettingsFile = (LPSTR) HeapAlloc (g_hHeap, 0, Len); 
    if (!g_SettingsFile) { 
        return; 
    } 
    wsprintf (g_SettingsFile, S_SETTINGS_MASK, g_WorkingDirectory); 
 
    Len = CountStringBytes (g_WorkingDirectory) + sizeof(S_MIGINF_MASK); 
    g_MigrateDotInf = (LPSTR) HeapAlloc (g_hHeap, 0, Len); 
    if (!g_MigrateDotInf) { 
        return; 
    } 
    wsprintf (g_MigrateDotInf, S_MIGINF_MASK, g_WorkingDirectory); 
} 
 
 
HKEY 
OpenRegKey ( 
    IN      HKEY RootKey, 
    IN      LPCSTR KeyStr 
    ) 
{ 
    HKEY Key; 
    LONG rc; 
 
    rc = RegOpenKeyEx (RootKey, KeyStr, 0, KEY_ALL_ACCESS, &Key); 
    if (rc != ERROR_SUCCESS) { 
        SetLastError (rc); 
        return NULL; 
    } 
 
    pAddKeyToStrMapping (Key, S_HKR, KeyStr); 
 
    return Key; 
} 
 
 
HKEY 
CreateRegKey ( 
    IN      HKEY RootKey, 
    IN      LPCSTR KeyStr 
    ) 
{ 
    HKEY Key; 
    LONG rc; 
    DWORD DontCare; 
 
    pAddKeyToStrMapping (NULL, S_HKR, KeyStr); 
 
    rc = RegCreateKeyEx (RootKey, KeyStr, 0, S_EMPTY, 0,  
                         KEY_ALL_ACCESS, NULL, &Key, &DontCare); 
    if (rc != ERROR_SUCCESS) { 
        SetLastError (rc); 
        LogRegistryError (NULL, S_EMPTY); 
        pRemoveKeyToStrMapping (NULL); 
        return NULL; 
    } 
 
    pRemoveKeyToStrMapping (NULL); 
    pAddKeyToStrMapping (Key, S_HKR, KeyStr); 
 
    return Key; 
} 
 
VOID 
CloseRegKey ( 
    IN      HKEY Key 
    ) 
{ 
    pRemoveKeyToStrMapping (Key); 
    RegCloseKey (Key); 
} 
 
 
LPCSTR 
GetRegValueString ( 
    IN      HKEY Key, 
    IN      LPCSTR ValueName 
    ) 
{ 
    static CHAR DataBuf[MAX_PATH]; 
    DWORD Size; 
    LONG rc; 
    DWORD Type; 
    DWORD d; 
 
    Size = MAX_PATH; 
    rc = RegQueryValueEx (Key, ValueName, NULL, &Type, DataBuf, &Size); 
    SetLastError (rc); 
 
    if (rc != ERROR_SUCCESS) { 
        return NULL; 
    } 
 
    if (Type == REG_DWORD) { 
        d = *((PDWORD) DataBuf); 
        wsprintf (DataBuf, "%u", d); 
    } 
    else if (Type != REG_SZ) { 
        return NULL; 
    } 
 
    return DataBuf; 
} 
 
BOOL 
SetRegValueString ( 
    HKEY Key, 
    LPCSTR ValueName, 
    LPCSTR ValueStr 
    ) 
{ 
    LONG rc; 
    LPCSTR p; 
 
    p = _mbschr (ValueStr, 0); 
    p++; 
 
    rc = RegSetValueEx (Key, ValueName, 0, REG_SZ, ValueStr, p - ValueStr); 
    SetLastError (rc); 
 
    if (rc != ERROR_SUCCESS) { 
        LogRegistryError (Key, ValueName); 
    } 
 
    return rc == ERROR_SUCCESS; 
} 
 
 
LPCSTR 
GetScrnSaveExe ( 
    VOID 
    ) 
{ 
    CHAR IniFileSetting[MAX_PATH]; 
 
    GetPrivateProfileString ( 
            S_BOOT,  
            S_SCRNSAVE_EXE,  
            S_EMPTY,  
            IniFileSetting,  
            MAX_PATH,  
            S_SYSTEM_INI 
            ); 
 
    if (!IniFileSetting[0]) { 
        return NULL; 
    } 
 
    if (!OurGetLongPathName (IniFileSetting, g_Data)) { 
        // File does not exist 
        return NULL; 
    } 
 
    return g_Data[0] ? g_Data : NULL; 
} 
 
INT 
_mbsbytes ( 
    IN      LPCSTR str 
    ) 
{ 
    LPCSTR p; 
 
    // Find the nul terminator and return the number of bytes 
    // occupied by the characters in the string, but don't 
    // include the nul. 
 
    p = _mbschr (str, 0); 
    return (p - str); 
} 
 
 
DWORD 
CountStringBytes ( 
    IN      LPCSTR str 
    ) 
{ 
    // Return bytes in string, plus 1 for the nul 
    return _mbsbytes (str) + 1; 
} 
 
DWORD 
CountMultiStringBytes ( 
    IN      LPCSTR str 
    ) 
{ 
    LPCSTR p; 
    INT Total = 0; 
    INT Bytes; 
 
    p = str; 
 
    do { 
        Bytes = CountStringBytes (p); 
        p += Bytes; 
        Total += Bytes; 
    } while (Bytes > 1); 
 
    return Total; 
} 
 
 
LPSTR 
CopyStringAtoB ( 
    OUT     LPSTR mbstrDest,  
    IN      LPCSTR mbstrStart,  
    IN      LPCSTR mbstrEnd     // first char NOT to copy 
    ) 
{ 
    LPSTR mbstrOrg; 
 
    mbstrOrg = mbstrDest; 
 
    // Assume mbstrEnd is on a lead byte 
 
    while (mbstrStart < mbstrEnd) { 
        if (isleadbyte (*mbstrStart)) { 
            *mbstrDest = *mbstrStart; 
            mbstrDest++; 
            mbstrStart++; 
        } 
 
        *mbstrDest = *mbstrStart; 
        mbstrDest++; 
        mbstrStart++; 
    } 
 
    *mbstrDest = 0; 
 
    return mbstrOrg; 
} 
 
LPSTR  
AppendStr ( 
    OUT     LPSTR mbstrDest,  
    IN      LPCSTR mbstrSrc 
    ) 
 
{ 
    // Advance mbstrDest to end of string 
    mbstrDest = _mbschr (mbstrDest, 0); 
 
    // Copy string 
    while (*mbstrSrc) { 
        *mbstrDest = *mbstrSrc++; 
        if (isleadbyte (*mbstrDest)) { 
            mbstrDest++; 
            *mbstrDest = *mbstrSrc++; 
        } 
        mbstrDest++; 
    } 
 
    *mbstrDest = 0; 
 
    return mbstrDest; 
} 
 
 
BOOL 
pFindShortName ( 
    IN      LPCTSTR WhatToFind, 
    OUT     LPTSTR Buffer 
    ) 
{ 
    WIN32_FIND_DATA fd; 
    HANDLE hFind; 
 
    hFind = FindFirstFile (WhatToFind, &fd); 
    if (!hFind) { 
        return FALSE; 
    } 
 
    FindClose (hFind); 
    _mbscpy (Buffer, fd.cFileName); 
 
    return TRUE; 
} 
 
 
BOOL 
OurGetLongPathName ( 
    IN      LPCSTR ShortPath, 
    OUT     LPSTR Buffer 
    ) 
{ 
    CHAR FullPath[MAX_PATH]; 
    LPSTR FilePart; 
    LPSTR BufferEnd; 
    LPSTR p, p2; 
    CHAR c; 
 
    // 
    // Convert ShortPath into complete path name 
    // 
 
    if (!_mbschr (ShortPath, TEXT('\\'))) { 
        if (!SearchPath (NULL, ShortPath, NULL, MAX_PATH, FullPath, &FilePart)) { 
            return FALSE; 
        } 
    } else { 
        GetFullPathName (ShortPath, MAX_PATH, FullPath, &FilePart); 
    } 
 
    // 
    // Convert short path to long path 
    // 
 
    p = FullPath; 
 
    // Don't process non-local paths 
    if (!(*p) || _mbsnextc (_mbsinc (p)) != TEXT(':')) { 
        _mbscpy (Buffer, FullPath); 
        return TRUE; 
    } 
 
    p = _mbsinc (p); 
    p = _mbsinc (p); 
    if (_mbsnextc (p) != TEXT('\\')) { 
        _mbscpy (Buffer, FullPath); 
        return TRUE; 
    } 
     
    // Copy drive letter to buffer 
    p = _mbsinc (p); 
    CopyStringAtoB (Buffer, FullPath, p); 
    BufferEnd = _mbschr (Buffer, 0); 
 
    // Convert each portion of the path 
    do { 
        // Locate end of this file or dir 
        p2 = _mbschr (p, TEXT('\\')); 
        if (!p2) { 
            p = _mbschr (p, 0); 
        } else { 
            p = p2; 
        } 
 
        // Look up file 
        c = *p; 
        *p = 0; 
        if (!pFindShortName (FullPath, BufferEnd)) { 
            return FALSE; 
        } 
        *p = c; 
 
        // Move on to next part of path 
        BufferEnd = _mbschr (BufferEnd, 0); 
        if (*p) { 
            p = _mbsinc (p); 
            BufferEnd = AppendStr (BufferEnd, TEXT("\\")); 
        } 
    } while (*p); 
 
    return TRUE; 
} 
 
 
BOOL 
CreateScreenSaverParamKey ( 
    IN      LPCSTR ScreenSaverName, 
    IN      LPCSTR ValueName, 
    OUT     LPSTR Buffer 
    ) 
{ 
    // 
    // Make sure we cannot create a string bigger than MAX_PATH 
    // 
 
    if (_mbslen (ScreenSaverName) + 4 + _mbslen (ValueName) > MAX_PATH) { 
        return FALSE; 
    } 
 
    // 
    // Format the string with length of screen saver name, screen saver name, 
    // and value name. 
    // 
 
    wsprintf (Buffer, "%03u/%s/%s", _mbslen (ScreenSaverName), ScreenSaverName, ValueName); 
 
    return TRUE; 
} 
 
BOOL 
DecodeScreenSaverParamKey ( 
    IN      LPCSTR EncodedString, 
    OUT     LPSTR ScreenSaverName, 
    OUT     LPSTR ValueName 
    ) 
{ 
    INT Len; 
 
    // 
    // Validate encoded string.  It is in the form of ###/screen saver name/value name. 
    // 
 
    Len = atoi (EncodedString); 
    if (Len < 0 || Len >= MAX_PATH || (Len - 5) > (INT) _mbslen (EncodedString)) { 
        return FALSE; 
    } 
 
    if (EncodedString[3] != '/' || EncodedString[4 + Len] != '/') { 
        return FALSE; 
    } 
 
    if (_mbslen (EncodedString + 5 + Len) >= MAX_PATH) { 
        return FALSE; 
    } 
 
    // 
    // Extract screen saver name and value name 
    // 
 
    _mbsncpy (ScreenSaverName, EncodedString + 4, Len); 
    ScreenSaverName[Len] = 0; 
 
    _mbscpy (ValueName, EncodedString + 5 + Len); 
    return TRUE; 
} 
 
LPSTR 
_mbsistr ( 
    IN      LPCSTR mbstrStr,  
    IN      LPCSTR mbstrSubStr 
    ) 
{ 
    LPCSTR mbstrStart, mbstrStrPos, mbstrSubStrPos; 
    LPCSTR mbstrEnd; 
 
    mbstrEnd = (LPSTR) ((LPBYTE) mbstrStr + _mbsbytes (mbstrStr) - _mbsbytes (mbstrSubStr)); 
 
    for (mbstrStart = mbstrStr ; mbstrStart <= mbstrEnd ; mbstrStart = _mbsinc (mbstrStart)) { 
        mbstrStrPos = mbstrStart; 
        mbstrSubStrPos = mbstrSubStr; 
 
        while (*mbstrSubStrPos &&  
               _mbctolower ((INT) _mbsnextc (mbstrSubStrPos)) == _mbctolower ((INT) _mbsnextc (mbstrStrPos)))  
        { 
            mbstrStrPos = _mbsinc (mbstrStrPos); 
            mbstrSubStrPos = _mbsinc (mbstrSubStrPos); 
        } 
 
        if (!(*mbstrSubStrPos)) 
            return (LPSTR) mbstrStart; 
    } 
 
    return NULL;     
} 
 
VOID 
DeletePartOfString ( 
    IN      LPSTR Buffer, 
    IN      DWORD CharsToDelete 
    ) 
{ 
    LPSTR p; 
    DWORD d; 
 
    p = Buffer; 
    for (d = 0 ; *p && d < CharsToDelete ; d++) { 
        p = _mbsinc (p); 
    } 
 
    if (!(*p)) { 
        *Buffer = 0; 
    } else { 
        MoveMemory (Buffer, p, CountStringBytes(p)); 
    } 
} 
 
VOID 
InsertStringInString ( 
    IN      LPSTR Buffer, 
    IN      LPCSTR StringToInsert 
    ) 
{ 
    DWORD BytesToMove; 
    DWORD BytesOfInsertedString; 
 
    BytesToMove = CountStringBytes (Buffer); 
    BytesOfInsertedString = _mbsbytes(StringToInsert); 
    MoveMemory (Buffer + BytesOfInsertedString,  
                Buffer, 
                BytesToMove 
                ); 
    _mbsncpy (Buffer, StringToInsert, _mbslen (StringToInsert)); 
} 
 
 
VOID 
ConvertSystemToSystem32 ( 
    IN OUT  LPSTR FileName 
    ) 
{ 
    LPSTR p; 
 
    // look for \system\ in the path somewhere 
    p = _mbsistr (FileName, S_SYSTEM_DIR); 
    if (p) { 
        // Remove "\system\" and replace with "\system32\" 
        DeletePartOfString (p, _mbslen (S_SYSTEM_DIR)); 
        InsertStringInString (p, S_SYSTEM32_DIR); 
    } 
}