/*++ Copyright (c) 1998 Microsoft Corporation Module Name: commonnt.c Abstract: Common functionality between various parts of GUI mode-side processing. The routines in this library are shared only by other LIBs in the w95upgnt tree. Author: Jim Schmidt (jimschm) 18-Aug-1998 Revision History: Name (alias) Date Description --*/ #include "pch.h" #define DBG_DATAFILTER "Data Filter" BOOL WINAPI CommonNt_Entry ( IN HINSTANCE Instance, IN DWORD Reason, IN PVOID lpv ) /*++ Routine Description: CommonNt_Entry is a DllMain-like init funciton, called by w95upgnt\dll. This function is called at process attach and detach. Arguments: Instance - (OS-supplied) instance handle for the DLL Reason - (OS-supplied) indicates attach or detatch from process or thread lpv - unused Return Value: Return value is always TRUE (indicating successful init). --*/ { switch (Reason) { case DLL_PROCESS_ATTACH: // Nothing to do... break; case DLL_PROCESS_DETACH: // Nothing to do... break; } return TRUE; } typedef enum { STATE_NO_PATH, STATE_PATH_FOUND, STATE_IN_PATH, STATE_PATH_CHANGED, STATE_PATH_DELETED, STATE_LONG_PATH_CHANGED, STATE_SHORT_PATH_CHANGED, STATE_RETURN_PATH } SCANSTATE; BOOL pIsPathSeparator ( CHARTYPE ch ) { return ch == 0 || ch == TEXT(',') || ch == TEXT(';') || _istspace (ch) != 0; } BOOL pIsValidPathCharacter ( CHARTYPE ch ) { if (_istalnum (ch)) { return TRUE; } if (ch == TEXT(',') || ch == TEXT(';') || ch == TEXT('\"') || ch == TEXT('<') || ch == TEXT('>') || ch == TEXT('|') || ch == TEXT('?') || ch == TEXT('*') ) { return FALSE; } return TRUE; } CONVERTPATH_RC pGetReplacementPath ( IN PCTSTR DataStart, IN PCTSTR Pos, OUT PCTSTR *OldStart, OUT PCTSTR *OldEnd, OUT PTSTR ReplacementStr ) { CONVERTPATH_RC rc = CONVERTPATH_NOT_REMAPPED; SCANSTATE State; BOOL DontIncrement; PCTSTR OrgStart = NULL; TCHAR PathBuffer[MAX_TCHAR_PATH + 2]; TCHAR RenamedFile[MAX_TCHAR_PATH]; PTSTR PathBufferRoot = NULL; PTSTR PathBufferPtr = NULL; CONVERTPATH_RC ConvertCode = 0; BOOL ShortPath = FALSE; BOOL QuotesOn = FALSE; BOOL Done = FALSE; BOOL OrgPathHasSepChar = FALSE; BOOL NeedQuotes = FALSE; BOOL PathSepChar; PCTSTR p; BOOL QuotesOnColumn = FALSE; PCTSTR LastPathPosition = NULL; State = STATE_NO_PATH; PathBuffer[0] = TEXT('\"'); // // Scan string of Pos for command line // while (!Done) { DontIncrement = FALSE; switch (State) { case STATE_NO_PATH: if (Pos[0] == 0) { Done = TRUE; break; } if (Pos[1] == TEXT(':') && Pos[2] == TEXT('\\')) { if (_istalpha (Pos[0])) { QuotesOn = FALSE; State = STATE_PATH_FOUND; DontIncrement = TRUE; } } else if (Pos[0] == TEXT('\"')) { if (_istalpha (Pos[1]) && Pos[2] == TEXT(':') && Pos[3] == TEXT('\\')) { QuotesOn = TRUE; State = STATE_PATH_FOUND; } } break; case STATE_PATH_FOUND: // // Initialize path attributes // QuotesOnColumn = QuotesOn; LastPathPosition = Pos; OrgStart = Pos; PathBufferRoot = &PathBuffer[1]; PathBufferRoot[0] = Pos[0]; PathBufferRoot[1] = Pos[1]; PathBufferPtr = &PathBufferRoot[2]; Pos = &Pos[2]; ShortPath = FALSE; OrgPathHasSepChar = FALSE; State = STATE_IN_PATH; DontIncrement = TRUE; break; case STATE_IN_PATH: // // Is this a closing quote? If so, look for replacement path // and fail entire string if it's not replaced. // if (Pos[0] == TEXT(':')) { // // bogus. This cannot be a path, it has two ':' characters // Pos = _tcsdec (LastPathPosition, Pos); if (Pos) { Pos = _tcsdec (LastPathPosition, Pos); if (Pos) { if (Pos[0] == TEXT('\"')) { Pos = NULL; } } } if (!Pos) { Pos = LastPathPosition; QuotesOn = QuotesOnColumn; } State = STATE_NO_PATH; break; } if (QuotesOn && *Pos == TEXT('\"')) { *PathBufferPtr = 0; ConvertCode = ConvertWin9xPath (PathBufferRoot); if (ConvertCode != CONVERTPATH_NOT_REMAPPED) { State = STATE_PATH_CHANGED; DontIncrement = TRUE; break; } State = STATE_NO_PATH; break; } // // Is this a path separator? If so, look in memdb for replacement path. // if (Pos[0] == L'\\') { PathSepChar = pIsPathSeparator ((CHARTYPE) _tcsnextc (Pos + 1)); } else { PathSepChar = pIsPathSeparator ((CHARTYPE) _tcsnextc (Pos)); } if (PathSepChar) { *PathBufferPtr = 0; ConvertCode = ConvertWin9xPath (PathBufferRoot); if (ConvertCode != CONVERTPATH_NOT_REMAPPED) { State = STATE_PATH_CHANGED; DontIncrement = TRUE; break; } } // // Check for end of data // if (Pos[0] == 0) { Done = TRUE; break; } // // Copy path character to buffer, break if we exceed max path length // *PathBufferPtr = *Pos; PathBufferPtr = _tcsinc (PathBufferPtr); if (PathBufferPtr == PathBufferRoot + MAX_TCHAR_PATH) { Pos = OrgStart; State = STATE_NO_PATH; break; } // // Test for short path // if (*Pos == TEXT('~')) { ShortPath = TRUE; } OrgPathHasSepChar |= PathSepChar; break; case STATE_PATH_CHANGED: if (ConvertCode == CONVERTPATH_DELETED) { State = STATE_PATH_DELETED; } else if (ShortPath) { State = STATE_SHORT_PATH_CHANGED; } else { State = STATE_LONG_PATH_CHANGED; } // // If replacement has introduced a path separator, set the // NeedQuotes flag. Quotes will later be added if the path // is only part of the complete string. // NeedQuotes = FALSE; if (!OrgPathHasSepChar) { for (p = PathBufferRoot ; *p ; p = _tcsinc (p)) { if (pIsPathSeparator ((CHARTYPE) _tcsnextc (p))) { NeedQuotes = TRUE; break; } } } DontIncrement = TRUE; break; case STATE_PATH_DELETED: State = STATE_RETURN_PATH; DontIncrement = TRUE; break; case STATE_SHORT_PATH_CHANGED: if (OurGetShortPathName (PathBufferRoot, RenamedFile, MAX_TCHAR_PATH)) { PathBufferRoot = RenamedFile; } State = STATE_RETURN_PATH; DontIncrement = TRUE; break; case STATE_LONG_PATH_CHANGED: if (!QuotesOn && NeedQuotes) { if (OrgStart != DataStart || Pos[0] != 0) { PathBufferPtr = _tcschr (PathBufferRoot, 0); PathBufferPtr[0] = TEXT('\"'); PathBufferPtr[1] = 0; PathBufferRoot = PathBuffer; } } State = STATE_RETURN_PATH; DontIncrement = TRUE; break; case STATE_RETURN_PATH: rc = ConvertCode; StringCopy (ReplacementStr, PathBufferRoot); *OldStart = OrgStart; *OldEnd = Pos; Done = TRUE; break; } if (!DontIncrement) { Pos = _tcsinc (Pos); } } return rc; } BOOL ConvertWin9xCmdLine ( IN OUT PTSTR CmdLine, // MAX_CMDLINE buffer IN PCTSTR ObjectForDbgMsg, OPTIONAL OUT PBOOL PointsToDeletedItem OPTIONAL ) { TCHAR NewCmdLine[MAX_CMDLINE]; TCHAR NewPathBuffer[MAX_TCHAR_PATH]; PCTSTR CmdLineStart; PCTSTR ReplaceStart; PCTSTR ExtraParamsStart; CONVERTPATH_RC ConvertCode; PTSTR EndOfNewCmdLine; UINT End = 0; BOOL NewCmdLineFlag = FALSE; INT Bytes; #ifdef DEBUG TCHAR OriginalCmdLine[MAX_CMDLINE]; StringCopy (OriginalCmdLine, CmdLine); #endif if (PointsToDeletedItem) { *PointsToDeletedItem = FALSE; } *NewCmdLine = 0; ExtraParamsStart = CmdLine; EndOfNewCmdLine = NewCmdLine; for(;;) { CmdLineStart = ExtraParamsStart; // // We must test for a command line argument that has quotes or // doesn't need quotes, and then test for an argument that needs // quotes but doesn't have them. // ConvertCode = pGetReplacementPath ( CmdLine, CmdLineStart, &ReplaceStart, &ExtraParamsStart, NewPathBuffer ); if (ConvertCode == CONVERTPATH_NOT_REMAPPED) { // // Rest of command line does not have changed files // break; } // // If a command line was found, we must replace the text between // ReplaceStart and ExtraParamsStart with NewPathBuffer. To do this, // we copy the unchanged portion (from CmdLineStart to ReplaceStart) // to the caller's buffer, and append the replacement text. The // search continues, searching the rest of the command line specified // by ExtraParamsStart. // if (ConvertCode == CONVERTPATH_DELETED && PointsToDeletedItem) { *PointsToDeletedItem = TRUE; } if (ObjectForDbgMsg) { DEBUGMSG_IF (( ConvertCode == CONVERTPATH_DELETED, DBG_WARNING, "%s still points to the deleted Win9x file %s (command line: %s).", ObjectForDbgMsg, NewPathBuffer, OriginalCmdLine )); } // // Path has changed, so we replace the path in the command line. // End = ((PBYTE) EndOfNewCmdLine - (PBYTE) NewCmdLine) + ((PBYTE) ReplaceStart - (PBYTE) CmdLineStart) + SizeOfString (NewPathBuffer); if (End > sizeof (NewCmdLine)) { LOG ((LOG_ERROR, "Converting CmdLine: Conversion caused buffer overrun - aborting")); return FALSE; } if (ReplaceStart > CmdLineStart) { StringCopyAB (EndOfNewCmdLine, CmdLineStart, ReplaceStart); } EndOfNewCmdLine = _tcsappend (EndOfNewCmdLine, NewPathBuffer); NewCmdLineFlag |= (ConvertCode == CONVERTPATH_REMAPPED); } if (NewCmdLineFlag) { // // We have changed the command line, so complete the processing. // if (ExtraParamsStart && *ExtraParamsStart) { End = (PBYTE) EndOfNewCmdLine - (PBYTE) NewCmdLine + SizeOfString (ExtraParamsStart); if (End > sizeof (NewCmdLine)) { LOG ((LOG_ERROR, "Converting CmdLine: Conversion caused buffer overrun -- aborting (2)")); return FALSE; } StringCopy (EndOfNewCmdLine, ExtraParamsStart); } // // End is the number of bytes in NewCmdLine // Bytes = (INT) End - sizeof(TCHAR); } else { // // No changes yet, initialize Bytes // Bytes = (INT) ByteCount (CmdLine); } // // In-place string conversion, first look for a complete match, and when // that fails, look for a partial match. // if (MappingSearchAndReplaceEx ( g_CompleteMatchMap, NewCmdLineFlag ? NewCmdLine : CmdLine, NewCmdLine, Bytes, NULL, sizeof (NewCmdLine), STRMAP_COMPLETE_MATCH_ONLY, NULL, NULL )) { NewCmdLineFlag = TRUE; } else { NewCmdLineFlag |= MappingSearchAndReplaceEx ( g_SubStringMap, NewCmdLineFlag ? NewCmdLine : CmdLine, NewCmdLine, Bytes, NULL, sizeof (NewCmdLine), STRMAP_ANY_MATCH, NULL, NULL ); } if (NewCmdLineFlag) { DEBUGMSG (( DBG_DATAFILTER, "Command line %s was modified to %s", OriginalCmdLine, NewCmdLine )); StringCopy (CmdLine, NewCmdLine); } return NewCmdLineFlag; }