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.

1401 lines
38 KiB

  1. //depot/private/Lab06_DEV/Windows/AppCompat/ShimDBC/mig.cpp#1 - branch change 8778 (text)
  2. ////////////////////////////////////////////////////////////////////////////////////
  3. //
  4. // File: mig.cpp
  5. //
  6. // History: ??-Jul-00 vadimb Added Migdb logic
  7. //
  8. //
  9. ////////////////////////////////////////////////////////////////////////////////////
  10. #include "StdAfx.h"
  11. #include "xml.h"
  12. #include "mig.h"
  13. #include "make.h"
  14. #include "typeinfo.h"
  15. #include "fileio.h"
  16. //
  17. // Max length of a migdb.inf string entry
  18. //
  19. #define MAX_INF_STRING_LENGTH 255
  20. //
  21. // from read.cpp - converts module type to a string (which is static)
  22. //
  23. LPCTSTR ModuleTypeIndicatorToStr(DWORD ModuleType);
  24. //
  25. // Mig tags support -- translation table
  26. //
  27. ATTRLISTENTRY g_rgMigDBAttributes[] = {
  28. MIGDB_ENTRY2(COMPANYNAME, COMPANY_NAME, COMPANYNAME ),
  29. MIGDB_ENTRY2(FILEDESCRIPTION, FILE_DESCRIPTION, FILEDESCRIPTION),
  30. MIGDB_ENTRY2(FILEVERSION, FILE_VERSION, FILEVERSION ),
  31. MIGDB_ENTRY2(INTERNALNAME, INTERNAL_NAME, INTERNALNAME ),
  32. MIGDB_ENTRY2(LEGALCOPYRIGHT, LEGAL_COPYRIGHT, LEGALCOPYRIGHT ),
  33. MIGDB_ENTRY2(ORIGINALFILENAME, ORIGINAL_FILENAME, ORIGINALFILENAME),
  34. MIGDB_ENTRY2(PRODUCTNAME, PRODUCT_NAME, PRODUCTNAME ),
  35. MIGDB_ENTRY2(PRODUCTVERSION, PRODUCT_VERSION, PRODUCTVERSION ),
  36. MIGDB_ENTRY2(FILESIZE, SIZE, FILESIZE ),
  37. MIGDB_ENTRY4(ISMSBINARY),
  38. MIGDB_ENTRY4(ISWIN9XBINARY),
  39. MIGDB_ENTRY4(INWINDIR),
  40. MIGDB_ENTRY4(INCATDIR),
  41. MIGDB_ENTRY4(INHLPDIR),
  42. MIGDB_ENTRY4(INSYSDIR),
  43. MIGDB_ENTRY4(INPROGRAMFILES),
  44. MIGDB_ENTRY4(ISNOTSYSROOT),
  45. MIGDB_ENTRY (CHECKSUM),
  46. MIGDB_ENTRY2(EXETYPE, MODULE_TYPE, EXETYPE ),
  47. MIGDB_ENTRY5(DESCRIPTION, 16BIT_DESCRIPTION, S16BITDESCRIPTION ),
  48. MIGDB_ENTRY4(INPARENTDIR),
  49. MIGDB_ENTRY4(INROOTDIR),
  50. MIGDB_ENTRY4(PNPID),
  51. MIGDB_ENTRY4(HLPTITLE),
  52. MIGDB_ENTRY4(ISWIN98),
  53. MIGDB_ENTRY4(HASVERSION),
  54. // MIGDB_ENTRY (REQFILE),
  55. MIGDB_ENTRY2(BINFILEVER, BIN_FILE_VERSION, BINFILEVER ),
  56. MIGDB_ENTRY2(BINPRODUCTVER, BIN_PRODUCT_VERSION, BINPRODUCTVER ),
  57. MIGDB_ENTRY5(FILEDATEHI, VERFILEDATEHI, FILEDATEHI),
  58. MIGDB_ENTRY5(FILEDATELO, VERFILEDATELO, FILEDATELO),
  59. MIGDB_ENTRY2(FILEVEROS, VERFILEOS, FILEVEROS ),
  60. MIGDB_ENTRY2(FILEVERTYPE, VERFILETYPE, FILEVERTYPE ),
  61. MIGDB_ENTRY4(FC),
  62. MIGDB_ENTRY2(UPTOBINPRODUCTVER,UPTO_BIN_PRODUCT_VERSION,UPTOBINPRODUCTVER),
  63. MIGDB_ENTRY2(UPTOBINFILEVER,UPTO_BIN_FILE_VERSION,UPTOBINFILEVER),
  64. MIGDB_ENTRY4(SECTIONKEY),
  65. MIGDB_ENTRY2(REGKEYPRESENT, REGISTRY_ENTRY, REGKEYPRESENT),
  66. MIGDB_ENTRY4(ATLEASTWIN98),
  67. // MIGDB_ENTRY (ARG)
  68. };
  69. TCHAR g_szArg[] = _T("ARG");
  70. TCHAR g_szReqFile[] = _T("REQFILE");
  71. //
  72. // report MigDB exception
  73. // this is our mechanism for passing errors around
  74. //
  75. void __cdecl MigThrowException(
  76. LPCTSTR lpszFormat, ...
  77. )
  78. {
  79. va_list arglist;
  80. CString csError;
  81. int nSize = 1024;
  82. LPTSTR lpszBuffer;
  83. va_start(arglist, lpszFormat);
  84. try {
  85. lpszBuffer = csError.GetBuffer(nSize);
  86. StringCchVPrintf(lpszBuffer, nSize, lpszFormat, arglist);
  87. csError.ReleaseBuffer();
  88. } catch(CMemoryException* pMemoryException) {
  89. SDBERROR(_T("Memory allocation error while trying to report an error\n"));
  90. pMemoryException->Delete();
  91. }
  92. // now we throw
  93. throw new CMigDBException(csError);
  94. }
  95. //
  96. // Given an XML attribute mask, produce equivalent Migdb attribute type
  97. //
  98. MIGATTRTYPE GetInfTagByXMLAttrType(
  99. IN DWORD dwXMLAttrType
  100. )
  101. {
  102. MIGATTRTYPE MigAttrType = NONE;
  103. int i;
  104. for (i = 0; i < sizeof(g_rgMigDBAttributes)/sizeof(g_rgMigDBAttributes[0]); ++i) {
  105. if (g_rgMigDBAttributes[i].XMLAttrType == dwXMLAttrType) {
  106. MigAttrType = g_rgMigDBAttributes[i].MigAttrType;
  107. break;
  108. }
  109. }
  110. return MigAttrType;
  111. }
  112. //
  113. // make string nice and flat, with no extra spaces in-between
  114. //
  115. //
  116. LPCTSTR g_pszDelim = _T(" \t\n\r");
  117. CString FlattenString(LPCTSTR lpszStr)
  118. {
  119. TCHAR* pchStart = (TCHAR*)lpszStr;
  120. TCHAR* pch;
  121. CString csResult;
  122. BOOL bSpace = FALSE;
  123. while (*pchStart) {
  124. //
  125. // skip leading spaces or other trash
  126. //
  127. pchStart += _tcsspn(pchStart, g_pszDelim);
  128. if (*pchStart == _T('\0')) {
  129. // tough bananas - we got what we've got, exit now
  130. break;
  131. }
  132. // search for the end-of-line
  133. pch = _tcspbrk(pchStart, g_pszDelim);
  134. if (pch == NULL) {
  135. // we are done, no more nasty characters
  136. // append and exit
  137. //
  138. if (bSpace) {
  139. csResult += _T(' ');
  140. }
  141. csResult += pchStart;
  142. break;
  143. }
  144. // add everything -- up until this \n
  145. if (bSpace) {
  146. csResult += _T(' ');
  147. }
  148. csResult += CString(pchStart, (int)(pch - pchStart));
  149. bSpace = TRUE; // we have just removed a portion of the string containing \n
  150. pchStart = pch; // point to the \n
  151. }
  152. //
  153. // Make quotes (") into double quotes ("") so that
  154. // it is legal INF
  155. //
  156. ReplaceStringNoCase(csResult, _T("\""), _T("\"\""));
  157. return csResult;
  158. }
  159. VOID FilterStringNonAlnum(
  160. CString& csTarget
  161. )
  162. {
  163. TCHAR ch;
  164. INT i;
  165. for (i = 0; i < csTarget.GetLength(); i++) {
  166. ch = csTarget.GetAt(i);
  167. if (!((ch >= 'a' && ch <= 'z') ||
  168. (ch >= 'A' && ch <= 'Z') ||
  169. (ch >= '0' && ch <= '9'))) {
  170. csTarget.SetAt(i, _T('_'));
  171. }
  172. }
  173. }
  174. ////////////////////////////////////////////////////////////////////////////////////////////
  175. //
  176. // Dumping .inf data support
  177. //
  178. CString MigApp::dump(void)
  179. {
  180. CString cs;
  181. BOOL bInline;
  182. INT i;
  183. MigAttribute* pAttr;
  184. // we can't do "inline" sections if we also have "ARGS"
  185. bInline = (0 == m_rgArgs.GetSize());
  186. cs = m_pSection->dump(m_csDescription.IsEmpty() ? NULL : (LPCTSTR)m_csDescription, NULL, FALSE, bInline);
  187. if (m_csDescription.IsEmpty() && !bInline) {
  188. cs += _T(",");
  189. }
  190. if (!bInline) {
  191. for (i = 0; i < m_rgArgs.GetSize(); ++i) {
  192. pAttr = (MigAttribute*)m_rgArgs.GetAt(i);
  193. cs += (cs.IsEmpty()? _T(""): _T(", ")) + pAttr->dump();
  194. }
  195. }
  196. return cs;
  197. }
  198. // we dump info into an array of strings, single-line entries are returned
  199. // The first kind of return is "inline" --
  200. // all the supplemental info is shoved into the rgOut
  201. // for example, the return might be a reference to the section
  202. // section's header and body are placed into rgOut
  203. // ELIMINATE duplicate section names (reqfile!)
  204. // optimize output - single "and" replaced with straight
  205. // if a section is generated and placed as a single-line entry, promote the contents
  206. // to upper level
  207. CString MigSection::dump(LPCTSTR lpszDescription, int* pIndexContents, BOOL bNoHeader, BOOL bInline)
  208. {
  209. SdbArrayElement* p;
  210. MigEntry* pEntry;
  211. MigSection* pSection;
  212. int indexContents = -1;
  213. int nEntries;
  214. const type_info& tiEntry = typeid(MigEntry); // cache type id info
  215. const type_info& tiSection = typeid(MigSection);
  216. int i;
  217. CString cs; // inline return
  218. CString csContents; // contents of supplemental section information
  219. CString csSect;
  220. CString csHeader;
  221. CString csDescription(lpszDescription);
  222. // place inline name and description
  223. // we may need to enclose this into quotes
  224. cs = m_csName;
  225. if (!csDescription.IsEmpty()) {
  226. if (csDescription.Left(1) == _T("%") &&
  227. csDescription.Right(1) == _T("%")) {
  228. cs += _T(", ") + csDescription;
  229. } else {
  230. cs += _T(", \"") + csDescription + _T("\"");
  231. }
  232. }
  233. // if our section is a single-entry
  234. // we dump this depending on the calling
  235. // special case -- single file (and/or, matters not)
  236. if (1 == m_rgEntries.GetSize() && m_bTopLevel && bInline) {
  237. // this single line goes "inline" only if we are called from within
  238. // other section
  239. // dump the entry if it's an entry
  240. p = (SdbArrayElement*)m_rgEntries.GetAt(0);
  241. if (typeid(*p) == tiEntry) {
  242. pEntry = (MigEntry*)p;
  243. if (m_bTopLevel && csDescription.IsEmpty()) { // if the description was not added earlier and top-level...
  244. cs += _T(",");
  245. }
  246. cs += _T(", ") + pEntry->dump();
  247. return cs;
  248. }
  249. }
  250. // first deal with sections...
  251. switch(m_Operation) {
  252. case MIGOP_OR:
  253. // grab just one section in all if more than one entry
  254. // IF we're the only entry -- but we need to have the right entry
  255. //
  256. if (!bNoHeader) { // ONLY valid for OR sections
  257. csContents.Format(_T("[%s]\n"), (LPCTSTR)m_csName);
  258. }
  259. for (i = 0; i < m_rgEntries.GetSize(); ++i) {
  260. p = (SdbArrayElement*)m_rgEntries.GetAt(i);
  261. const type_info& tiPtr = typeid(*p);
  262. if (tiPtr == tiEntry) {
  263. pEntry = (MigEntry*)p;
  264. csContents += pEntry->dump() + _T("\n");
  265. }
  266. else if (tiPtr == tiSection) {
  267. pSection = (MigSection*)p;
  268. csContents += pSection->dump() + _T("\n");
  269. }
  270. else {
  271. // if we are here -- something is seriously wrong
  272. // _tprintf(_T("Error - bad class information\n"));
  273. MigThrowException(_T("Bad Entry detected in section \"%s\"\n"), (LPCTSTR)m_csName);
  274. break;
  275. }
  276. }
  277. break;
  278. case MIGOP_AND:
  279. // and for this entry ...
  280. // optimization:
  281. // if we're single-entry, retrieve the contents of the child section
  282. // and put it right in
  283. nEntries = m_rgEntries.GetSize();
  284. for (i = 0; i < nEntries; ++i) {
  285. p = (SdbArrayElement*)m_rgEntries.GetAt(i);
  286. if (nEntries > 1) {
  287. ++m_nEntry;
  288. csSect.Format(_T("[%s.%d]\n"), (LPCTSTR)m_csName, m_nEntry);
  289. }
  290. else {
  291. csSect.Format(_T("[%s]\n"), (LPCTSTR)m_csName);
  292. }
  293. csContents += csSect;
  294. const type_info& tiPtr = typeid(*p);
  295. if (tiPtr == tiEntry) { // this is an entry, dump it into the section body
  296. pEntry = (MigEntry*)p;
  297. // numbered entry please...
  298. csContents += pEntry->dump() + _T("\n");
  299. }
  300. else if (tiPtr == tiSection) { // this is a section, dump it, get the ref into the section body
  301. pSection = (MigSection*)p;
  302. // optimization:
  303. if (pSection->m_Operation == MIGOP_OR) { // sub is an "OR" -- we need not have a ref
  304. int index;
  305. CString csSingle;
  306. // dump all the entries right here
  307. csSingle = pSection->dump(NULL, &index, TRUE);
  308. if (index >= 0) {
  309. csContents += m_pMigDB->m_rgOut.GetAt(index) + _T("\n");
  310. m_pMigDB->m_rgOut.RemoveAt(index);
  311. }
  312. else {
  313. csContents += csSingle;
  314. }
  315. }
  316. else {
  317. csContents += pSection->dump(NULL) + _T("\n");
  318. }
  319. }
  320. else {
  321. MigThrowException(_T("Internal Error: bad migration object\n"));
  322. break;
  323. }
  324. }
  325. break;
  326. }
  327. if (!csContents.IsEmpty()) {
  328. indexContents = m_pMigDB->m_rgOut.Add(csContents);
  329. }
  330. if (NULL != pIndexContents) {
  331. *pIndexContents = indexContents;
  332. }
  333. return cs;
  334. }
  335. CString MigEntry::FormatName(
  336. VOID
  337. )
  338. {
  339. INT i;
  340. TCHAR ch;
  341. BOOL bQuoteStr = FALSE;
  342. CString csName;
  343. bQuoteStr = (m_csName.GetLength() > 12); // 8.3 outright
  344. for (i = 0; i < m_csName.GetLength() && !bQuoteStr; ++i) {
  345. ch = m_csName.GetAt(i);
  346. bQuoteStr = _istspace(ch) || (!_istalnum(ch) && _T('.') != ch);
  347. }
  348. if (!bQuoteStr) { // hmmm check filename and ext part
  349. i = m_csName.Find(_T('.'));
  350. if (i < 0) {
  351. bQuoteStr = (m_csName.GetLength() > 8);
  352. }
  353. else {
  354. // check for the second dot
  355. bQuoteStr = (m_csName.Find(_T('.'), i+1) >= 0);
  356. if (!bQuoteStr) {
  357. // check for the ext length
  358. bQuoteStr = (m_csName.Mid(i).GetLength() > 4); // with .abc
  359. }
  360. }
  361. }
  362. if (!bQuoteStr) {
  363. return m_csName;
  364. }
  365. // else
  366. csName.Format(_T("\"%s\""), m_csName);
  367. return csName;
  368. }
  369. CString MigEntry::dump(void)
  370. {
  371. INT i;
  372. MigAttribute* pAttr;
  373. CString cs;
  374. CString csName;
  375. ULONG ulResult;
  376. // _tprintf(_T("Entry: name=\"%s\"\n"), (LPCTSTR)m_csName);
  377. // check whether we need to enclose this into quotes
  378. // to do such a check we need to:
  379. // check for non-ascii stuff...
  380. // parser has put all the ARG attributes in the beginning of the array
  381. // put any "arg" attributes before the exe name
  382. for (i = 0; i < m_rgAttrs.GetSize(); ++i) {
  383. pAttr = (MigAttribute*)m_rgAttrs.GetAt(i);
  384. if (ARG != pAttr->m_type) {
  385. break;
  386. }
  387. cs += (cs.IsEmpty()? _T(""): _T(", ")) + pAttr->dump();
  388. }
  389. cs += (cs.IsEmpty()? _T(""): _T(", ")) + FormatName();
  390. for (;i < m_rgAttrs.GetSize(); ++i) {
  391. pAttr = (MigAttribute*)m_rgAttrs.GetAt(i);
  392. cs += (cs.IsEmpty()? _T(""): _T(", ")) + pAttr->dump();
  393. }
  394. return cs;
  395. }
  396. CString MigAttribute::dump(void)
  397. {
  398. CString cs;
  399. CString csTemp;
  400. switch(m_type) {
  401. // note -- none of the attributes below are supported
  402. case ISMSBINARY:
  403. case ISWIN9XBINARY:
  404. case INWINDIR:
  405. case INCATDIR:
  406. case INHLPDIR:
  407. case INSYSDIR:
  408. case INPROGRAMFILES:
  409. case ISNOTSYSROOT:
  410. case INROOTDIR:
  411. case ISWIN98:
  412. case HASVERSION:
  413. case ATLEASTWIN98:
  414. cs.Format(_T("%s%s"), m_bNot ? _T("!") : _T(""), (LPCTSTR)m_csName);
  415. break;
  416. case CHECKSUM:
  417. case FILESIZE:
  418. // under old code the following two values had been strings
  419. case FILEDATEHI:
  420. case FILEDATELO:
  421. cs.Format(_T("%s%s(0x%.8lX)"), m_bNot?_T("!"):_T(""), (LPCTSTR)m_csName, m_dwValue);
  422. break;
  423. case BINFILEVER:
  424. case BINPRODUCTVER:
  425. case UPTOBINFILEVER:
  426. case UPTOBINPRODUCTVER:
  427. // version, ull
  428. VersionQwordToString(csTemp, m_ullValue);
  429. cs.Format(_T("%s%s(%s)"), m_bNot? _T("!"):_T(""), (LPCTSTR)m_csName, (LPCTSTR)csTemp);
  430. break;
  431. case EXETYPE:
  432. // this is dword-encoded format that really is a string, convert
  433. //
  434. cs.Format(_T("%s%s(\"%s\")"), m_bNot ? _T("!") : _T(""), (LPCTSTR)m_csName, ModuleTypeIndicatorToStr(m_dwValue));
  435. break;
  436. // these two attributes are not supported either
  437. case ARG:
  438. case REQFILE:
  439. if (m_pSection) {
  440. m_pSection->dump();
  441. }
  442. // fall through
  443. default:
  444. cs.Format(_T("%s%s(\"%s\")"), m_bNot ? _T("!") : _T(""), (LPCTSTR)m_csName, (LPCTSTR)m_csValue);
  445. break;
  446. }
  447. return cs;
  448. }
  449. /*++
  450. Used to be a nice statistics-spewing function
  451. VOID DumpMigDBStats(ShimDatabase* pDatabase)
  452. {
  453. POSITION pos = pDatabase->m_mapMigApp.GetStartPosition();
  454. ShimArray* prgApp;
  455. CString csSection;
  456. DWORD dwApps = 0;
  457. INT i;
  458. Print( _T("Sections compiled: %d\n\n"), pDatabase->m_mapMigApp.GetCount());
  459. while (pos) {
  460. pDatabase->m_mapMigApp.GetNextAssoc(pos, csSection, (LPVOID&)prgApp);
  461. Print(_T("Section [%36s]: %8ld apps\n"), (LPCTSTR)csSection, prgApp->GetSize());
  462. dwApps += prgApp->GetSize();
  463. }
  464. Print( _T("--------\n"));
  465. Print( _T("Total %38s: %8ld entries\n"), "", dwApps);
  466. Print( _T("\n"));
  467. if (gfVerbose) {
  468. Print(_T("APPS\n"));
  469. pos = pDatabase->m_mapMigApp.GetStartPosition();
  470. while (pos) {
  471. pDatabase->m_mapMigApp.GetNextAssoc(pos, csSection, (LPVOID&)prgApp);
  472. Print(_T("Section [%36s]: %8ld apps\n"), (LPCTSTR)csSection, prgApp->GetSize());
  473. Print(_T("-------------------------------------------------------------\n"));
  474. for (i = 0; i < prgApp->GetSize(); ++i) {
  475. MigApp* pApp = (MigApp*)prgApp->GetAt(i);
  476. Print(_T("%s\n"), (LPCTSTR)pApp->m_csName);
  477. }
  478. Print(_T("\n"));
  479. }
  480. }
  481. }
  482. --*/
  483. BOOL MigDatabase::DumpMigDBStrings(
  484. LPCTSTR lpszFilename
  485. )
  486. {
  487. CString csOut;
  488. POSITION pos;
  489. CANSITextFile OutFile(
  490. lpszFilename,
  491. m_pAppHelpDatabase->m_pCurrentMakefile->GetLangMap(m_pAppHelpDatabase->m_pCurrentOutputFile->m_csLangID)->m_dwCodePage,
  492. CFile::modeCreate|CFile::modeReadWrite|CFile::shareDenyWrite);
  493. CString csStringID;
  494. CString csStringContent;
  495. CString csCompoundString, csCompoundStringPart;
  496. long nCursor = 0;
  497. //
  498. // write header (needed for postbuild!)
  499. //
  500. OutFile.WriteString(_T(";\n; AppCompat additions start here\n;\n; ___APPCOMPAT_MIG_ENTRIES___\n;\n"));
  501. //
  502. // write out the strings section
  503. //
  504. pos = m_mapStringsOut.GetStartPosition();
  505. while (pos) {
  506. m_mapStringsOut.GetNextAssoc(pos, csStringID, csStringContent);
  507. if (csStringContent.GetLength() > MAX_INF_STRING_LENGTH) {
  508. nCursor = 0;
  509. csCompoundString.Empty();
  510. while (nCursor * MAX_INF_STRING_LENGTH < csStringContent.GetLength()) {
  511. csOut.Format(_T("%s.%d = \"%s\"\n"),
  512. (LPCTSTR)csStringID,
  513. nCursor + 1,
  514. (LPCTSTR)csStringContent.Mid(nCursor * MAX_INF_STRING_LENGTH, MAX_INF_STRING_LENGTH));
  515. OutFile.WriteString(csOut);
  516. csCompoundStringPart.Format(_T(" %%%s.%d%%"), csStringID, nCursor + 1);
  517. csCompoundString += csCompoundStringPart;
  518. nCursor++;
  519. }
  520. } else {
  521. csOut.Format(_T("%s = \"%s\"\n"), (LPCTSTR)csStringID, (LPCTSTR)csStringContent);
  522. OutFile.WriteString(csOut);
  523. }
  524. }
  525. return TRUE;
  526. }
  527. BOOL MigDatabase::DumpMigDBInf(
  528. LPCTSTR lpszFilename
  529. )
  530. {
  531. CString csSection;
  532. CString csOut;
  533. SdbArray<SdbArrayElement>* prgApp;
  534. INT i;
  535. MigApp* pApp;
  536. BOOL bSuccess = FALSE;
  537. POSITION pos;
  538. CStringArray rgShowInSimplifiedView;
  539. // clear out help array
  540. m_rgOut.RemoveAll();
  541. CANSITextFile OutFile(
  542. lpszFilename,
  543. m_pAppHelpDatabase->m_pCurrentMakefile->GetLangMap(m_pAppHelpDatabase->m_pCurrentOutputFile->m_csLangID)->m_dwCodePage,
  544. CFile::modeCreate|CFile::modeReadWrite|CFile::shareDenyWrite);
  545. //
  546. // traverse sections...
  547. //
  548. pos = m_mapSections.GetStartPosition();
  549. while (pos) {
  550. m_mapSections.GetNextAssoc(pos, csSection, (LPVOID&)prgApp);
  551. csOut.Format(_T("[%s]\n"), (LPCTSTR)csSection);
  552. OutFile.WriteString(csOut);
  553. for (i = 0; i < prgApp->GetSize(); ++i) {
  554. pApp = (MigApp*)prgApp->GetAt(i);
  555. csOut.Format(_T("%s\n"), pApp->dump());
  556. if (pApp->m_bShowInSimplifiedView) {
  557. rgShowInSimplifiedView.Add(csOut);
  558. }
  559. OutFile.WriteString(csOut);
  560. }
  561. csOut.Format(_T("\n"));
  562. OutFile.WriteString(csOut);
  563. }
  564. //
  565. // Dump ShowInSimplifiedView section
  566. //
  567. OutFile.WriteString(_T("[ShowInSimplifiedView]\n"));
  568. for (i = 0; i < rgShowInSimplifiedView.GetSize(); i++) {
  569. OutFile.WriteString(rgShowInSimplifiedView[i]);
  570. }
  571. OutFile.WriteString(_T("\n"));
  572. for (i = 0; i < m_rgOut.GetSize(); ++i) {
  573. OutFile.WriteString(m_rgOut.GetAt(i));
  574. }
  575. bSuccess = TRUE;
  576. return bSuccess;
  577. }
  578. MigSection& MigSection::operator=(SdbMatchOperation& rMatchOp)
  579. {
  580. MigEntry* pEntry;
  581. MigSection* pSection;
  582. int i;
  583. if (rMatchOp.m_Type == SDB_MATCH_ALL) {
  584. m_Operation = MIGOP_AND;
  585. } else if (rMatchOp.m_Type == SDB_MATCH_ANY) {
  586. m_Operation = MIGOP_OR;
  587. } else {
  588. MigThrowException(_T("Bad matching operation\n"));
  589. }
  590. // now translate the content
  591. for (i = 0; i < rMatchOp.m_rgMatchingFiles.GetSize(); ++i) {
  592. SdbMatchingFile* pMatchingFile = (SdbMatchingFile*)rMatchOp.m_rgMatchingFiles.GetAt(i);
  593. pEntry = new MigEntry(m_pMigDB);
  594. if (pEntry == NULL) {
  595. AfxThrowMemoryException();
  596. }
  597. *pEntry = *pMatchingFile;
  598. // add the entry in
  599. m_rgEntries.Add(pEntry, m_pDB);
  600. }
  601. for (i = 0; i < rMatchOp.m_rgSubMatchOps.GetSize(); ++i) {
  602. SdbMatchOperation* pMatchOp = (SdbMatchOperation*)rMatchOp.m_rgSubMatchOps.GetAt(i);
  603. pSection = new MigSection(m_pMigDB);
  604. if (pSection == NULL) {
  605. AfxThrowMemoryException();
  606. }
  607. //
  608. // format section's name
  609. //
  610. pSection->m_csName.Format(_T("%s_%lx"), (LPCTSTR)m_csName, i);
  611. *pSection = *pMatchOp;
  612. //
  613. // patch the name of the section
  614. //
  615. m_rgEntries.Add(pSection, m_pDB);
  616. }
  617. return *this;
  618. }
  619. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  620. //
  621. // Conversion code
  622. //
  623. MigApp& MigApp::operator=(
  624. SdbWin9xMigration& rMig
  625. )
  626. {
  627. INT i;
  628. SdbMatchingFile* pMatchingFile;
  629. MigEntry* pMigEntry;
  630. CString csSectionName;
  631. CString csID;
  632. BOOL bSuccess;
  633. CString csName;
  634. if (rMig.m_pApp == NULL) {
  635. MigThrowException(_T("Internal Compiler Error: Migration object should contain reference to the application"));
  636. }
  637. // name please
  638. csName = m_pMigDB->GetAppTitle(&rMig);
  639. m_csName = csName;
  640. ++m_pMigDB->m_dwExeCount;
  641. //
  642. // step one -- translate the general stuff
  643. // we will probably need
  644. m_pSection = new MigSection(m_pMigDB); //
  645. if (m_pSection == NULL) {
  646. AfxThrowMemoryException();
  647. }
  648. // our matching method is always AND (meaning all the files have to be present to produce a match
  649. // it is set when constructing the section object
  650. //
  651. // m_csSection -- set here the section where this exe will go
  652. // should the function below fail -- it will throw an exception
  653. //
  654. m_csSection = rMig.m_csSection; // copy the section over
  655. //
  656. // check whether we will have description
  657. m_csDescription = m_pMigDB->FormatDescriptionStringID(&rMig);
  658. //
  659. // Set the section's level
  660. //
  661. m_pSection->m_bTopLevel = TRUE;
  662. // the name of the section is the name of the app
  663. m_pSection->m_csName = csName;
  664. m_bShowInSimplifiedView = rMig.m_bShowInSimplifiedView;
  665. //
  666. // on to the assignment operation
  667. //
  668. *m_pSection = rMig.m_MatchOp; // simple assignment
  669. return *this;
  670. }
  671. MigEntry& MigEntry::operator=(
  672. SdbMatchingFile& rMatchingFile
  673. )
  674. {
  675. INT i;
  676. MigAttribute* pAttr;
  677. //
  678. // this name may be '*' denoting the main exe -- in this case the name will be corrected
  679. // on the upper level, after this assignment operation completes
  680. //
  681. m_csName = rMatchingFile.m_csName;
  682. // inherit the database ptr
  683. m_pDB = rMatchingFile.m_pDB;
  684. // roll through the attributes now
  685. for (i = 0; i < sizeof(g_rgMigDBAttributes)/sizeof(g_rgMigDBAttributes[0]); ++i) {
  686. if (!g_rgMigDBAttributes[i].XMLAttrType) {
  687. continue;
  688. }
  689. // now check whether this attribute is present in matching file
  690. if (!(rMatchingFile.m_dwMask & g_rgMigDBAttributes[i].XMLAttrType)) {
  691. // attribute not present, keep on
  692. continue;
  693. }
  694. // this attribute is present, encode it
  695. pAttr = new MigAttribute(m_pMigDB);
  696. if (pAttr == NULL) {
  697. AfxThrowMemoryException();
  698. }
  699. pAttr->m_type = g_rgMigDBAttributes[i].MigAttrType;
  700. pAttr->m_csName = g_rgMigDBAttributes[i].szOutputName ?
  701. g_rgMigDBAttributes[i].szOutputName :
  702. g_rgMigDBAttributes[i].szAttributeName;
  703. switch(g_rgMigDBAttributes[i].XMLAttrType) {
  704. case SDB_MATCHINGINFO_SIZE:
  705. pAttr->m_dwValue = rMatchingFile.m_dwSize;
  706. break;
  707. case SDB_MATCHINGINFO_CHECKSUM:
  708. pAttr->m_dwValue = rMatchingFile.m_dwChecksum;
  709. break;
  710. case SDB_MATCHINGINFO_COMPANY_NAME:
  711. pAttr->m_csValue = rMatchingFile.m_csCompanyName;
  712. break;
  713. case SDB_MATCHINGINFO_PRODUCT_NAME:
  714. pAttr->m_csValue = rMatchingFile.m_csProductName;
  715. break;
  716. case SDB_MATCHINGINFO_PRODUCT_VERSION:
  717. pAttr->m_csValue = rMatchingFile.m_csProductVersion;
  718. break;
  719. case SDB_MATCHINGINFO_FILE_DESCRIPTION:
  720. pAttr->m_csValue = rMatchingFile.m_csFileDescription;
  721. break;
  722. case SDB_MATCHINGINFO_BIN_FILE_VERSION:
  723. pAttr->m_ullValue = rMatchingFile.m_ullBinFileVersion;
  724. break;
  725. case SDB_MATCHINGINFO_BIN_PRODUCT_VERSION:
  726. pAttr->m_ullValue = rMatchingFile.m_ullBinProductVersion;
  727. break;
  728. case SDB_MATCHINGINFO_MODULE_TYPE:
  729. pAttr->m_dwValue = rMatchingFile.m_dwModuleType;
  730. break;
  731. case SDB_MATCHINGINFO_VERFILEDATEHI:
  732. pAttr->m_dwValue = rMatchingFile.m_dwFileDateMS;
  733. break;
  734. case SDB_MATCHINGINFO_VERFILEDATELO:
  735. pAttr->m_dwValue = rMatchingFile.m_dwFileDateLS;
  736. break;
  737. case SDB_MATCHINGINFO_VERFILEOS:
  738. pAttr->m_dwValue = rMatchingFile.m_dwFileOS;
  739. break;
  740. case SDB_MATCHINGINFO_VERFILETYPE:
  741. pAttr->m_dwValue = rMatchingFile.m_dwFileType;
  742. break;
  743. case SDB_MATCHINGINFO_PE_CHECKSUM:
  744. pAttr->m_ulValue = rMatchingFile.m_ulPECheckSum;
  745. break;
  746. case SDB_MATCHINGINFO_FILE_VERSION:
  747. pAttr->m_csValue = rMatchingFile.m_csFileVersion;
  748. break;
  749. case SDB_MATCHINGINFO_ORIGINAL_FILENAME:
  750. pAttr->m_csValue = rMatchingFile.m_csOriginalFileName;
  751. break;
  752. case SDB_MATCHINGINFO_INTERNAL_NAME:
  753. pAttr->m_csValue = rMatchingFile.m_csInternalName;
  754. break;
  755. case SDB_MATCHINGINFO_LEGAL_COPYRIGHT:
  756. pAttr->m_csValue = rMatchingFile.m_csLegalCopyright;
  757. break;
  758. case SDB_MATCHINGINFO_UPTO_BIN_PRODUCT_VERSION:
  759. pAttr->m_ullValue = rMatchingFile.m_ullUpToBinProductVersion;
  760. break;
  761. case SDB_MATCHINGINFO_UPTO_BIN_FILE_VERSION:
  762. pAttr->m_ullValue = rMatchingFile.m_ullUpToBinFileVersion;
  763. break;
  764. case SDB_MATCHINGINFO_16BIT_DESCRIPTION:
  765. pAttr->m_csValue = rMatchingFile.m_cs16BitDescription;
  766. break;
  767. case SDB_MATCHINGINFO_REGISTRY_ENTRY:
  768. pAttr->m_csValue = rMatchingFile.m_csRegistryEntry;
  769. break;
  770. //
  771. // case SDB_MATCHINGINFO_PREVOSMAJORVERSION
  772. // case SDB_MATCHINGINFO_PREVOSMINORVERSION
  773. // case SDB_MATCHINGINFO_PREVOSPLATFORMID
  774. // case SDB_MATCHINGINFO_PREVOSBUILDNO
  775. // there is no such attribute. it will simply be ignored
  776. //
  777. }
  778. m_rgAttrs.Add(pAttr, NULL);
  779. }
  780. return *this;
  781. }
  782. TCHAR g_szIncompatible[] = _T("Incompatible");
  783. TCHAR g_szReinstall[] = _T("Reinstall");
  784. CString MigDatabase::GetAppTitle(
  785. SdbWin9xMigration* pAppMig
  786. )
  787. {
  788. // part one -- get the application's title
  789. BOOL bSuccess;
  790. CString csID;
  791. CString csAppTitle;
  792. LPTSTR pBuffer = csID.GetBuffer(64); // a little more than you need for guid
  793. if (pBuffer == NULL) {
  794. AfxThrowMemoryException();
  795. }
  796. bSuccess = StringFromGUID(pBuffer, &pAppMig->m_ID);
  797. csID.ReleaseBuffer();
  798. if (!bSuccess) {
  799. MigThrowException(_T("Failed trying to convert GUID to string for entry \"%s\"\n"),
  800. (LPCTSTR)pAppMig->m_pApp->m_csName);
  801. }
  802. //
  803. // name of this particular exe (we don't care for it -- it won't be reflected anywhere)
  804. //
  805. csAppTitle.Format(_T("%s_%s"), (LPCTSTR)pAppMig->m_pApp->m_csName, (LPCTSTR)csID);
  806. csAppTitle.Remove(_T('{'));
  807. csAppTitle.Remove(_T('}'));
  808. // weed out the rest of non-alnum characters
  809. FilterStringNonAlnum(csAppTitle);
  810. return csAppTitle;
  811. }
  812. CString MigDatabase::GetDescriptionStringID(
  813. SdbWin9xMigration* pAppMig
  814. )
  815. {
  816. CString csDescriptionID;
  817. // part one -- get the application's title
  818. BOOL bSuccess;
  819. CString csID;
  820. CString csAppTitle;
  821. if (pAppMig->m_csMessage.IsEmpty()) {
  822. return csID; // empty string
  823. }
  824. LPTSTR pBuffer = csID.GetBuffer(64); // a little more than you need for guid
  825. if (pBuffer == NULL) {
  826. AfxThrowMemoryException();
  827. }
  828. bSuccess = StringFromGUID(pBuffer, &pAppMig->m_ID);
  829. csID.ReleaseBuffer();
  830. if (!bSuccess) {
  831. MigThrowException(_T("Failed trying to convert GUID to string for entry \"%s\"\n"),
  832. (LPCTSTR)pAppMig->m_pApp->m_csName);
  833. }
  834. //
  835. // name of this particular exe (we don't care for it -- it won't be reflected anywhere)
  836. //
  837. csDescriptionID.Format(_T("__Message_%s_%s"), (LPCTSTR)pAppMig->m_csMessage, (LPCTSTR)csID);
  838. csDescriptionID.Remove(_T('{'));
  839. csDescriptionID.Remove(_T('}'));
  840. // weed out the rest of non-alnum characters
  841. FilterStringNonAlnum(csDescriptionID);
  842. return csDescriptionID;
  843. }
  844. CString MigDatabase::FormatDescriptionStringID(
  845. SdbWin9xMigration* pMigApp
  846. )
  847. {
  848. CString csDescriptionID;
  849. CString csRet;
  850. CString csCompoundStringPart;
  851. CString csStringContent;
  852. long nCursor;
  853. //
  854. // get the string
  855. // basis is the application's name
  856. csDescriptionID = GetDescriptionStringID(pMigApp);
  857. if (csDescriptionID.IsEmpty()) {
  858. return csDescriptionID;
  859. }
  860. csStringContent = GetDescriptionString(pMigApp);
  861. if (csStringContent.GetLength() > MAX_INF_STRING_LENGTH) {
  862. nCursor = 0;
  863. while (nCursor * MAX_INF_STRING_LENGTH < csStringContent.GetLength()) {
  864. csCompoundStringPart.Format(_T("%%%s.%d%%"), csDescriptionID, nCursor + 1);
  865. csRet += csCompoundStringPart;
  866. nCursor++;
  867. }
  868. } else {
  869. csRet.Format(_T("%%%s%%"), csDescriptionID);
  870. }
  871. //
  872. // return id
  873. //
  874. return csRet;
  875. }
  876. CString MigDatabase::GetDescriptionString(
  877. SdbWin9xMigration* pMigApp
  878. )
  879. {
  880. CString csDescription;
  881. SdbMessage* pMessage;
  882. SdbDatabase* pMessageDB;
  883. CString csDetails;
  884. BOOL bSuccess;
  885. //
  886. // get apphelp database
  887. //
  888. pMessageDB = m_pMessageDatabase;
  889. if (pMessageDB == NULL) {
  890. MigThrowException(_T("Internal error: cannot produce description without apphelp database\n"));
  891. }
  892. if (pMigApp->m_csMessage.IsEmpty()) {
  893. return csDescription;
  894. }
  895. //
  896. // lookup this app in the apphelp db
  897. //
  898. pMessage = (SdbMessage *)pMessageDB->m_rgMessages.LookupName(pMigApp->m_csMessage, pMessageDB->m_pCurrentMakefile->m_csLangID);
  899. if (pMessage == NULL) {
  900. MigThrowException(_T("Exe \"%s\" has bad apphelp reference object\n"), (LPCTSTR)pMigApp->m_csMessage);
  901. }
  902. bSuccess = pMessageDB->ConstructMigrationMessage(pMigApp,
  903. pMessage,
  904. &csDetails);
  905. if (!bSuccess) {
  906. MigThrowException(_T("Failed to construct Migration message %s for \"%s\"\n"),
  907. (LPCTSTR)pMigApp->m_pApp->m_csName, pMigApp->m_csMessage);
  908. }
  909. //
  910. // 2. now that we have csDetails, flatten it
  911. //
  912. csDescription = FlattenString(csDetails);
  913. return csDescription;
  914. }
  915. BOOL MigDatabase::AddApp(
  916. MigApp* pApp
  917. )
  918. {
  919. SdbArray<MigApp>* prgApp;
  920. CString csSection;
  921. csSection = pApp->m_csSection;
  922. csSection.MakeUpper();
  923. if (m_mapSections.Lookup(csSection, (LPVOID&)prgApp)) {
  924. if (g_bStrict && NULL != prgApp->LookupName(pApp->m_csName)) {
  925. //
  926. // can't do that -- duplicate name
  927. //
  928. MigThrowException(_T("Duplicate application name found for app \"%s\"\n"), (LPCTSTR)pApp->m_csName);
  929. }
  930. prgApp->Add(pApp, m_pFixDatabase, FALSE);
  931. } else {
  932. prgApp = new SdbArray<MigApp>;
  933. if (prgApp == NULL) {
  934. AfxThrowMemoryException();
  935. }
  936. prgApp->Add(pApp, m_pFixDatabase, FALSE);
  937. m_mapSections.SetAt(csSection, (LPVOID&)prgApp);
  938. }
  939. return TRUE;
  940. }
  941. BOOL MigDatabase::Populate(
  942. VOID
  943. )
  944. {
  945. //
  946. // roll through all the outer objects (exes and generate migdb objects)
  947. //
  948. int i, iMig;
  949. SdbExe* pExe;
  950. MigApp* pMigApp;
  951. SdbDatabase* pFixDatabase = m_pFixDatabase;
  952. SdbApp* pApp;
  953. SdbWin9xMigration* pMigration;
  954. if (pFixDatabase == NULL) {
  955. MigThrowException(_T("Cannot produce migdb entries without fix db\n"));
  956. }
  957. for (i = 0; i < pFixDatabase->m_rgApps.GetSize(); i++) {
  958. //
  959. // for each app check whether it has migration info
  960. //
  961. pApp = (SdbApp*)pFixDatabase->m_rgApps.GetAt(i);
  962. for (iMig = 0; iMig < pApp->m_rgWin9xMigEntries.GetSize(); ++iMig) {
  963. pMigration = (SdbWin9xMigration*)pApp->m_rgWin9xMigEntries.GetAt(iMig);
  964. pMigApp = new MigApp(this);
  965. if (pMigApp == NULL) {
  966. AfxThrowMemoryException();
  967. }
  968. // we have a brand new migration object, assign it
  969. *pMigApp = *pMigration;
  970. // once that is done, pMigApp->m_csSection has the destination of it
  971. // this function will throw an exception if an error occurs
  972. AddApp(pMigApp);
  973. }
  974. }
  975. return TRUE;
  976. }
  977. BOOL MigDatabase::PopulateStrings(
  978. VOID
  979. )
  980. {
  981. SdbWin9xMigration* pMigration;
  982. SdbApp* pApp;
  983. CString csDescriptionID;
  984. CString csDescription;
  985. CString csAppTitleID;
  986. CString csAppTitle;
  987. CString csTemp;
  988. int i, iMig;
  989. //
  990. // get all the strings
  991. //
  992. for (i = 0; i < m_pAppHelpDatabase->m_rgApps.GetSize(); i++) {
  993. //
  994. // for each app check whether it has migration info
  995. //
  996. pApp = (SdbApp*)m_pAppHelpDatabase->m_rgApps.GetAt(i);
  997. for (iMig = 0; iMig < pApp->m_rgWin9xMigEntries.GetSize(); ++iMig) {
  998. pMigration = (SdbWin9xMigration*)pApp->m_rgWin9xMigEntries.GetAt(iMig);
  999. //
  1000. // Set up title strings
  1001. //
  1002. csAppTitleID = GetAppTitle(pMigration);
  1003. csAppTitle = pMigration->m_pApp->GetLocalizedAppName();
  1004. if (m_mapStringsOut.Lookup(csAppTitleID, csTemp)) {
  1005. MigThrowException(_T("Duplicate String ID \"%s\" found for entry \"%s\"\n"),
  1006. csAppTitleID,
  1007. pMigration->m_pApp->m_csName);
  1008. }
  1009. m_mapStringsOut.SetAt(csAppTitleID, csAppTitle);
  1010. csDescription = GetDescriptionString(pMigration);
  1011. csDescriptionID = GetDescriptionStringID(pMigration);
  1012. if (csDescriptionID.IsEmpty()) { // we allow description to be empty
  1013. continue;
  1014. }
  1015. if (m_mapStringsOut.Lookup(csDescriptionID, csTemp)) {
  1016. MigThrowException(_T("Duplicate String ID \"%s\" found for entry \"%s\"\n"),
  1017. csDescriptionID,
  1018. pMigration->m_pApp->m_csName);
  1019. }
  1020. m_mapStringsOut.SetAt(csDescriptionID, csDescription);
  1021. }
  1022. }
  1023. return TRUE;
  1024. }
  1025. ////////////////////////////////////////////////////////////////////////////
  1026. //
  1027. // Top-level function
  1028. //
  1029. // if supplied: pAppHelpDatabase and pFixDatabase ->> migapp.inx is produced
  1030. // pAppHelpDatabase and pMessageDatabas ->> migapp.txt is produced
  1031. //
  1032. BOOL WriteMigDBFile(
  1033. SdbDatabase* pFixDatabase, // may be NULL
  1034. SdbDatabase* pAppHelpDatabase, // always supplied
  1035. SdbDatabase* pMessageDatabase, // may be NULL
  1036. LPCTSTR lpszFileName // always supplied
  1037. )
  1038. {
  1039. MigDatabase* pMigDatabase = NULL;
  1040. BOOL bSuccess = FALSE;
  1041. // construct migdatabase object and populate it
  1042. try {
  1043. // construct
  1044. pMigDatabase = new MigDatabase;
  1045. if (pMigDatabase == NULL) {
  1046. AfxThrowMemoryException();
  1047. }
  1048. // init MigDatabase object
  1049. //
  1050. // [markder] Make them all the same so that
  1051. // we can process messages/fixes at the same
  1052. // time.
  1053. //
  1054. pMigDatabase->m_pFixDatabase = pAppHelpDatabase;
  1055. pMigDatabase->m_pAppHelpDatabase = pAppHelpDatabase;
  1056. pMigDatabase->m_pMessageDatabase = pAppHelpDatabase;
  1057. bSuccess = pMigDatabase->Populate();
  1058. if (!bSuccess) {
  1059. throw new CMigDBException(_T("Unknown error populating MIGDB additions."));
  1060. }
  1061. bSuccess = pMigDatabase->PopulateStrings();
  1062. if (!bSuccess) {
  1063. throw new CMigDBException(_T("Unknown error populating MIGDB additions."));
  1064. }
  1065. if (pFixDatabase != NULL) {
  1066. //
  1067. // produce migdb.inf
  1068. //
  1069. bSuccess = pMigDatabase->DumpMigDBInf(lpszFileName);
  1070. } else { // dumping the strings
  1071. bSuccess = pMigDatabase->DumpMigDBStrings(lpszFileName);
  1072. }
  1073. delete pMigDatabase;
  1074. //
  1075. // can only get here if we don't catch any exceptions
  1076. //
  1077. return bSuccess;
  1078. } catch(CMigDBException* pMigdbException) {
  1079. SDBERROR((LPCTSTR)pMigdbException->m_csError);
  1080. pMigdbException->Delete();
  1081. } catch(CFileException* pFileException) {
  1082. //
  1083. // a little more tricky
  1084. //
  1085. CString csError;
  1086. int nSize = 1024;
  1087. BOOL bError;
  1088. bError = pFileException->GetErrorMessage(csError.GetBuffer(nSize), nSize);
  1089. csError.ReleaseBuffer();
  1090. if (bError) {
  1091. SDBERROR((LPCTSTR)csError);
  1092. }
  1093. pFileException->Delete();
  1094. } catch(CMemoryException* pMemoryException) {
  1095. SDBERROR(_T("Memory Allocation Failure\n"));
  1096. pMemoryException->Delete();
  1097. }
  1098. return FALSE;
  1099. }