Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

659 lines
15 KiB

  1. //++
  2. //
  3. // Copyright (c) 1999 Microsoft Corporation
  4. //
  5. // File: commonlib.cpp
  6. //
  7. // Contents: Implements functions used across binaries in SFP
  8. //
  9. //
  10. // History: AshishS Created 07/02/99
  11. //
  12. //--
  13. #include "commonlibh.h"
  14. #ifdef THIS_FILE
  15. #undef THIS_FILE
  16. #endif
  17. static char __szTraceSourceFile[] = __FILE__;
  18. #define THIS_FILE __szTraceSourceFile
  19. //
  20. // #define TRACEID SFPCOMLIBID
  21. //
  22. #define TRACEID 100
  23. #define TOASCII(str) str
  24. #define USES_CONVERSION
  25. //
  26. // MBCS Char Index Function
  27. //
  28. inline LPTSTR CharIndex(LPTSTR pszStr, DWORD idwIndex)
  29. {
  30. #ifdef _MBCS
  31. DWORD cdwIndex;
  32. for( cdwIndex = 0;cdwIndex < idwIndex; cdwIndex++)
  33. {
  34. pszStr = _tcsinc( pszStr );
  35. }
  36. #else
  37. pszStr = pszStr + idwIndex;
  38. #endif
  39. return( pszStr );
  40. }
  41. //
  42. // Calculate the Real size of a MBCS String
  43. //
  44. DWORD StringLengthBytes( LPTSTR pszStr )
  45. {
  46. DWORD cdwNumBytes = 0;
  47. #ifdef _MBCS
  48. for( ; *pszStr; pszStr = _tcsinc( pszTemp ) )
  49. {
  50. cdwNumBytes += _tclen( pszTemp )
  51. }
  52. //
  53. // Add one for the NULL char
  54. //
  55. cdwNumBytes += sizeof( TCHAR );
  56. #else
  57. //
  58. // Return (length+NULL)*sizeof(TCHAR)
  59. //
  60. cdwNumBytes = (_tcslen( pszStr ) + 1) * sizeof(TCHAR);
  61. #endif
  62. return( cdwNumBytes );
  63. }
  64. //
  65. // String Trimming-- this is a quite complicated routine because of all
  66. // the work needed to get around MBCS string manipulation.
  67. //
  68. void TrimString( LPTSTR pszStr )
  69. {
  70. WCHAR *pszStart=NULL;
  71. WCHAR *pszBufStart = NULL;
  72. LONG cStrLen =0;
  73. DWORD cdwOrigSizeBytes;
  74. WCHAR szStrBuf[MAX_BUFFER];
  75. DWORD dwError;
  76. TraceFunctEnter("TrimString");
  77. if( !pszStr )
  78. {
  79. ErrorTrace(TRACEID, "NULL String passed to trim string");
  80. goto cleanup;
  81. }
  82. //
  83. // Find the original size in bytes so we can convert back
  84. // to MBCS later.
  85. //
  86. cdwOrigSizeBytes = StringLengthBytes( pszStr );
  87. #ifndef _UNICODE
  88. if( !MultiByteToWideChar(
  89. GetCurrentCodePage(),
  90. 0,
  91. pszStr,
  92. -1,
  93. szStrBuf,
  94. MAX_BUFFER ) )
  95. {
  96. dwError = GetLastError();
  97. ErrorTrace( TRACEID, "MultiByteToWideChar( ) failed- ec--%d", dwError);
  98. goto cleanup;
  99. }
  100. pszStart = szStrBuf;
  101. pszBufStart = szStrBuf;
  102. #else
  103. pszStart = pszStr;
  104. pszBufStart = pszStr;
  105. #endif
  106. //
  107. // get the first non whitespace characters
  108. //
  109. for( ; (*pszStart == L' ' || *pszStart == L'\t' || *pszStart == L'\n' || *pszStart == L'\r'); pszStart++ )
  110. {
  111. ;
  112. }
  113. cStrLen = wcslen( pszStart );
  114. if( cStrLen == 0 )
  115. {
  116. DebugTrace(TRACEID, "Empty string in Trim String.",0);
  117. goto cleanup;
  118. }
  119. //
  120. // go back before the null char
  121. //
  122. cStrLen--;
  123. while( (cStrLen >= 0) && ( (pszStart[cStrLen] == L' ') || (pszStart[cStrLen] == L'\t' ) || (pszStart[cStrLen] == L'\n' ) || (pszStart[cStrLen] == L'\r' ) ) )
  124. {
  125. pszStart[cStrLen--] = 0;
  126. //pszStart[cStrLen--] = 0;
  127. }
  128. if( cStrLen == -1 )
  129. {
  130. DebugTrace(TRACEID, "Empty string in Trim String.",0);
  131. goto cleanup;
  132. }
  133. //
  134. // Shift the memory back left ( The +2 is because we need to
  135. // move the null and cStrLen is an index value at this point)
  136. //
  137. MoveMemory( (PVOID) pszBufStart, pszStart,(cStrLen + 2)*sizeof(WCHAR) );
  138. //
  139. // Convert back
  140. //
  141. #ifndef _UNICODE
  142. if(!WideCharToMultiByte(
  143. GetCurrentCodePage(), // code page
  144. 0, // performance and mapping flags
  145. pszBufStart, // address of wide-character string
  146. -1, // number of characters in string
  147. pszStr, // address of buffer for new string
  148. cdwOrigSizeBytes, // size of buffer
  149. NULL, // address of default for unmappable
  150. // characters
  151. NULL) ) // address of flag set when default
  152. {
  153. dwError = GetLastError();
  154. ErrorTrace( TRACEID, "MultiByteToWideChar( ) failed- ec--%d", dwError);
  155. goto cleanup;
  156. }
  157. #endif
  158. cleanup:
  159. TraceFunctLeave();
  160. return;
  161. }
  162. //
  163. // A buffer safe string copy. The buffer is in characters.
  164. //
  165. BOOL BufStrCpy(LPTSTR pszBuf, LPTSTR pszSrc, LONG lBufSize)
  166. {
  167. DWORD cdwSrcLen=0;
  168. DWORD cdwBytesUsed=0;
  169. DWORD cdwNumCharsToCopy;
  170. cdwSrcLen = _tcslen( pszSrc );
  171. if( (unsigned) lBufSize >= StringLengthBytes( pszSrc ) )
  172. {
  173. _tcscpy( pszBuf, pszSrc );
  174. return TRUE;
  175. }
  176. #ifdef _MBCS
  177. LPTSTR pszTemp;
  178. DWORD cdwBufLeft;
  179. //Save room for the NULL char
  180. cdwBufLeft = (lBufSize-1) * sizeof(TCHAR);
  181. pszTemp = pszSrc;
  182. cdwNumCharsToCopy = 0;
  183. while( (_tcsnextc(pszTemp) != 0) && ( cdwBufLeft > 0 ) )
  184. {
  185. cdwBufLeft -= _tclen( pszTemp );
  186. pszTemp = _tcsinc( pszTemp );
  187. if( cdwBufLeft > 0 )
  188. {
  189. cdwNumCharsToCopy++;
  190. }
  191. }
  192. #else
  193. cdwNumCharsToCopy = lBufSize - 1;
  194. #endif
  195. _tcsncpy( pszBuf, pszSrc, cdwNumCharsToCopy );
  196. CHARINDEX( pszBuf, cdwNumCharsToCopy ) = 0;
  197. return TRUE;
  198. }
  199. //
  200. // Function: GetLine
  201. // Desc : Gets a line from a file stream, ignores empty lines and
  202. // lines starting with '#'- it also trims off whitespace
  203. // and newline (\n) and return (\r) characters from the input.
  204. // Returns: 0 = Failed or end of st stream
  205. // or
  206. // Length of the string read in ( characters )
  207. //
  208. LONG
  209. GetLine(FILE *fl, LPTSTR pszBuf, LONG lMaxBuf)
  210. {
  211. LONG lRead;
  212. _ASSERT( fl );
  213. _ASSERT( pszBuf );
  214. if( lMaxBuf <= 0 )
  215. {
  216. return( 0 );
  217. }
  218. do
  219. {
  220. pszBuf[0] = 0;
  221. if( _fgetts( pszBuf, lMaxBuf, fl ) == NULL )
  222. {
  223. // our buffer might be too small
  224. return( 0 );
  225. }
  226. // trim the buffer, do it this point so # doesn't get missed because of a space
  227. TrimString( pszBuf );
  228. if( _tcsnextc(pszBuf) == 0 )
  229. {
  230. continue;
  231. }
  232. } while( _tcsnextc(pszBuf) == _TEXT('#') );
  233. lRead = _tcslen( pszBuf );
  234. return( lRead );
  235. }
  236. //
  237. // Function: GetField
  238. // Desc : Gets a field _lNum_ (0 based index) delimited by _chSep_
  239. // from string psmMain and puts it into pszInto. pszInto
  240. // should be >= in size as pszMain since GetField assumes
  241. // there is enough space.
  242. // Returns: 1 -TRUE, 0, FALSE
  243. //
  244. LONG GetField(LPTSTR pszMain, LPTSTR pszInto, LONG lNum, TCHAR chSep)
  245. {
  246. WCHAR *pszP;
  247. WCHAR *pszI;
  248. LONG ToFind;
  249. WCHAR szMainBuf[MAX_BUFFER];
  250. WCHAR szIntoBuf[MAX_BUFFER];
  251. DWORD dwError;
  252. BOOL fReturn = FALSE;
  253. TraceFunctEnter("CXMLFileListParser::GetField");
  254. if(!pszMain || !pszInto)
  255. {
  256. goto cleanup;
  257. }
  258. #ifndef _UNICODE
  259. if( !MultiByteToWideChar(
  260. CP_OEMCP,
  261. 0,
  262. pszMain,
  263. -1,
  264. szMainBuf,
  265. MAX_BUFFER ) )
  266. {
  267. dwError = GetLastError();
  268. ErrorTrace( TRACEID, "MultiByteToWideChar( ) failed- ec--%d", dwError);
  269. goto cleanup;
  270. }
  271. pszP = szMainBuf;
  272. pszI = szIntoBuf;
  273. #else
  274. pszP = pszMain;
  275. pszI = pszInto;
  276. #endif
  277. ToFind = lNum;
  278. while( *pszP != 0 && ToFind > 0)
  279. {
  280. if( *pszP == (WCHAR) ((TBYTE) chSep) )
  281. {
  282. ToFind--;
  283. }
  284. pszP++;
  285. }
  286. if( *pszP == 0 )
  287. {
  288. goto cleanup;
  289. }
  290. while(*pszP != 0 && *pszP != (WCHAR) ((TBYTE) chSep) )
  291. {
  292. *pszI = *pszP;
  293. pszI++;
  294. pszP++;
  295. }
  296. *pszI = 0;
  297. #ifndef _UNICODE
  298. //
  299. // Even though we know by definition the products is smaller than
  300. // the source, we need to get the exact size or otherwise
  301. // WidCharToMultiByte will blow some bounds.
  302. //
  303. if(!WideCharToMultiByte(
  304. CP_OEMCP, // code page
  305. 0, // performance and mapping flags
  306. szIntoBuf, // address of wide-character string
  307. -1, // number of characters in string
  308. pszInto, // address of buffer for new string
  309. StringLengthBytes(pszMain), // size of buffer
  310. NULL, // address of default for unmappable char
  311. NULL) ) // address of flag set when default
  312. {
  313. dwError = GetLastError();
  314. ErrorTrace( TRACEID, "MultiByteToWideChar( ) failed- ec--%d", dwError);
  315. goto cleanup;
  316. }
  317. #endif
  318. fReturn = TRUE;
  319. cleanup:
  320. TraceFunctLeave();
  321. return( fReturn );
  322. }
  323. inline UINT GetCurrentCodePage()
  324. {
  325. //
  326. // the current code page value
  327. //
  328. static UINT uiLocal;
  329. //
  330. // only query once-- by ANSI standard, should init to 0
  331. //
  332. static BOOL fPrevQuery;
  333. TraceFunctEnter("GetCurrentCodePage");
  334. //
  335. // Only bother with the query stuff once
  336. // Load variables onto the stack only when needed.
  337. //
  338. if( FALSE == fPrevQuery )
  339. {
  340. TCHAR *pszCurrent;
  341. // 256 should be able to fit the language name.
  342. TCHAR szBuffer[256];
  343. uiLocal = CP_ACP;
  344. pszCurrent = NULL;
  345. #ifndef UNICODE
  346. pszCurrent = setlocale( LC_CTYPE, "");
  347. #else
  348. pszCurrent = _wsetlocale( LC_CTYPE, L"");
  349. #endif
  350. if( NULL == pszCurrent )
  351. {
  352. ErrorTrace(TRACEID, "Error querying code locale.",0);
  353. goto cleanup;
  354. }
  355. if( FALSE == GetField( pszCurrent, szBuffer, 1, _TEXT('.')) )
  356. {
  357. ErrorTrace(TRACEID, "Error getting code page.",0);
  358. goto cleanup;
  359. }
  360. uiLocal = _ttoi( szBuffer );
  361. // some bugus input
  362. if( uiLocal == 0 )
  363. {
  364. // default to the ansi code page
  365. uiLocal = CP_ACP;
  366. }
  367. fPrevQuery = TRUE;
  368. }
  369. cleanup:
  370. TraceFunctLeave();
  371. return( uiLocal );
  372. }
  373. #define DIFF( a, b ) (INT)(INT_PTR)( (PBYTE)(a) - (PBYTE)(b) )
  374. BOOL
  375. ExpandShortNames(
  376. LPTSTR pFileName,
  377. DWORD cbFileName,
  378. LPTSTR LongName,
  379. DWORD cbLongName
  380. )
  381. {
  382. PTSTR pStart;
  383. PTSTR pEnd;
  384. PTSTR pCurrent;
  385. TCHAR ShortName[MAX_PATH];
  386. DWORD cbShortName = 0, LongNameIndex = 0;
  387. WIN32_FIND_DATA fd;
  388. BOOL bRet = TRUE;
  389. pStart = pFileName;
  390. pCurrent = pFileName;
  391. LongNameIndex = 0;
  392. //
  393. // scan the entire string
  394. //
  395. while (*pCurrent)
  396. {
  397. //
  398. //
  399. // in this example the pointers are like this:
  400. //
  401. // \Device\HarddiskDmVolumes\PhysicalDmVolumes\
  402. // BlockVolume3\Progra~1\office.exe
  403. // ^ ^
  404. // | |
  405. // pStart pEnd
  406. //
  407. // pStart always points to the last seen '\\' .
  408. //
  409. //
  410. // is this a potential start of a path part?
  411. //
  412. if (*pCurrent == L'\\')
  413. {
  414. DWORD cbElem = DIFF(pCurrent, pStart) + sizeof(TCHAR);
  415. if (LongNameIndex + cbElem > cbLongName )
  416. {
  417. bRet = FALSE;
  418. goto End;
  419. }
  420. //
  421. // yes. copy in the dest string and update pStart.
  422. //
  423. RtlCopyMemory( (PBYTE)LongName + LongNameIndex,
  424. pStart,
  425. cbElem ); // include '\\'
  426. LongNameIndex += cbElem;
  427. pStart = pCurrent;
  428. }
  429. //
  430. // does this current path part contain a short version (~)
  431. //
  432. if (*pCurrent == L'~')
  433. {
  434. //
  435. // we need to expand this part.
  436. //
  437. //
  438. // find the end
  439. //
  440. while (*pCurrent != L'\\' && *pCurrent != 0)
  441. {
  442. pCurrent++ ;
  443. }
  444. pEnd = pCurrent;
  445. cbShortName = DIFF(pEnd, pFileName);
  446. CopyMemory( ShortName, pFileName, cbShortName );
  447. ShortName[cbShortName/sizeof(TCHAR)] = 0;
  448. if ( FindFirstFile( ShortName,
  449. &fd ) )
  450. {
  451. DWORD cbElem = (_tcslen(fd.cFileName)+1) * sizeof(TCHAR);
  452. if ((LongNameIndex + cbElem) > cbLongName )
  453. {
  454. bRet = FALSE;
  455. goto End;
  456. }
  457. RtlCopyMemory( (PBYTE)LongName + LongNameIndex,
  458. fd.cFileName,
  459. cbElem ); // include '\\'
  460. LongNameIndex += cbElem;
  461. LongName[(LongNameIndex - sizeof(TCHAR))/sizeof(TCHAR)] =
  462. TEXT('\\');
  463. }
  464. else
  465. {
  466. DWORD cbElem = (_tcslen(ShortName) + 1) * sizeof( TCHAR );
  467. if ((LongNameIndex + cbElem) > cbLongName )
  468. {
  469. bRet = FALSE;
  470. goto End;
  471. }
  472. RtlCopyMemory( (PBYTE)LongName + LongNameIndex,
  473. pStart,
  474. cbElem + sizeof(TCHAR)); // include '\\'
  475. LongNameIndex += cbElem;
  476. }
  477. pStart = pEnd + 1;
  478. if ( *pEnd == TEXT('\\') )
  479. {
  480. pCurrent = pStart;
  481. continue;
  482. }
  483. else
  484. {
  485. pCurrent = pEnd;
  486. }
  487. } // if (*pCurrent == L'~')
  488. pCurrent++;
  489. }
  490. if ( pEnd != pCurrent )
  491. {
  492. DWORD cbElem = DIFF( pCurrent, pStart ) + sizeof(TCHAR);
  493. if ((LongNameIndex + cbElem) > cbLongName )
  494. {
  495. bRet = FALSE;
  496. goto End;
  497. }
  498. RtlCopyMemory( (PBYTE)LongName + LongNameIndex,
  499. pStart,
  500. cbElem); // include '\\'
  501. LongNameIndex += cbElem;
  502. }
  503. LongName[(LongNameIndex - sizeof(TCHAR))/sizeof(TCHAR)] = 0;
  504. End:
  505. return bRet;
  506. } // SrExpandShortNames