Source code of Windows XP (NT5)
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.

1218 lines
36 KiB

  1. #include <windows.h>
  2. #include <iostream.h>
  3. #include <iomanip.h>
  4. #include <assert.h>
  5. #include <stdio.h>
  6. #include "array.hxx"
  7. #include "types.h"
  8. #include "icomp.hxx"
  9. #include "CoComp.hxx"
  10. #include "errors.hxx"
  11. //
  12. // PROTOTYPES
  13. //
  14. void WriteLine(HANDLE file, char* pBuff, int nLen);
  15. unsigned long FindEndOfLine(char* pBuff );
  16. BLOCK_TYPE GetBlockType(char* pchData, char* pchTerm );
  17. bool GetBlock(HANDLE file, INDEX* pIdx, char** ppTarget = NULL, unsigned long* pulBlockBase=NULL );
  18. void DisplayError(UINT uError, UINT uLineNum, ostream& out = cerr);
  19. extern void TokenizeAttributes( char* pBuf, unsigned long nCnt, CAutoArray<ATTRINFO>* pList );
  20. extern long CompareAttributeBlock( char * pRefBuf, CAutoArray<ATTRINFO>* pRefList, char * pCurBuf,
  21. CAutoArray<ATTRINFO>* pCurList);
  22. //
  23. // GLOBALS
  24. //
  25. bool fgCoClass;
  26. bool fgInterface;
  27. bool fgDispInterface;
  28. bool fgMethodAttribute;
  29. bool fgMethodParameter;
  30. bool fgInterfaceAttr;
  31. bool fgFlush;
  32. bool fgParamNames;
  33. bool fgParamTypes;
  34. bool fgParamNameCase;
  35. bool fgParamTypeCase;
  36. unsigned long g_ulAppRetVal;
  37. bool g_fWriteToStdOut = false;
  38. char g_szDiffFileName[14] = {0}; // Will contain differences
  39. char g_szNewFileName[14] = {0}; // Will contain added interfaces, etc.
  40. char g_szCurFileName[256] = {0}; // Contains tlviewer output for current tlb
  41. char g_szRefFileName[256] = {0}; // Contains tlviewer output for new tlb
  42. char* g_pszMethodAttr = NULL;
  43. #define BUFFER_SIZE(buf) (sizeof(buf)/sizeof(buf[0]))
  44. //
  45. // Test function to test the index structure on the original MSHTML.OUT
  46. // without debugging the system. The mirror file and the original fileCur
  47. // should only be different with their blanks.
  48. //
  49. void CreateTestMirror(HANDLE fileCur, CAutoArray<INDEX>* rgFileIdx)
  50. {
  51. INDEX idxTmp;
  52. char* pTmp;
  53. DWORD dwRead;
  54. HANDLE fileData = CreateFile("mirror", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
  55. FILE_ATTRIBUTE_NORMAL, NULL);
  56. if (INVALID_HANDLE_VALUE == fileData)
  57. {
  58. DisplayError(ERR_OPENINGMIRROR, __LINE__);
  59. return;
  60. }
  61. // Write this stuff to a file.
  62. for (int i = 0; i < rgFileIdx->Size(); i++)
  63. {
  64. long nLen;
  65. //get records
  66. rgFileIdx->GetAt(i, &idxTmp);
  67. nLen = idxTmp.ulEndPos - idxTmp.ulAttrStartPos;
  68. //allocate memory to read
  69. pTmp = new char[nLen+1];
  70. if (!pTmp) // Hopefully will never happen but just in case.
  71. {
  72. DisplayError(ERR_OUTOFMEMORY, __LINE__);
  73. return;
  74. }
  75. // Read data
  76. SetFilePointer( (HANDLE)fileCur, idxTmp.ulAttrStartPos, NULL, FILE_BEGIN);
  77. ReadFile( (HANDLE)fileCur, pTmp, nLen, &dwRead, NULL);
  78. // Terminate string
  79. pTmp[ nLen ]=0;
  80. // Write to file
  81. WriteLine(fileData, pTmp, nLen);
  82. // Release mem.
  83. delete [] pTmp;
  84. }
  85. CloseHandle(fileData);
  86. }
  87. //
  88. //
  89. //
  90. void MarkAttrChanges(HANDLE fileCur, CAutoArray<INDEX>* rgFileIdx, char* pszDiffFileName)
  91. {
  92. INDEX idxTmp1, idxTmp2;
  93. DWORD dwRead;
  94. HANDLE fileLocal = INVALID_HANDLE_VALUE;
  95. char szEntry[160];
  96. char szTmp[80];
  97. // First, add the modified ATTR tags to the difference file.
  98. if (g_fWriteToStdOut)
  99. {
  100. fileLocal = GetStdHandle(STD_OUTPUT_HANDLE);
  101. }
  102. else
  103. {
  104. fileLocal = CreateFile(pszDiffFileName, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
  105. FILE_ATTRIBUTE_NORMAL, NULL);
  106. }
  107. if (INVALID_HANDLE_VALUE == fileLocal)
  108. {
  109. DisplayError(ERR_OPENINGDIFF, __LINE__);
  110. return;
  111. }
  112. SetFilePointer(fileLocal, 0, NULL, FILE_END);
  113. // An attribute cannot be the last block in a file, so we
  114. // can go until size - 1
  115. for ( int i = 0; i < rgFileIdx->Size() - 1; i++)
  116. {
  117. // Get record
  118. rgFileIdx->GetAt(i, &idxTmp1);
  119. // If it is an unmatched attribute, analyze
  120. if ((!idxTmp1.fCopied) && (idxTmp1.blockType == BLK_ATTR))
  121. {
  122. // Get the next block
  123. rgFileIdx->GetAt(i + 1, &idxTmp2);
  124. // If the next block is valid and it is matched, then the attributes
  125. // for it must have changed.
  126. //
  127. if ((idxTmp2.blockType != BLK_NONE) &&
  128. (idxTmp2.fCopied))
  129. {
  130. // Take a note of this in the differences file
  131. lstrcpy(szEntry, "Attributes for ");
  132. // Read the data
  133. SetFilePointer((HANDLE)fileCur, idxTmp2.ulStartPos, NULL, FILE_BEGIN);
  134. ReadFile((HANDLE)fileCur, szTmp, 79, &dwRead, NULL);
  135. // Add the type and the name of the block here.
  136. unsigned int j = 0;
  137. int nSpaceCnt = 0;
  138. while (j < min(79, dwRead))
  139. {
  140. if (szTmp[j] == ' ')
  141. nSpaceCnt++;
  142. if (nSpaceCnt == 2)
  143. break;
  144. j++;
  145. }
  146. if (nSpaceCnt!=2)
  147. break;
  148. szTmp[j] = 0;
  149. lstrcat(szEntry, szTmp);
  150. lstrcat(szEntry, " changed ");
  151. WriteLine(fileLocal, szEntry, -1);
  152. idxTmp1.fCopied = true;
  153. rgFileIdx->Set(i, idxTmp1);
  154. }
  155. }
  156. }
  157. // Don't want to close the stdout. Otherwise, write
  158. // operations go nowhere. We will close stdout
  159. // at the end of this program.
  160. //
  161. if (!g_fWriteToStdOut)
  162. CloseHandle(fileLocal);
  163. }
  164. //
  165. //
  166. //
  167. void FlushDifferences(HANDLE fileCur, CAutoArray<INDEX>* rgFileIdx)
  168. {
  169. INDEX idxTmp;
  170. DWORD dwRead;
  171. char* pTmp;
  172. bool fCheck;
  173. HANDLE fileDiff = INVALID_HANDLE_VALUE;
  174. if (g_fWriteToStdOut)
  175. {
  176. fileDiff = GetStdHandle(STD_OUTPUT_HANDLE);
  177. }
  178. else
  179. {
  180. fileDiff = CreateFile(g_szNewFileName, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
  181. FILE_ATTRIBUTE_NORMAL, NULL);
  182. }
  183. if (INVALID_HANDLE_VALUE == fileDiff)
  184. {
  185. DisplayError(ERR_OPENINGNEW, __LINE__);
  186. return;
  187. }
  188. // Write this stuff to a file.
  189. bool fFirst = true;
  190. for (int i = 0; i < rgFileIdx->Size(); i++)
  191. {
  192. // Get records
  193. rgFileIdx->GetAt(i, &idxTmp);
  194. switch ( idxTmp.blockType )
  195. {
  196. case BLK_INTERFACE:
  197. if (!fgInterface)
  198. fCheck = false;
  199. break;
  200. case BLK_DISPINT:
  201. if (!fgDispInterface)
  202. fCheck = false;
  203. break;
  204. case BLK_COCLASS:
  205. if (!fgCoClass)
  206. fCheck = false;
  207. default:
  208. fCheck = true;
  209. }
  210. if ((!idxTmp.fCopied) && (fCheck))
  211. {
  212. // Allocate memory to read
  213. pTmp = new char[idxTmp.ulEndPos - idxTmp.ulStartPos+1];
  214. // Read data
  215. SetFilePointer((HANDLE)fileCur, idxTmp.ulStartPos, NULL, FILE_BEGIN);
  216. ReadFile((HANDLE)fileCur, pTmp, idxTmp.ulEndPos - idxTmp.ulStartPos, &dwRead, NULL);
  217. // Terminate string
  218. pTmp[idxTmp.ulEndPos - idxTmp.ulStartPos ]=0;
  219. if (fFirst)
  220. {
  221. fFirst = false;
  222. // Write out a blank line if writing to stdout
  223. //
  224. if (g_fWriteToStdOut)
  225. WriteLine(fileDiff, "", -1);
  226. WriteLine(fileDiff, "------------------------------------------", -1);
  227. WriteLine(fileDiff, "NEW BLOCKS", -1);
  228. WriteLine(fileDiff, "------------------------------------------", -1);
  229. WriteLine(fileDiff, "", -1);
  230. }
  231. // Write the block
  232. WriteLine(fileDiff, pTmp, idxTmp.ulEndPos - idxTmp.ulStartPos);
  233. // Put some empty lines after the block to make it easier to read
  234. WriteLine(fileDiff, "", -1);
  235. // ScotRobe: only want to set g_ulAppRetVal to an error
  236. // code if something was changed. We don't want to stop the
  237. // build process if something was added. Adding is okay,
  238. // change is bad.
  239. //
  240. /* switch (idxTmp.blockType)
  241. {
  242. case BLK_INTERFACE:
  243. ulTmp |= CHANGE_ADDINTERFACE;
  244. break;
  245. case BLK_DISPINT:
  246. ulTmp |= CHANGE_ADDDISPINT;
  247. break;
  248. case BLK_COCLASS:
  249. ulTmp |= CHANGE_ADDCOCLASS;
  250. break;
  251. case BLK_ATTR:
  252. ulTmp |= CHANGE_ADDATTRIBUTE;
  253. break;
  254. default:
  255. break;
  256. }
  257. */
  258. // Release memory.
  259. delete [] pTmp;
  260. }
  261. }
  262. // Don't want to close the stdout if we are writing to it.
  263. // Otherwise, write operations go nowhere. We will close
  264. // stdout at the end of main.
  265. //
  266. if (!g_fWriteToStdOut)
  267. CloseHandle(fileDiff);
  268. // Uncomment this line if you uncomment the above switch statement.
  269. //
  270. //g_ulAppRetVal |= ulTmp;
  271. }
  272. //----------------------------------------------------------------------------
  273. // Function : PrepareIndex
  274. // Description : Prepare the index for a given file by creating an array of
  275. // INDEX structures.
  276. // Parameters :
  277. // fileCur : handle of current file
  278. // CAutoArray<INDEX>* : pointer to the index array
  279. //
  280. // Returns : void
  281. //----------------------------------------------------------------------------
  282. void PrepareIndex (HANDLE fileCur, CAutoArray<INDEX>* rgFileIdx)
  283. {
  284. INDEX idxCurr = {BLK_NONE, 0};
  285. INDEX idxAttr;
  286. bool fContinue = true;
  287. // Create an index for the file that is to be analyzed.
  288. while (fContinue)
  289. {
  290. fContinue = GetBlock(fileCur, &idxCurr);
  291. if (fContinue)
  292. {
  293. switch (idxCurr.blockType)
  294. {
  295. case BLK_ATTR:
  296. idxAttr = idxCurr;
  297. break;
  298. case BLK_DISPINT:
  299. case BLK_INTERFACE:
  300. case BLK_COCLASS:
  301. assert(idxAttr.blockType == BLK_ATTR);
  302. // copy the attribute start and end positions to the current block's
  303. // index structure.
  304. idxCurr.ulAttrStartPos = idxAttr.ulStartPos;
  305. idxCurr.ulAttrEndPos = idxAttr.ulEndPos;
  306. //add the data to the index
  307. rgFileIdx->Append(idxCurr);
  308. // reset
  309. idxAttr.blockType = BLK_NONE;
  310. idxAttr.ulStartPos = idxAttr.ulEndPos = 0;
  311. break;
  312. /* LEAVE TYPEDEFs out of this for now, since there are problems with them.
  313. The end of the typedef block is coded as it should be a semicolon. However, the semicolon could be
  314. used for anything inside the typedef when the typedef is a structure. This causes a false termination
  315. of the typedef.
  316. Solution:
  317. Find the '}', however, end the block at the end of the line that contains the '}'
  318. case BLK_TYPEDEF:
  319. // copy the block as it is. However, for the mirror file use, make sure the
  320. // attribute information starts and ends with the actual buffer.
  321. idxCurr.ulAttrStartPos = idxCurr.ulStartPos;
  322. //add the data to the index
  323. rgFileIdx->Append(idxCurr);
  324. // reset
  325. idxAttr.blockType = BLK_NONE;
  326. idxAttr.ulStartPos = idxAttr.ulEndPos = 0;
  327. break;
  328. */
  329. }
  330. }
  331. }
  332. }
  333. //
  334. //
  335. //
  336. bool
  337. CompareCoClass( char* pCurBuf, char* pRefBuf,
  338. char * pAttrCur, char * pAttrRef, HANDLE fileDiff)
  339. {
  340. bool bRes = true;
  341. char szClassName[64] = {0};
  342. CCompareCoClass * pCompareCoClass = NULL;
  343. CAutoArray<ATTRINFO>* pCurList = new CAutoArray<ATTRINFO>;
  344. CAutoArray<ATTRINFO>* pRefList = new CAutoArray<ATTRINFO>;
  345. long lRes;
  346. // compare the names of the coclasses. The comparison is done until we reach the
  347. // end of the longer name
  348. for ( unsigned long ulIdx = LEN_COCLASS+1;
  349. (pCurBuf[ulIdx] != 0x20) || (pRefBuf[ulIdx] != 0x20);
  350. ulIdx++ )
  351. {
  352. if ( pCurBuf[ulIdx] != pRefBuf[ulIdx] )
  353. goto Fail; //if the names don't match, these are not the coclasses that we
  354. //want to compare.
  355. szClassName[ulIdx-LEN_COCLASS-1] = pCurBuf[ulIdx]; //get the coclass name
  356. //OVERFLOW check
  357. assert( ulIdx<64 ); //sanity check to stop a corrupt file from killing us.
  358. if ( ulIdx==64 )
  359. goto Fail;
  360. }
  361. TokenizeAttributes( pAttrRef+1, lstrlen(pAttrRef) - 2, pRefList );
  362. TokenizeAttributes( pAttrCur+1, lstrlen(pAttrCur) - 2, pCurList );
  363. lRes = CompareAttributeBlock( pAttrRef+1, pRefList, pAttrCur+1, pCurList);
  364. if (lRes != 0)
  365. {
  366. char szBuf[MAX_PATH];
  367. if (lRes == CHANGE_UUIDHASCHANGED)
  368. {
  369. sprintf(szBuf, "\nGUID was modified for the coclass %s", szClassName);
  370. }
  371. else
  372. {
  373. sprintf(szBuf, "\nUnexpected error when comparing attributes for coclass %s", szClassName);
  374. }
  375. WriteLine(fileDiff, szBuf, -1);
  376. g_ulAppRetVal |= CHANGE_BLOCKREMOVED;
  377. goto Fail;
  378. }
  379. pCompareCoClass = new CCompareCoClass( pCurBuf, pRefBuf, fileDiff, szClassName );
  380. pCompareCoClass->FindAdditionsAndChanges();
  381. pCompareCoClass->FindRemovals();
  382. Cleanup:
  383. if (pCompareCoClass)
  384. delete pCompareCoClass;
  385. return bRes;
  386. Fail:
  387. bRes= false;
  388. goto Cleanup;
  389. }
  390. //
  391. //
  392. //
  393. bool
  394. CompareInterface( BLOCK_TYPE blockType, char* pCurBuf, char* pRefBuf,
  395. char * pAttrCur, char * pAttrRef, HANDLE fileDiff)
  396. {
  397. bool bRes = true;
  398. unsigned long ulNameOffset=0; //offset to start reading for the name of the interface on both blocks.
  399. char szIntName[64] = {0}; //initialize to zero so we don't deal with termination later.
  400. CCompareInterface * pCompareInterface = NULL;
  401. CAutoArray<ATTRINFO>* pCurList = new CAutoArray<ATTRINFO>;
  402. CAutoArray<ATTRINFO>* pRefList = new CAutoArray<ATTRINFO>;
  403. long lRes;
  404. //assign the offset for the first space
  405. ulNameOffset = ( blockType==BLK_DISPINT ) ? LEN_DISPINT+1 : LEN_INTERFACE+1;
  406. // The format of the name is: interface/dispinterface_name_{
  407. // Compare until the space character is reached for either of the names.
  408. for (unsigned long ulIdx = ulNameOffset;
  409. (pCurBuf[ulIdx] != 0x20) || (pRefBuf[ulIdx] != 0x20);
  410. ulIdx++ )
  411. {
  412. if ( pCurBuf[ulIdx] != pRefBuf[ulIdx] )
  413. goto Fail; //if the name does not match, this is not
  414. //the interface we are looking to compare with
  415. szIntName[ulIdx-ulNameOffset] = pCurBuf[ulIdx]; //get the interface name simultaneously
  416. //OVERFLOW CHECK
  417. assert( ulIdx<64 ); //sanity check to stop a corrupt file from killing us.
  418. if ( ulIdx==64 )
  419. goto Fail;
  420. }
  421. TokenizeAttributes( pAttrRef+1, lstrlen(pAttrRef) - 2, pRefList );
  422. TokenizeAttributes( pAttrCur+1, lstrlen(pAttrCur) - 2, pCurList );
  423. lRes = CompareAttributeBlock( pAttrRef+1, pRefList, pAttrCur+1, pCurList);
  424. if (lRes != 0)
  425. {
  426. char szBuf[MAX_PATH];
  427. switch(lRes)
  428. {
  429. case CHANGE_DUALATTRADDED:
  430. sprintf(szBuf, "\nDual attribute was added to the interface %s", szIntName);
  431. break;
  432. case CHANGE_DUALATTRREMOVED:
  433. sprintf(szBuf, "\nDual attribute was removed from the interface %s", szIntName);
  434. break;
  435. case CHANGE_UUIDHASCHANGED:
  436. sprintf(szBuf, "\nIID was changed for the interface %s", szIntName);
  437. break;
  438. default:
  439. break;
  440. }
  441. WriteLine(fileDiff, szBuf, -1);
  442. g_ulAppRetVal |= CHANGE_BLOCKREMOVED;
  443. goto Fail;
  444. }
  445. pCompareInterface = new CCompareInterface(pCurBuf, pRefBuf, fileDiff, szIntName, blockType, g_pszMethodAttr);
  446. pCompareInterface->FindAdditionsAndChanges();
  447. pCompareInterface->FindRemovals();
  448. Cleanup:
  449. if ( pCompareInterface )
  450. delete pCompareInterface;
  451. return bRes;
  452. Fail:
  453. bRes= false;
  454. goto Cleanup;
  455. }
  456. //
  457. //
  458. //
  459. bool CompareBlocks(HANDLE fileCur, CAutoArray<INDEX>* rgFileIdx, INDEX* pIdxRef,
  460. char* pRefBuf, char * pAttrRef, HANDLE fileDiff)
  461. {
  462. INDEX idxCur = {BLK_NONE, 0}; // Index record for the current file's block
  463. char * pCurBuf = NULL;
  464. char * pAttrCur = NULL;
  465. DWORD dwRead;
  466. BOOL bRes = FALSE;
  467. int nRes = 1;
  468. //we have index information about the reference file block
  469. //use it to narrow down the possibilities
  470. //
  471. //walk through the index and find the matching block types
  472. //with matching lengths.
  473. for (int i = 0; i < rgFileIdx->Size(); i++)
  474. {
  475. rgFileIdx->GetAt(i, &idxCur);
  476. //if the block we read from the reference file matches this
  477. //block's type
  478. if ((idxCur.blockType == pIdxRef->blockType) &&
  479. (!idxCur.fCopied))
  480. {
  481. //read the block from the current file, using the
  482. //index record
  483. int nLen = idxCur.ulEndPos - idxCur.ulStartPos;
  484. pCurBuf = new char[nLen+1];
  485. int nAttrLen = idxCur.ulAttrEndPos - idxCur.ulAttrStartPos;
  486. pAttrCur = new char[nAttrLen+1];
  487. SetFilePointer((HANDLE)fileCur, idxCur.ulStartPos, NULL, FILE_BEGIN);
  488. bRes = ReadFile((HANDLE)fileCur, pCurBuf, nLen, &dwRead, NULL);
  489. SetFilePointer((HANDLE)fileCur, idxCur.ulAttrStartPos, NULL, FILE_BEGIN);
  490. bRes = ReadFile((HANDLE)fileCur, pAttrCur, nAttrLen, &dwRead, NULL);
  491. // Terminate the string that was just read from the current file.
  492. pCurBuf[nLen] = 0;
  493. pAttrCur[nAttrLen] = 0;
  494. //comparison behavior may change by the type of the block to be
  495. //compared
  496. switch ( pIdxRef->blockType )
  497. {
  498. case BLK_COCLASS:
  499. if (fgCoClass)
  500. nRes = !CompareCoClass(pCurBuf, pRefBuf, pAttrCur, pAttrRef, fileDiff);
  501. else
  502. nRes = 0;
  503. break;
  504. case BLK_DISPINT:
  505. if (fgDispInterface)
  506. {
  507. //if the length of two blocks is the same, there is a chance that
  508. //they are the same block. So, compare the memory before going into
  509. //a long and detailed analysis
  510. nRes = 1;
  511. if (( pIdxRef->ulEndPos - pIdxRef->ulStartPos) == (unsigned long)nLen )
  512. {
  513. nRes = memcmp(pCurBuf, pRefBuf, nLen);
  514. }
  515. if (!nRes)
  516. nRes = memcmp( pAttrCur, pAttrRef, max(lstrlen(pAttrCur), lstrlen(pAttrRef)));
  517. // The memory comparison failed. Go into details.
  518. if ( nRes )
  519. nRes = !CompareInterface(pIdxRef->blockType, pCurBuf, pRefBuf, pAttrCur, pAttrRef, fileDiff);
  520. }
  521. else
  522. {
  523. // although we did not compare, set the flag so that
  524. // we mark the index as if we did compare to avoid false errors.
  525. nRes = 0;
  526. }
  527. break;
  528. case BLK_INTERFACE:
  529. if (fgInterface)
  530. {
  531. //if the length of two blocks is the same, there is a chance that
  532. //they are the same block. So, compare the memory before going into
  533. //a long and detailed analysis
  534. nRes = 1;
  535. if ((pIdxRef->ulEndPos - pIdxRef->ulStartPos) == (unsigned long)nLen)
  536. {
  537. nRes = memcmp(pCurBuf, pRefBuf, nLen);
  538. }
  539. if (!nRes)
  540. nRes = memcmp( pAttrCur, pAttrRef, max(lstrlen(pAttrCur), lstrlen(pAttrRef)));
  541. //the memory comparison failed. Go into details.
  542. if ( nRes )
  543. nRes = !CompareInterface(pIdxRef->blockType, pCurBuf, pRefBuf, pAttrCur, pAttrRef, fileDiff);
  544. }
  545. else
  546. {
  547. // although we did not compare, set the flag so that
  548. // we mark the index as if we did compare to avoid false errors.
  549. nRes = 0;
  550. }
  551. break;
  552. default:
  553. nRes = memcmp(pCurBuf, pRefBuf, nLen);
  554. break;
  555. }
  556. if (nRes == 0)
  557. {
  558. // Mark the current index record, so it's not used anymore.
  559. // This is true if the block name is found, regardless of the content
  560. // comparison results.
  561. idxCur.fCopied = true;
  562. rgFileIdx->Set(i, idxCur);
  563. break;
  564. }
  565. delete [] pCurBuf;
  566. pCurBuf = NULL;
  567. }
  568. }
  569. if (pCurBuf)
  570. {
  571. delete [] pCurBuf;
  572. pCurBuf = NULL;
  573. }
  574. return (nRes ? false : true);
  575. }
  576. //
  577. // Compare two files, by walking through the reference file and using the index
  578. // to read the current file.
  579. //
  580. void CompareFiles(HANDLE fileCur, HANDLE fileRef,
  581. CAutoArray<INDEX>* rgFileIdx, HANDLE fileDiff)
  582. {
  583. INDEX idxRef = {BLK_NONE, 0}; // index record for the reference file block
  584. INDEX idxAttr = {BLK_NONE, 0};
  585. bool fContinue = true;
  586. unsigned long ulOffset;
  587. char * pRefBuf = NULL;
  588. char * pAttrBuf = NULL;
  589. bool fFound = false;
  590. //create an index for the file that is to be analyzed.
  591. while ( fContinue )
  592. {
  593. ulOffset = 0;
  594. fContinue = GetBlock(fileRef, &idxRef, &pRefBuf, &ulOffset);
  595. if (fContinue)
  596. {
  597. switch (idxRef.blockType)
  598. {
  599. case BLK_ATTR:
  600. int nLen;
  601. idxAttr = idxRef; // the last attribute block is remembered, to be used with the
  602. // interface, dispinteface and coclass comparison.
  603. // if we currently have a block, release it
  604. if (pAttrBuf)
  605. {
  606. delete [] pAttrBuf;
  607. pAttrBuf = NULL;
  608. }
  609. nLen = idxAttr.ulEndPos - idxAttr.ulStartPos;
  610. pAttrBuf = new char[nLen+1];
  611. memcpy( pAttrBuf, pRefBuf+ulOffset, nLen);
  612. pAttrBuf[nLen] = 0;
  613. break;
  614. case BLK_DISPINT:
  615. case BLK_INTERFACE:
  616. case BLK_COCLASS:
  617. assert(idxAttr.blockType == BLK_ATTR);
  618. idxRef.ulAttrStartPos = idxAttr.ulStartPos;
  619. idxRef.ulAttrEndPos = idxAttr.ulEndPos;
  620. fFound = CompareBlocks( fileCur, rgFileIdx, &idxRef, &pRefBuf[ulOffset], pAttrBuf, fileDiff);
  621. if (!fFound)
  622. {
  623. char szBuf[MAX_PATH];
  624. sprintf(szBuf, "\n%s- Removed", strtok(&pRefBuf[ulOffset], "{"));
  625. WriteLine(fileDiff, szBuf, -1);
  626. g_ulAppRetVal |= CHANGE_BLOCKREMOVED;
  627. }
  628. //release the memory allocated by the GetBlock function
  629. delete [] pRefBuf;
  630. pRefBuf = NULL;
  631. delete [] pAttrBuf;
  632. pAttrBuf = NULL;
  633. idxAttr.blockType = BLK_NONE;
  634. break;
  635. /* ferhane: see comments in PrepareIndex
  636. case BLK_TYPEDEF:
  637. break;
  638. */
  639. }
  640. }
  641. }
  642. }
  643. void DisplayError(UINT uError, UINT uLineNum /* = __LINE__ */, ostream& out /* = cerr*/)
  644. {
  645. assert(uError < BUFFER_SIZE(pszErrors));
  646. out.fill('0');
  647. out << "TlDiff.exe(" << uLineNum << ") : error E9"
  648. << setw(3) << uError << ": " << pszErrors[uError] << endl;
  649. }
  650. /*----------------------------------------------------------------------------
  651. -----------------------------------------------------------------------------*/
  652. bool ProcessINIFile(char* lpszIniFile)
  653. {
  654. bool fRet = true;
  655. char szFileNames[] = {"FileNames"};
  656. char szCheckRules[] = {"CheckRules"};
  657. char szMethodAttr[] = {"BreakingMethodAttributes"};
  658. DWORD dwBuffSize = 256;
  659. DWORD dwBuffSizeOld;
  660. char* pszDirectory = new char[dwBuffSize + 13];
  661. dwBuffSize = GetCurrentDirectory(dwBuffSize, pszDirectory);
  662. if (dwBuffSize > 256)
  663. {
  664. // we need a larger buffer for path.
  665. delete pszDirectory;
  666. pszDirectory = NULL;
  667. pszDirectory = new char[dwBuffSize+13];
  668. if (!pszDirectory)
  669. {
  670. DisplayError(ERR_OUTOFMEMORY, __LINE__);
  671. fRet = false;
  672. goto Error;
  673. }
  674. GetCurrentDirectory( dwBuffSize, pszDirectory );
  675. }
  676. lstrcat(pszDirectory, "\\");
  677. lstrcat(pszDirectory, lpszIniFile);
  678. // Make sure the INI file exists
  679. // GetFileAttributes returns 0xFFFFFFFF if the
  680. // file doesn't exist.
  681. //
  682. if (0xFFFFFFFF == GetFileAttributes(pszDirectory))
  683. {
  684. DisplayError(ERR_INIFILENOTFOUND, __LINE__);
  685. fRet = false;
  686. goto Error;
  687. }
  688. /*
  689. if (!GetPrivateProfileString(szFileNames, "CurrentFile", "cur.out", g_szCurFileName, 255, pszDirectory))
  690. {
  691. DisplayError( ERR_CURRFILENAME );
  692. bRet = FALSE;
  693. goto Error;
  694. }
  695. if (!GetPrivateProfileString(szFileNames, "ReferenceFile", "ref.out", g_szRefFileName, 255, pszDirectory))
  696. {
  697. DisplayError( ERR_REFFILENAME );
  698. bRet = FALSE;
  699. goto Error;
  700. }
  701. */
  702. if (!g_fWriteToStdOut)
  703. {
  704. // Specify a NULL default name so that we can check to see
  705. // if the file name wasn't specified in the INI file.
  706. //
  707. // If either the difference file or new file name is missing
  708. // from the INI, we write to stdout.
  709. //
  710. GetPrivateProfileString(szFileNames, "DifferenceFile", NULL, g_szDiffFileName,
  711. BUFFER_SIZE(g_szDiffFileName) - 1, pszDirectory);
  712. if (NULL == g_szDiffFileName[0])
  713. {
  714. g_fWriteToStdOut = true;
  715. }
  716. else
  717. {
  718. GetPrivateProfileString(szFileNames, "AdditionsFile", NULL, g_szNewFileName,
  719. BUFFER_SIZE(g_szNewFileName) - 1, pszDirectory);
  720. if (NULL == g_szNewFileName[0])
  721. {
  722. g_fWriteToStdOut = true;
  723. }
  724. }
  725. }
  726. fgCoClass = !!(GetPrivateProfileInt(szCheckRules, "Coclass", 1, pszDirectory));
  727. fgInterface = !!(GetPrivateProfileInt(szCheckRules, "Interface", 1, pszDirectory));
  728. fgDispInterface = !!(GetPrivateProfileInt(szCheckRules, "Dispinterface", 1, pszDirectory));
  729. fgMethodParameter = !!(GetPrivateProfileInt(szCheckRules, "MethodParameter", 1, pszDirectory));
  730. fgMethodAttribute = !!(GetPrivateProfileInt(szCheckRules, "MethodAttribute", 1, pszDirectory));
  731. fgInterfaceAttr = !!(GetPrivateProfileInt(szCheckRules, "InterfaceAttribute", 1, pszDirectory));
  732. fgFlush = !!(GetPrivateProfileInt(szCheckRules, "GenerateAdditionsFile", 1, pszDirectory));
  733. fgParamNames = !!(GetPrivateProfileInt(szCheckRules, "ParameterName", 1, pszDirectory));
  734. fgParamTypes = !!(GetPrivateProfileInt(szCheckRules, "ParameterType", 1, pszDirectory));
  735. fgParamNameCase= !!(GetPrivateProfileInt(szCheckRules, "ParameterNameCase", 1, pszDirectory));
  736. fgParamTypeCase= !!(GetPrivateProfileInt(szCheckRules, "ParameterTypeCase", 1, pszDirectory));
  737. // get breaking method attributes.
  738. g_pszMethodAttr = new char[dwBuffSize];
  739. dwBuffSizeOld = 0;
  740. // down side of the APIs... It won't tell it needs more, it returns size - 1 or
  741. // size - 2 to indicate that it does not have enough buffer.
  742. //
  743. while (dwBuffSize < dwBuffSizeOld - 2)
  744. {
  745. dwBuffSizeOld = dwBuffSize; // reset the condition.
  746. // Read into the buffer.
  747. dwBuffSize = GetPrivateProfileString(szMethodAttr, NULL, "none", g_pszMethodAttr,
  748. dwBuffSize, pszDirectory);
  749. // Did we have enough buffer size?
  750. //
  751. if (dwBuffSize < dwBuffSizeOld - 2)
  752. {
  753. break;
  754. }
  755. // Reallocate and try again.
  756. //
  757. delete g_pszMethodAttr;
  758. dwBuffSize = dwBuffSize * 2;
  759. g_pszMethodAttr = new char[dwBuffSize];
  760. }
  761. Error:
  762. if (pszDirectory)
  763. delete pszDirectory;
  764. return fRet;
  765. }
  766. void ShowUsage()
  767. {
  768. cout << endl
  769. << "Usage: tldiff [-?|h] [-s] -f SettingsFile CurFile.out RefFile.out" << endl << endl
  770. << "Where: -?|h = Show usage. (These arguments are exclusive from the rest)" << endl
  771. << " -s = write output to stdout." << endl
  772. << " -f = use SettingsFile for initialization data." << endl
  773. << " CurFile.out = Tlviewer file containing data for current tlb" << endl
  774. << " RefFile.out = Tlviewer file containing data for new tlb" << endl
  775. << endl;
  776. }
  777. bool ProcessArgs(int argc, char* argv[])
  778. {
  779. char* pszIniFile = NULL;
  780. bool fSuccess = true;
  781. int i;
  782. // Check for "Show usage" request.
  783. //
  784. if ((argc >= 2) && ('-' == argv[1][0]) && ('?' == argv[1][1] || 'h' == argv[1][1]))
  785. {
  786. ShowUsage();
  787. return false;
  788. }
  789. if (argc < 5)
  790. {
  791. DisplayError(ERR_MISSINGARGS, __LINE__);
  792. goto Error;
  793. }
  794. // Note: i is initialized up top.
  795. //
  796. for (i=1; i < argc; i++)
  797. {
  798. if ('-' == argv[i][0])
  799. {
  800. switch(argv[i][1])
  801. {
  802. case 'f':
  803. {
  804. // The file is the next argument
  805. i++;
  806. if (i >= argc)
  807. {
  808. DisplayError(ERR_INIFILENAME, __LINE__);
  809. goto Error;
  810. }
  811. int nBufSize = lstrlen(argv[i]) + 1;
  812. pszIniFile = new char[nBufSize];
  813. if (!pszIniFile)
  814. {
  815. DisplayError(ERR_OUTOFMEMORY, __LINE__);
  816. goto Error;
  817. }
  818. lstrcpyn(pszIniFile, argv[i], nBufSize);
  819. break;
  820. }
  821. case 's':
  822. g_fWriteToStdOut = true;
  823. break;
  824. // Stop the build process for invalid arguments.
  825. // This ensures that somebody didn't make a typo.
  826. //
  827. default:
  828. DisplayError(ERR_INVALIDARG, __LINE__);
  829. goto Error;
  830. }
  831. }
  832. else
  833. {
  834. // Retrieve the current and new tlviewer output files.
  835. // These files must be in order. Therefore, I assume that
  836. // if the current file name variable is not set, then it's time
  837. // to set the current file name variable. If it is set, it's time
  838. // to set the new file name variable.
  839. //
  840. if (NULL == g_szCurFileName[0])
  841. {
  842. lstrcpyn(g_szCurFileName, argv[i], BUFFER_SIZE(g_szCurFileName));
  843. }
  844. else
  845. {
  846. lstrcpyn(g_szRefFileName, argv[i], BUFFER_SIZE(g_szRefFileName));
  847. }
  848. }
  849. }
  850. // This should never happen because the current file name
  851. // is the first file name in the arg list. I check anyway just
  852. // in case. If this every happens, that means there's a
  853. // nasty bug somewhere in the code.
  854. //
  855. if (NULL == g_szCurFileName[0])
  856. {
  857. DisplayError(ERR_CURFILENAME, __LINE__);
  858. goto Error;
  859. }
  860. if (NULL == g_szRefFileName[0])
  861. {
  862. DisplayError(ERR_REFFILENAME, __LINE__);
  863. goto Error;
  864. }
  865. if (pszIniFile)
  866. {
  867. fSuccess = ProcessINIFile(pszIniFile);
  868. }
  869. else
  870. {
  871. DisplayError(ERR_INIFILENAME, __LINE__);
  872. goto Error;
  873. }
  874. Cleanup:
  875. if (pszIniFile)
  876. delete pszIniFile;
  877. return fSuccess;
  878. Error:
  879. ShowUsage();
  880. fSuccess = false;
  881. goto Cleanup;
  882. }
  883. //----------------------------------------------------------------------------
  884. //----------------------------------------------------------------------------
  885. int __cdecl main(int argc, char* argv[])
  886. {
  887. HANDLE fileRef = INVALID_HANDLE_VALUE;
  888. HANDLE fileCur = INVALID_HANDLE_VALUE;
  889. HANDLE fileDiff = INVALID_HANDLE_VALUE;
  890. CAutoArray<INDEX>* rgFileIdx = NULL;
  891. //initialize global variables
  892. fgCoClass = fgInterface = fgDispInterface = fgMethodAttribute = fgMethodParameter
  893. = fgFlush = fgInterfaceAttr = true;
  894. g_ulAppRetVal = 0;
  895. //
  896. // Get and process the input arguments
  897. //
  898. if (!ProcessArgs(argc, argv))
  899. {
  900. goto Cleanup;
  901. }
  902. rgFileIdx = new CAutoArray<INDEX>;
  903. // Open the reference file and the current file
  904. //
  905. fileCur = CreateFile(g_szCurFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
  906. FILE_ATTRIBUTE_NORMAL, NULL);
  907. if (INVALID_HANDLE_VALUE == fileCur)
  908. {
  909. DisplayError(ERR_OPENINGCUR, __LINE__);
  910. goto Cleanup;
  911. }
  912. fileRef = CreateFile(g_szRefFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
  913. FILE_ATTRIBUTE_NORMAL, NULL);
  914. if (INVALID_HANDLE_VALUE == fileRef)
  915. {
  916. DisplayError(ERR_OPENINGREF, __LINE__);
  917. goto Cleanup;
  918. }
  919. // Prepare the index for the current file.
  920. cout << "Preparing index" << endl;
  921. PrepareIndex(fileCur, rgFileIdx);
  922. /* This was to test if the index algorithm would work on different files.
  923. The mirror file should only be different from the file passed in as the
  924. current file, by its blanks and new lines.
  925. */
  926. //create a test mirror file using the index information we have.
  927. /*cout << "Creating test mirror file" << endl;
  928. CreateTestMirror( fileCur, rgFileIdx );
  929. */
  930. // Compare files.
  931. //
  932. if (g_fWriteToStdOut)
  933. {
  934. fileDiff = GetStdHandle(STD_OUTPUT_HANDLE);
  935. }
  936. else
  937. {
  938. fileDiff = CreateFile(g_szDiffFileName, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
  939. FILE_ATTRIBUTE_NORMAL, NULL);
  940. }
  941. if (INVALID_HANDLE_VALUE == fileDiff)
  942. {
  943. DisplayError(ERR_OPENINGDIFF, __LINE__);
  944. goto Cleanup;
  945. }
  946. cout << "Comparing Files" << endl;
  947. CompareFiles(fileCur, fileRef, rgFileIdx, fileDiff);
  948. // Only close here if we aren't writing to stdout.
  949. // Otherwise, we won't be able to write to stdout anymore.
  950. //
  951. if ((!g_fWriteToStdOut) && (INVALID_HANDLE_VALUE != fileDiff))
  952. {
  953. CloseHandle(fileDiff);
  954. fileDiff = INVALID_HANDLE_VALUE;
  955. }
  956. // Compare the attributes of interfaces.
  957. // These contain the GUIDs of interfaces too.
  958. //
  959. if (fgInterfaceAttr)
  960. MarkAttrChanges(fileCur, rgFileIdx, g_szDiffFileName);
  961. // Flush out the blocks that are completely new for the current file
  962. // and do not exist on the reference file.
  963. if (fgFlush)
  964. FlushDifferences(fileCur, rgFileIdx);
  965. if (g_ulAppRetVal)
  966. {
  967. DisplayError(ERR_DIFFERENCES, __LINE__);
  968. }
  969. else
  970. {
  971. cout << "Comparison Complete: No Errors" << endl;
  972. }
  973. Cleanup:
  974. if (INVALID_HANDLE_VALUE != fileCur)
  975. CloseHandle(fileCur);
  976. if (INVALID_HANDLE_VALUE != fileRef)
  977. CloseHandle(fileRef);
  978. // Due to the fact that we may be writing to
  979. // stdout, we should only close it once at the
  980. // very end of this program. It is not specified
  981. // if closing the console is actually necessary.
  982. //
  983. if (INVALID_HANDLE_VALUE != fileDiff)
  984. CloseHandle(fileDiff);
  985. // Release the memory allocated for the index array
  986. if (rgFileIdx)
  987. delete [] rgFileIdx;
  988. if (g_pszMethodAttr)
  989. delete g_pszMethodAttr;
  990. return g_ulAppRetVal;
  991. }