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.

1003 lines
28 KiB

  1. /*++
  2. Copyright (C) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. PREPROC.CPP
  5. Abstract:
  6. Implementation for the preprocessor.
  7. History:
  8. a-davj 6-april-99 Created.
  9. --*/
  10. #include "precomp.h"
  11. #include <arrtempl.h>
  12. #include "trace.h"
  13. #include "moflex.h"
  14. #include "preproc.h"
  15. #include <wbemcli.h>
  16. #include <io.h>
  17. #include "bmof.h"
  18. #include "strings.h"
  19. #define HR_LASTERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError() )
  20. //***************************************************************************
  21. //
  22. // WriteLineAndFilePragma
  23. //
  24. // DESCRIPTION:
  25. //
  26. // Write the line into the temp file which indicates what file and line number
  27. // is to follow.
  28. //
  29. //***************************************************************************
  30. #define MAX_PRAGMA_BUFF (2*MAX_PATH + 23)
  31. void WriteLineAndFilePragma(FILE * pFile, const TCHAR * pFileName, int iLine)
  32. {
  33. WCHAR wTemp[MAX_PRAGMA_BUFF];
  34. WCHAR * pTo;
  35. const WCHAR * pFr;
  36. StringCchPrintfW (wTemp, MAX_PRAGMA_BUFF, L"#line %d \"", iLine);
  37. int iLen = wcslen(wTemp);
  38. for(pFr = pFileName, pTo = wTemp+iLen; *pFr && iLen < MAX_PRAGMA_BUFF-5; pFr++, pTo++, iLen++)
  39. {
  40. *pTo = *pFr;
  41. if(*pFr == L'\\')
  42. {
  43. pTo++;
  44. *pTo = L'\\';
  45. iLen++;
  46. }
  47. }
  48. *pTo = 0;
  49. StringCchCatW(wTemp, MAX_PRAGMA_BUFF, L"\"\r\n");
  50. WriteLine(pFile, wTemp);
  51. }
  52. //***************************************************************************
  53. //
  54. // WriteLine(FILE * pFile, WCHAR * pLine)
  55. //
  56. // DESCRIPTION:
  57. //
  58. // Writes a single line out to the temporary file.
  59. //
  60. //***************************************************************************
  61. void WriteLine(FILE * pFile, WCHAR * pLine)
  62. {
  63. fwrite(pLine, 2, wcslen(pLine), pFile);
  64. }
  65. //***************************************************************************
  66. //
  67. // IsBMOFBuffer
  68. //
  69. // DESCRIPTION:
  70. //
  71. // Used to check if a buffer is the start of a binary mof.
  72. //
  73. //***************************************************************************
  74. bool IsBMOFBuffer(byte * pTest, DWORD & dwCompressedSize, DWORD & dwExpandedSize)
  75. {
  76. DWORD dwSig = BMOF_SIG;
  77. if(0 == memcmp(pTest, &dwSig, sizeof(DWORD)))
  78. {
  79. // ignore the compression type, and the Compressed Size
  80. pTest += 2*sizeof(DWORD);
  81. memcpy(&dwCompressedSize, pTest, sizeof(DWORD));
  82. pTest += sizeof(DWORD);
  83. memcpy(&dwExpandedSize, pTest, sizeof(DWORD));
  84. return true;
  85. }
  86. return false;
  87. }
  88. //***************************************************************************
  89. //
  90. // IsBinaryFile
  91. //
  92. // DESCRIPTION:
  93. //
  94. // returns true if the file contains a binary mof.
  95. //
  96. //***************************************************************************
  97. #ifdef USE_MMF_APPROACH
  98. bool IsBinaryFile(BYTE * pData,DWORD dwSize)
  99. {
  100. if(dwSize < TEST_SIZE)
  101. {
  102. // if we cant read even the header, it must not be a BMOF
  103. return false;
  104. }
  105. DWORD dwCompressedSize, dwExpandedSize;
  106. // Test if the mof is binary
  107. if(!IsBMOFBuffer(pData, dwCompressedSize, dwExpandedSize))
  108. {
  109. // not a binary mof. This is the typical case
  110. return false;
  111. }
  112. return true;
  113. }
  114. #else
  115. bool IsBinaryFile(FILE * fp)
  116. {
  117. // read the first 20 bytes
  118. BYTE Test[TEST_SIZE];
  119. int iRet = fread(Test, 1, TEST_SIZE, fp);
  120. if( fseek(fp, 0, SEEK_SET) ) return false;
  121. if(iRet != TEST_SIZE)
  122. {
  123. // if we cant read even the header, it must not be a BMOF
  124. return false;
  125. }
  126. DWORD dwCompressedSize, dwExpandedSize;
  127. // Test if the mof is binary
  128. if(!IsBMOFBuffer(Test, dwCompressedSize, dwExpandedSize))
  129. {
  130. // not a binary mof. This is the typical case
  131. return false;
  132. }
  133. return true;
  134. }
  135. #endif
  136. //***************************************************************************
  137. //
  138. // CheckForUnicodeEndian
  139. //
  140. // DESCRIPTION:
  141. //
  142. // Examines the first couple of bytes in a file and determines if the file
  143. // is in unicode and if so, if it is big endian. It is assumed that the
  144. // file is pointing to the start and if the file is unicode, the pointer
  145. // is left at the first actual data byte.
  146. //
  147. //***************************************************************************
  148. #ifdef USE_MMF_APPROACH
  149. void CheckForUnicodeEndian(BYTE * &pData, bool * punicode, bool * pbigendian)
  150. {
  151. // Check for UNICODE source file.
  152. // ==============================
  153. BYTE * UnicodeSignature = pData;
  154. if (UnicodeSignature[0] == 0xFF && UnicodeSignature[1] == 0xFE)
  155. {
  156. *punicode = TRUE;
  157. *pbigendian = FALSE;
  158. pData+=2;
  159. }
  160. else if (UnicodeSignature[0] == 0xFE && UnicodeSignature[1] == 0xFF)
  161. {
  162. *punicode = TRUE;
  163. *pbigendian = TRUE;
  164. pData+=2;
  165. }
  166. else // ANSI/DBCS. Move back to start of file.
  167. {
  168. *punicode = false;
  169. }
  170. }
  171. #else
  172. void CheckForUnicodeEndian(FILE * fp, bool * punicode, bool * pbigendian)
  173. {
  174. // Check for UNICODE source file.
  175. // ==============================
  176. BYTE UnicodeSignature[2];
  177. if (fread(UnicodeSignature, sizeof(BYTE), 2, fp) != 2)
  178. {
  179. *punicode = false;
  180. fseek(fp, 0, SEEK_SET);
  181. return ;
  182. }
  183. if (UnicodeSignature[0] == 0xFF && UnicodeSignature[1] == 0xFE)
  184. {
  185. *punicode = TRUE;
  186. *pbigendian = FALSE;
  187. }
  188. else if (UnicodeSignature[0] == 0xFE && UnicodeSignature[1] == 0xFF)
  189. {
  190. *punicode = TRUE;
  191. *pbigendian = TRUE;
  192. }
  193. else // ANSI/DBCS. Move back to start of file.
  194. {
  195. *punicode = false;
  196. fseek(fp, 0, SEEK_SET);
  197. }
  198. }
  199. #endif
  200. //***************************************************************************
  201. //
  202. // GetNextChar
  203. //
  204. // DESCRIPTION:
  205. //
  206. // Gets the next WCHAR from the file.
  207. //
  208. //***************************************************************************
  209. #ifdef USE_MMF_APPROACH
  210. WCHAR GetNextChar(BYTE * & pData, BYTE * pEnd, bool unicode, bool bigendian)
  211. {
  212. if(unicode) // unicode file
  213. {
  214. if ( (ULONG_PTR)pData >= (ULONG_PTR)pEnd) return 0;
  215. WCHAR wc = *(WCHAR *)pData;
  216. pData+=sizeof(WCHAR);
  217. if(bigendian)
  218. {
  219. wc = ((wc & 0xff) << 8) | ((wc & 0xff00) >> 8);
  220. }
  221. return wc;
  222. }
  223. else // single character file
  224. {
  225. if ( (ULONG_PTR)pData >= (ULONG_PTR)pEnd) return 0;
  226. char temp = (char)*pData;
  227. pData++;
  228. if(temp == 0x1a) return 0; // EOF for ascii files!
  229. WCHAR wRet[2];
  230. MultiByteToWideChar(CP_ACP,0,&temp,1,wRet,2);
  231. return wRet[0];
  232. }
  233. return 0;
  234. }
  235. #else
  236. WCHAR GetNextChar(FILE * fp, bool unicode, bool bigendian)
  237. {
  238. WCHAR wRet[2];
  239. if(unicode) // unicode file
  240. {
  241. if (fread(wRet, sizeof(wchar_t), 1, fp) == 0)
  242. return 0;
  243. if(bigendian)
  244. {
  245. wRet[0] = ((wRet[0] & 0xff) << 8) | ((wRet[0] & 0xff00) >> 8);
  246. }
  247. }
  248. else // single character file
  249. {
  250. char temp;
  251. if (fread(&temp, sizeof(char), 1, fp) == 0)
  252. return 0;
  253. if(temp == 0x1a)
  254. return 0; // EOF for ascii files!
  255. StringCchPrintfW (wRet, 2, L"%C", temp);
  256. }
  257. return wRet[0];
  258. }
  259. #endif
  260. //***************************************************************************
  261. //
  262. // IsInclude
  263. //
  264. // DESCRIPTION:
  265. //
  266. // Looks at a line and determines if it is a #include line. This is
  267. // probably temporary since later we might have a preprocessor parser should
  268. // we start to add a lot of preprocessor features.
  269. //
  270. //***************************************************************************
  271. HRESULT IsInclude(WCHAR * pLine, TCHAR * cFileNameBuff, bool & bReturn)
  272. {
  273. bReturn = false;
  274. // Do a quick check to see if this could be a #include or #pragma include
  275. int iNumNonBlank = 0;
  276. WCHAR * pTemp;
  277. for(pTemp = pLine; *pTemp; pTemp++)
  278. {
  279. if(*pTemp != L' ')
  280. {
  281. iNumNonBlank++;
  282. if(iNumNonBlank == 1 && *pTemp != L'#')
  283. return false;
  284. if(iNumNonBlank == 2 && towupper(*pTemp) != L'I' &&
  285. towupper(*pTemp) != L'P')
  286. return S_OK;
  287. // we have established that the first two non blank characters are #I
  288. // or #p, therefore we continue on...
  289. if(iNumNonBlank > 1)
  290. break;
  291. }
  292. }
  293. // Create a version of the line with no blanks in front of the first quote
  294. WCHAR *wTemp = new WCHAR[wcslen(pLine) + 1];
  295. if(wTemp == NULL)
  296. return WBEM_E_OUT_OF_MEMORY;
  297. CDeleteMe<WCHAR> dm(wTemp);
  298. WCHAR *pTo;
  299. BOOL bFoundQuote = FALSE;
  300. for(pTo = wTemp, pTemp = pLine; *pTemp; pTemp++)
  301. {
  302. if(*pTemp == L'"')
  303. bFoundQuote = TRUE;
  304. if(*pTemp != L' ' || bFoundQuote)
  305. {
  306. *pTo = *pTemp;
  307. pTo++;
  308. }
  309. }
  310. *pTo = 0;
  311. // Verify that the line starts with #include(" or #pragma include
  312. WCHAR * pTest;
  313. if(wbem_wcsnicmp(wTemp, L"#pragma", 7) == 0)
  314. pTest = wTemp+7;
  315. else
  316. pTest = wTemp+1;
  317. if(wbem_wcsnicmp(pTest, L"include(\"", 9) || wcslen(pTest) < 12)
  318. return S_OK;
  319. // Count back from the end to find the previous "
  320. WCHAR *Last;
  321. for(Last = pTo-1; *Last && Last > wTemp+9 && *Last != L'"'; Last--);
  322. if(*Last != L'"')
  323. return S_OK;
  324. *Last = 0;
  325. CopyOrConvert(cFileNameBuff, pTest+9, MAX_PATH);
  326. bReturn = true;
  327. return S_OK;
  328. }
  329. #if defined(_AMD64_)
  330. //***************************************************************************
  331. //
  332. // ReadLineFast
  333. //
  334. // DESCRIPTION:
  335. //
  336. // Reads a single line from a file.
  337. //
  338. // The ReadLine() function (below) is painfully slow. For each character
  339. // in a line, the following routines are performed:
  340. //
  341. // fread()
  342. // swprintf()
  343. //
  344. // Neither of which are fast. Then, when the length of the line is
  345. // determined, each character in the line is processed *again*. The files
  346. // being processed are not small, either... greater than a megabyte is
  347. // not uncommon.
  348. //
  349. // This routine is an attempt to speed things up. Right now this is done
  350. // for AMD64 because we're running on a simulator, however someone should
  351. // consider enabling this routine for all platforms.
  352. //
  353. // RETURN:
  354. //
  355. // NULL if end of file, or error, other wise this is a pointer to a WCHAR
  356. // string which MUST BE FREED BY THE CALLER.
  357. //
  358. //***************************************************************************
  359. WCHAR * ReadLineFast(FILE * pFile, bool unicode, bool bigendian)
  360. {
  361. #define TMP_BUF_CHARS 256
  362. CHAR asciiBuffer[TMP_BUF_CHARS];
  363. WCHAR unicodeBuffer[TMP_BUF_CHARS];
  364. PWCHAR returnBuffer;
  365. int unicodeChars;
  366. int currentFilePosition;
  367. //
  368. // This routine does not handle the bigendian case.
  369. //
  370. if (bigendian != FALSE) {
  371. return NULL;
  372. }
  373. //
  374. // Remember the current file position. If an error is encountered,
  375. // the file position must be restored for the slower ReadLine()
  376. // routine.
  377. //
  378. currentFilePosition = ftell(pFile);
  379. if (unicode == FALSE) {
  380. //
  381. // Read the next line into asciiBuffer, and convert it to
  382. // unicodeBuffer. If any problems (buffer overrun, etc.) are
  383. // encountered, fail the call.
  384. //
  385. asciiBuffer[TMP_BUF_CHARS-1] = '\0';
  386. if (NULL == fgets(asciiBuffer,TMP_BUF_CHARS,pFile)) {
  387. goto exitError;
  388. }
  389. if (asciiBuffer[TMP_BUF_CHARS-1] != '\0') {
  390. goto exitError;
  391. }
  392. if (FAILED(StringCchPrintfW (unicodeBuffer, TMP_BUF_CHARS, L"%S", asciiBuffer)))
  393. goto exitError;
  394. unicodeChars = wcslen(unicodeBuffer);
  395. } else {
  396. //
  397. // Read the next line into unicodeBuffer. If any problems (buffer
  398. // overrun, etc.) are encountered, fail the call.
  399. //
  400. unicodeBuffer[TMP_BUF_CHARS-1] = L'\0';
  401. if (NULL == fgetws(unicodeBuffer,TMP_BUF_CHARS,pFile)) {
  402. goto exitError;
  403. }
  404. if (unicodeBuffer[TMP_BUF_CHARS-1] != L'\0') {
  405. goto exitError;
  406. }
  407. unicodeChars = wcslen(unicodeBuffer);
  408. }
  409. //
  410. // Allocate the buffer to return to the caller, copy the unicode
  411. // string into it, and return to the caller.
  412. //
  413. returnBuffer = new WCHAR[unicodeChars + 1];
  414. if (returnBuffer == NULL) {
  415. goto exitError;
  416. }
  417. RtlCopyMemory(returnBuffer,unicodeBuffer,unicodeChars * sizeof(WCHAR));
  418. returnBuffer[unicodeChars] = L'\0';
  419. return returnBuffer;
  420. exitError:
  421. fseek(pFile, currentFilePosition, SEEK_SET);
  422. return NULL;
  423. }
  424. #endif // _AMD64_
  425. #ifdef USE_MMF_APPROACH
  426. WCHAR * FindWCharOrEnd(WCHAR * pStart, WCHAR * pEnd,WCHAR wc)
  427. {
  428. while ((ULONG_PTR)pStart < (ULONG_PTR)pEnd)
  429. {
  430. if (wc == *pStart) break;
  431. pStart++;
  432. }
  433. return pStart;
  434. }
  435. BYTE * FindCharOrEnd(BYTE * pStart, BYTE * pEnd,BYTE c)
  436. {
  437. while ((ULONG_PTR)pStart < (ULONG_PTR)pEnd)
  438. {
  439. if (c == *pStart) break;
  440. pStart++;
  441. }
  442. return pStart;
  443. }
  444. //***************************************************************************
  445. //
  446. // ReadLine
  447. //
  448. // DESCRIPTION:
  449. //
  450. // Reads a single line from a file.
  451. //
  452. // RETURN:
  453. //
  454. // NULL if end of file, or error, other wise this is a pointer to a WCHAR
  455. // string which MUST BE FREED BY THE CALLER.
  456. //
  457. //***************************************************************************
  458. WCHAR * ReadLine(BYTE * & pData,BYTE * pEnd, bool unicode, bool bigendian)
  459. {
  460. if (unicode)
  461. {
  462. if ((ULONG_PTR)pData >= (ULONG_PTR)pEnd) return NULL;
  463. WCHAR * pFound = FindWCharOrEnd((WCHAR *)pData,(WCHAR *)pEnd,L'\n');
  464. ULONG_PTR iNumChar = (ULONG_PTR)pFound-(ULONG_PTR)pData;
  465. WCHAR * pRet = new WCHAR[2 + (iNumChar/sizeof(WCHAR))];
  466. if (NULL == pRet) return NULL;
  467. memcpy(pRet,pData,iNumChar);
  468. pRet[iNumChar/sizeof(WCHAR)] = L'\n';
  469. pRet[iNumChar/sizeof(WCHAR)+1] = 0;
  470. pData = (BYTE *)(pFound + 1);
  471. return pRet;
  472. }
  473. else
  474. {
  475. if ((ULONG_PTR)pData >= (ULONG_PTR)pEnd) return NULL;
  476. BYTE * pFound = FindCharOrEnd(pData,pEnd,'\n');
  477. ULONG_PTR iNumChar = (ULONG_PTR)pFound-(ULONG_PTR)pData;
  478. WCHAR * pRet = new WCHAR[2 + (iNumChar)];
  479. if (NULL == pRet) return NULL;
  480. MultiByteToWideChar(CP_ACP,0,(LPCSTR)pData,iNumChar,pRet,iNumChar);
  481. pRet[iNumChar] = L'\n';
  482. pRet[iNumChar + 1] = 0;
  483. pData = pFound + 1;
  484. return pRet;
  485. }
  486. }
  487. HRESULT WriteFileToTemp(const TCHAR * pFileName, FILE * pTempFile, CFlexArray & sofar, PDBG pDbg,CMofLexer* pLex)
  488. {
  489. SCODE sc = S_OK;
  490. int iSoFarPos = -1;
  491. // Make sure the file isnt on the list already. If it is, then fail since we would
  492. // be in a loop. If it isnt, add it to the list.
  493. for(int iCnt = 0; iCnt < sofar.Size(); iCnt++)
  494. {
  495. TCHAR * pTemp = (TCHAR * )sofar.GetAt(iCnt);
  496. if(lstrcmpi(pTemp, pFileName) == 0)
  497. {
  498. Trace(true, pDbg, ERROR_RECURSIVE_INCLUDE, pFileName);
  499. return WBEM_E_FAILED;
  500. }
  501. }
  502. DWORD dwLen = lstrlen(pFileName) + 1;
  503. TCHAR * pNew = new TCHAR[dwLen];
  504. if(pNew)
  505. {
  506. StringCchCopyW(pNew, dwLen, pFileName);
  507. sofar.Add((void *)pNew);
  508. iSoFarPos = sofar.Size()-1;
  509. }
  510. else
  511. return WBEM_E_OUT_OF_MEMORY;
  512. // Write the file and line number out
  513. WriteLineAndFilePragma(pTempFile, pFileName, 1);
  514. HANDLE hSrcFile = CreateFile(pFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
  515. if (INVALID_HANDLE_VALUE == hSrcFile) return HR_LASTERR;
  516. OnDelete<HANDLE,BOOL(*)(HANDLE),CloseHandle> cmSrc(hSrcFile);
  517. DWORD dwSize = GetFileSize(hSrcFile,NULL);
  518. HANDLE hFileMapSrc = CreateFileMapping(hSrcFile,
  519. NULL,
  520. PAGE_READONLY,
  521. 0,0, // the entire file
  522. NULL);
  523. if (NULL == hFileMapSrc) return HR_LASTERR;
  524. OnDelete<HANDLE,BOOL(*)(HANDLE),CloseHandle> cmMapSrc(hFileMapSrc);
  525. VOID * pData = MapViewOfFile(hFileMapSrc,FILE_MAP_READ,0,0,0);
  526. if (NULL == pData) return HR_LASTERR;
  527. OnDelete<PVOID,BOOL(*)(LPCVOID),UnmapViewOfFile> UnMap(pData);
  528. // Make sure the file isnt binary
  529. if(IsBinaryFile((BYTE *)pData,dwSize))
  530. {
  531. Trace(true, pDbg, ERROR_INCLUDING_ABSENT, pFileName);
  532. return WBEM_E_FAILED;
  533. }
  534. // Determine if the file is unicode and bigendian
  535. BYTE * pMovedData = (BYTE *)pData;
  536. BYTE * pEnd = pMovedData + dwSize;
  537. bool unicode, bigendian;
  538. CheckForUnicodeEndian(pMovedData, &unicode, &bigendian);
  539. // Go through each line of the file, if it is another include, then recursively call this guy.
  540. WCHAR * pLine = NULL;
  541. for(int iLine = 1; pLine = ReadLine(pMovedData,pEnd, unicode, bigendian);)
  542. {
  543. CDeleteMe<WCHAR> dm(pLine);
  544. TCHAR cFileName[MAX_PATH+1];
  545. bool bInclude;
  546. HRESULT hr = IsInclude(pLine, cFileName, bInclude);
  547. if(FAILED(hr))
  548. return hr;
  549. if(bInclude)
  550. {
  551. TCHAR szExpandedFilename[MAX_PATH+1];
  552. DWORD nRes = ExpandEnvironmentStrings(cFileName,
  553. szExpandedFilename,
  554. FILENAME_MAX);
  555. if (nRes == 0)
  556. {
  557. //That failed!
  558. StringCchCopyW(szExpandedFilename, MAX_PATH+1, cFileName);
  559. }
  560. if (_waccess(szExpandedFilename,0))
  561. {
  562. // Included file not found, look in same directory as parent MOF file
  563. TCHAR cSrcPath[_MAX_PATH+1] = L"";
  564. TCHAR cSrcDrive[_MAX_DRIVE] = L"";
  565. TCHAR cSrcDir[_MAX_DIR] = L"";
  566. // Get drive and directory information of parent MOF file
  567. if (_wfullpath( cSrcPath, pFileName, _MAX_PATH ) != NULL)
  568. {
  569. _wsplitpath(cSrcPath, cSrcDrive, cSrcDir, NULL, NULL);
  570. }
  571. // Copy original included MOF file information to cSrcPath
  572. StringCchCopyW(cSrcPath, _MAX_PATH+1, szExpandedFilename);
  573. // Build up new full path of included MOF using the
  574. // path of the parent MOF.
  575. // Note: Intentionally did not use _makepath here.
  576. StringCchCopyW(szExpandedFilename, MAX_PATH+1, L""); // flush string
  577. StringCchCatW(szExpandedFilename, MAX_PATH+1, cSrcDrive); // add drive info
  578. StringCchCatW(szExpandedFilename, MAX_PATH+1, cSrcDir); // add directory info
  579. StringCchCatW(szExpandedFilename, MAX_PATH+1, cSrcPath); // add original specified path and filename
  580. }
  581. if (_waccess(szExpandedFilename,0))
  582. {
  583. // still dont have the file. Must be invalid include. Set the name back and report the error
  584. DWORD nRes = ExpandEnvironmentStrings(cFileName,
  585. szExpandedFilename,
  586. FILENAME_MAX);
  587. if (nRes == 0)
  588. {
  589. //That failed!
  590. StringCchCopyW(szExpandedFilename, MAX_PATH+1, cFileName);
  591. }
  592. Trace(true, pDbg, ERROR_INCLUDING_ABSENT, szExpandedFilename);
  593. pLex->SetError(CMofLexer::invalid_include_file);
  594. return WBEM_E_FAILED;
  595. }
  596. sc = WriteFileToTemp(szExpandedFilename, pTempFile, sofar, pDbg, pLex);
  597. WriteLineAndFilePragma(pTempFile, pFileName, 1);
  598. if(sc != S_OK)
  599. break;
  600. }
  601. else
  602. {
  603. iLine++;
  604. WriteLine(pTempFile, pLine);
  605. }
  606. }
  607. // remove the entry so that the file can be included more than once at the same level
  608. if(iSoFarPos != -1)
  609. {
  610. TCHAR * pTemp = (TCHAR * )sofar.GetAt(iSoFarPos);
  611. if(pTemp)
  612. {
  613. delete pTemp;
  614. sofar.RemoveAt(iSoFarPos);
  615. }
  616. }
  617. return sc;
  618. }
  619. #else
  620. //***************************************************************************
  621. //
  622. // ReadLine
  623. //
  624. // DESCRIPTION:
  625. //
  626. // Reads a single line from a file.
  627. //
  628. // RETURN:
  629. //
  630. // NULL if end of file, or error, other wise this is a pointer to a WCHAR
  631. // string which MUST BE FREED BY THE CALLER.
  632. //
  633. //***************************************************************************
  634. WCHAR * ReadLine(FILE * pFile, bool unicode, bool bigendian)
  635. {
  636. WCHAR * pRet;
  637. #if defined(_AMD64_)
  638. pRet = ReadLineFast(pFile,unicode,bigendian);
  639. if (pRet != NULL) {
  640. return pRet;
  641. }
  642. #endif
  643. // Get the current position
  644. int iCurrPos = ftell(pFile);
  645. // count the number of characters in the line
  646. WCHAR wCurr;
  647. int iNumChar = 0;
  648. for(iNumChar = 0; wCurr = GetNextChar(pFile, unicode, bigendian); iNumChar++)
  649. if(wCurr == L'\n')
  650. break;
  651. if(iNumChar == 0 && wCurr == 0)
  652. return NULL;
  653. iNumChar+= 2;
  654. // move the file pointer back
  655. if( fseek(pFile, iCurrPos, SEEK_SET) ) return NULL;
  656. // allocate the buffer
  657. pRet = new WCHAR[iNumChar+1];
  658. if(pRet == NULL)
  659. return NULL;
  660. // move the characters into the buffer
  661. WCHAR * pNext = pRet;
  662. for(iNumChar = 0; wCurr = GetNextChar(pFile, unicode, bigendian); pNext++)
  663. {
  664. *pNext = wCurr;
  665. if(wCurr == L'\n')
  666. {
  667. pNext++;
  668. break;
  669. }
  670. }
  671. *pNext = 0;
  672. return pRet;
  673. }
  674. //***************************************************************************
  675. //
  676. // WriteFileToTemp
  677. //
  678. // DESCRIPTION:
  679. //
  680. // Writes the contests of a file to the temporay file. The temporary file
  681. // will always be little endian unicode. This will be called recursively
  682. // should an include be encountered.
  683. //
  684. //***************************************************************************
  685. HRESULT WriteFileToTemp(const TCHAR * pFileName, FILE * pTempFile, CFlexArray & sofar, PDBG pDbg,CMofLexer* pLex)
  686. {
  687. SCODE sc = S_OK;
  688. int iSoFarPos = -1;
  689. // Make sure the file isnt on the list already. If it is, then fail since we would
  690. // be in a loop. If it isnt, add it to the list.
  691. for(int iCnt = 0; iCnt < sofar.Size(); iCnt++)
  692. {
  693. TCHAR * pTemp = (TCHAR * )sofar.GetAt(iCnt);
  694. if(lstrcmpi(pTemp, pFileName) == 0)
  695. {
  696. Trace(true, pDbg, ERROR_RECURSIVE_INCLUDE, pFileName);
  697. return WBEM_E_FAILED;
  698. }
  699. }
  700. DWORD dwLen = lstrlen(pFileName) + 1;
  701. TCHAR * pNew = new TCHAR[dwLen];
  702. if(pNew)
  703. {
  704. StringCchCopyW(pNew, dwLen, pFileName);
  705. sofar.Add((void *)pNew);
  706. iSoFarPos = sofar.Size()-1;
  707. }
  708. else
  709. return WBEM_E_OUT_OF_MEMORY;
  710. // Write the file and line number out
  711. WriteLineAndFilePragma(pTempFile, pFileName, 1);
  712. // Open the file
  713. FILE *fp;
  714. #ifdef UNICODE
  715. fp = _wfopen(pFileName, L"rb");
  716. #else
  717. fp = fopen(pFileName, "rb");
  718. #endif
  719. if(fp == NULL)
  720. {
  721. Trace(true, pDbg, ERROR_INCLUDING_ABSENT, pFileName);
  722. pLex->SetError(CMofLexer::invalid_include_file);
  723. return WBEM_E_FAILED;
  724. }
  725. CfcloseMe cm(fp);
  726. // Make sure the file isnt binary
  727. if(IsBinaryFile(fp))
  728. {
  729. Trace(true, pDbg, ERROR_INCLUDING_ABSENT, pFileName);
  730. return WBEM_E_FAILED;
  731. }
  732. // Determine if the file is unicode and bigendian
  733. bool unicode, bigendian;
  734. CheckForUnicodeEndian(fp, &unicode, &bigendian);
  735. // Go through each line of the file, if it is another include, then recursively call this guy.
  736. WCHAR * pLine = NULL;
  737. for(int iLine = 1; pLine = ReadLine(fp, unicode, bigendian);)
  738. {
  739. CDeleteMe<WCHAR> dm(pLine);
  740. TCHAR cFileName[MAX_PATH+1];
  741. bool bInclude;
  742. HRESULT hr = IsInclude(pLine, cFileName, bInclude);
  743. if(FAILED(hr))
  744. return hr;
  745. if(bInclude)
  746. {
  747. TCHAR szExpandedFilename[MAX_PATH+1];
  748. DWORD nRes = ExpandEnvironmentStrings(cFileName,
  749. szExpandedFilename,
  750. FILENAME_MAX);
  751. if (nRes == 0)
  752. {
  753. //That failed!
  754. StringCchCopyW(szExpandedFilename, MAX_PATH+1, cFileName);
  755. }
  756. if (_waccess(szExpandedFilename,0))
  757. {
  758. // Included file not found, look in same directory as parent MOF file
  759. TCHAR cSrcPath[_MAX_PATH+1] = L"";
  760. TCHAR cSrcDrive[_MAX_DRIVE] = L"";
  761. TCHAR cSrcDir[_MAX_DIR] = L"";
  762. // Get drive and directory information of parent MOF file
  763. if (_wfullpath( cSrcPath, pFileName, _MAX_PATH ) != NULL)
  764. {
  765. _wsplitpath(cSrcPath, cSrcDrive, cSrcDir, NULL, NULL);
  766. }
  767. // Copy original included MOF file information to cSrcPath
  768. StringCchCopyW(cSrcPath, _MAX_PATH+1, szExpandedFilename);
  769. // Build up new full path of included MOF using the
  770. // path of the parent MOF.
  771. // Note: Intentionally did not use _makepath here.
  772. StringCchCopyW(szExpandedFilename, MAX_PATH+1, L""); // flush string
  773. StringCchCatW(szExpandedFilename, MAX_PATH+1, cSrcDrive); // add drive info
  774. StringCchCatW(szExpandedFilename, MAX_PATH+1, cSrcDir); // add directory info
  775. StringCchCatW(szExpandedFilename, MAX_PATH+1, cSrcPath); // add original specified path and filename
  776. }
  777. if (_waccess(szExpandedFilename,0))
  778. {
  779. // still dont have the file. Must be invalid include. Set the name back and report the error
  780. DWORD nRes = ExpandEnvironmentStrings(cFileName,
  781. szExpandedFilename,
  782. FILENAME_MAX);
  783. if (nRes == 0)
  784. {
  785. //That failed!
  786. StringCchCopyW(szExpandedFilename, MAX_PATH+1, cFileName);
  787. }
  788. Trace(true, pDbg, ERROR_INCLUDING_ABSENT, szExpandedFilename);
  789. pLex->SetError(CMofLexer::invalid_include_file);
  790. return WBEM_E_FAILED;
  791. }
  792. sc = WriteFileToTemp(szExpandedFilename, pTempFile, sofar, pDbg, pLex);
  793. WriteLineAndFilePragma(pTempFile, pFileName, 1);
  794. if(sc != S_OK)
  795. break;
  796. }
  797. else
  798. {
  799. iLine++;
  800. WriteLine(pTempFile, pLine);
  801. }
  802. }
  803. // remove the entry so that the file can be included more than once at the same level
  804. if(iSoFarPos != -1)
  805. {
  806. TCHAR * pTemp = (TCHAR * )sofar.GetAt(iSoFarPos);
  807. if(pTemp)
  808. {
  809. delete pTemp;
  810. sofar.RemoveAt(iSoFarPos);
  811. }
  812. }
  813. return sc;
  814. }
  815. #endif