windows-nt/Source/XPSP1/NT/windows/appcompat/shimdbc/mig.cpp
2020-09-26 16:20:57 +08:00

1402 lines
38 KiB
C++

//depot/private/Lab06_DEV/Windows/AppCompat/ShimDBC/mig.cpp#1 - branch change 8778 (text)
////////////////////////////////////////////////////////////////////////////////////
//
// File: mig.cpp
//
// History: ??-Jul-00 vadimb Added Migdb logic
//
//
////////////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "xml.h"
#include "mig.h"
#include "make.h"
#include "typeinfo.h"
#include "fileio.h"
//
// Max length of a migdb.inf string entry
//
#define MAX_INF_STRING_LENGTH 255
//
// from read.cpp - converts module type to a string (which is static)
//
LPCTSTR ModuleTypeIndicatorToStr(DWORD ModuleType);
//
// Mig tags support -- translation table
//
ATTRLISTENTRY g_rgMigDBAttributes[] = {
MIGDB_ENTRY2(COMPANYNAME, COMPANY_NAME, COMPANYNAME ),
MIGDB_ENTRY2(FILEDESCRIPTION, FILE_DESCRIPTION, FILEDESCRIPTION),
MIGDB_ENTRY2(FILEVERSION, FILE_VERSION, FILEVERSION ),
MIGDB_ENTRY2(INTERNALNAME, INTERNAL_NAME, INTERNALNAME ),
MIGDB_ENTRY2(LEGALCOPYRIGHT, LEGAL_COPYRIGHT, LEGALCOPYRIGHT ),
MIGDB_ENTRY2(ORIGINALFILENAME, ORIGINAL_FILENAME, ORIGINALFILENAME),
MIGDB_ENTRY2(PRODUCTNAME, PRODUCT_NAME, PRODUCTNAME ),
MIGDB_ENTRY2(PRODUCTVERSION, PRODUCT_VERSION, PRODUCTVERSION ),
MIGDB_ENTRY2(FILESIZE, SIZE, FILESIZE ),
MIGDB_ENTRY4(ISMSBINARY),
MIGDB_ENTRY4(ISWIN9XBINARY),
MIGDB_ENTRY4(INWINDIR),
MIGDB_ENTRY4(INCATDIR),
MIGDB_ENTRY4(INHLPDIR),
MIGDB_ENTRY4(INSYSDIR),
MIGDB_ENTRY4(INPROGRAMFILES),
MIGDB_ENTRY4(ISNOTSYSROOT),
MIGDB_ENTRY (CHECKSUM),
MIGDB_ENTRY2(EXETYPE, MODULE_TYPE, EXETYPE ),
MIGDB_ENTRY5(DESCRIPTION, 16BIT_DESCRIPTION, S16BITDESCRIPTION ),
MIGDB_ENTRY4(INPARENTDIR),
MIGDB_ENTRY4(INROOTDIR),
MIGDB_ENTRY4(PNPID),
MIGDB_ENTRY4(HLPTITLE),
MIGDB_ENTRY4(ISWIN98),
MIGDB_ENTRY4(HASVERSION),
// MIGDB_ENTRY (REQFILE),
MIGDB_ENTRY2(BINFILEVER, BIN_FILE_VERSION, BINFILEVER ),
MIGDB_ENTRY2(BINPRODUCTVER, BIN_PRODUCT_VERSION, BINPRODUCTVER ),
MIGDB_ENTRY5(FILEDATEHI, VERFILEDATEHI, FILEDATEHI),
MIGDB_ENTRY5(FILEDATELO, VERFILEDATELO, FILEDATELO),
MIGDB_ENTRY2(FILEVEROS, VERFILEOS, FILEVEROS ),
MIGDB_ENTRY2(FILEVERTYPE, VERFILETYPE, FILEVERTYPE ),
MIGDB_ENTRY4(FC),
MIGDB_ENTRY2(UPTOBINPRODUCTVER,UPTO_BIN_PRODUCT_VERSION,UPTOBINPRODUCTVER),
MIGDB_ENTRY2(UPTOBINFILEVER,UPTO_BIN_FILE_VERSION,UPTOBINFILEVER),
MIGDB_ENTRY4(SECTIONKEY),
MIGDB_ENTRY2(REGKEYPRESENT, REGISTRY_ENTRY, REGKEYPRESENT),
MIGDB_ENTRY4(ATLEASTWIN98),
// MIGDB_ENTRY (ARG)
};
TCHAR g_szArg[] = _T("ARG");
TCHAR g_szReqFile[] = _T("REQFILE");
//
// report MigDB exception
// this is our mechanism for passing errors around
//
void __cdecl MigThrowException(
LPCTSTR lpszFormat, ...
)
{
va_list arglist;
CString csError;
int nSize = 1024;
LPTSTR lpszBuffer;
va_start(arglist, lpszFormat);
try {
lpszBuffer = csError.GetBuffer(nSize);
StringCchVPrintf(lpszBuffer, nSize, lpszFormat, arglist);
csError.ReleaseBuffer();
} catch(CMemoryException* pMemoryException) {
SDBERROR(_T("Memory allocation error while trying to report an error\n"));
pMemoryException->Delete();
}
// now we throw
throw new CMigDBException(csError);
}
//
// Given an XML attribute mask, produce equivalent Migdb attribute type
//
MIGATTRTYPE GetInfTagByXMLAttrType(
IN DWORD dwXMLAttrType
)
{
MIGATTRTYPE MigAttrType = NONE;
int i;
for (i = 0; i < sizeof(g_rgMigDBAttributes)/sizeof(g_rgMigDBAttributes[0]); ++i) {
if (g_rgMigDBAttributes[i].XMLAttrType == dwXMLAttrType) {
MigAttrType = g_rgMigDBAttributes[i].MigAttrType;
break;
}
}
return MigAttrType;
}
//
// make string nice and flat, with no extra spaces in-between
//
//
LPCTSTR g_pszDelim = _T(" \t\n\r");
CString FlattenString(LPCTSTR lpszStr)
{
TCHAR* pchStart = (TCHAR*)lpszStr;
TCHAR* pch;
CString csResult;
BOOL bSpace = FALSE;
while (*pchStart) {
//
// skip leading spaces or other trash
//
pchStart += _tcsspn(pchStart, g_pszDelim);
if (*pchStart == _T('\0')) {
// tough bananas - we got what we've got, exit now
break;
}
// search for the end-of-line
pch = _tcspbrk(pchStart, g_pszDelim);
if (pch == NULL) {
// we are done, no more nasty characters
// append and exit
//
if (bSpace) {
csResult += _T(' ');
}
csResult += pchStart;
break;
}
// add everything -- up until this \n
if (bSpace) {
csResult += _T(' ');
}
csResult += CString(pchStart, (int)(pch - pchStart));
bSpace = TRUE; // we have just removed a portion of the string containing \n
pchStart = pch; // point to the \n
}
//
// Make quotes (") into double quotes ("") so that
// it is legal INF
//
ReplaceStringNoCase(csResult, _T("\""), _T("\"\""));
return csResult;
}
VOID FilterStringNonAlnum(
CString& csTarget
)
{
TCHAR ch;
INT i;
for (i = 0; i < csTarget.GetLength(); i++) {
ch = csTarget.GetAt(i);
if (!((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9'))) {
csTarget.SetAt(i, _T('_'));
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Dumping .inf data support
//
CString MigApp::dump(void)
{
CString cs;
BOOL bInline;
INT i;
MigAttribute* pAttr;
// we can't do "inline" sections if we also have "ARGS"
bInline = (0 == m_rgArgs.GetSize());
cs = m_pSection->dump(m_csDescription.IsEmpty() ? NULL : (LPCTSTR)m_csDescription, NULL, FALSE, bInline);
if (m_csDescription.IsEmpty() && !bInline) {
cs += _T(",");
}
if (!bInline) {
for (i = 0; i < m_rgArgs.GetSize(); ++i) {
pAttr = (MigAttribute*)m_rgArgs.GetAt(i);
cs += (cs.IsEmpty()? _T(""): _T(", ")) + pAttr->dump();
}
}
return cs;
}
// we dump info into an array of strings, single-line entries are returned
// The first kind of return is "inline" --
// all the supplemental info is shoved into the rgOut
// for example, the return might be a reference to the section
// section's header and body are placed into rgOut
// ELIMINATE duplicate section names (reqfile!)
// optimize output - single "and" replaced with straight
// if a section is generated and placed as a single-line entry, promote the contents
// to upper level
CString MigSection::dump(LPCTSTR lpszDescription, int* pIndexContents, BOOL bNoHeader, BOOL bInline)
{
SdbArrayElement* p;
MigEntry* pEntry;
MigSection* pSection;
int indexContents = -1;
int nEntries;
const type_info& tiEntry = typeid(MigEntry); // cache type id info
const type_info& tiSection = typeid(MigSection);
int i;
CString cs; // inline return
CString csContents; // contents of supplemental section information
CString csSect;
CString csHeader;
CString csDescription(lpszDescription);
// place inline name and description
// we may need to enclose this into quotes
cs = m_csName;
if (!csDescription.IsEmpty()) {
if (csDescription.Left(1) == _T("%") &&
csDescription.Right(1) == _T("%")) {
cs += _T(", ") + csDescription;
} else {
cs += _T(", \"") + csDescription + _T("\"");
}
}
// if our section is a single-entry
// we dump this depending on the calling
// special case -- single file (and/or, matters not)
if (1 == m_rgEntries.GetSize() && m_bTopLevel && bInline) {
// this single line goes "inline" only if we are called from within
// other section
// dump the entry if it's an entry
p = (SdbArrayElement*)m_rgEntries.GetAt(0);
if (typeid(*p) == tiEntry) {
pEntry = (MigEntry*)p;
if (m_bTopLevel && csDescription.IsEmpty()) { // if the description was not added earlier and top-level...
cs += _T(",");
}
cs += _T(", ") + pEntry->dump();
return cs;
}
}
// first deal with sections...
switch(m_Operation) {
case MIGOP_OR:
// grab just one section in all if more than one entry
// IF we're the only entry -- but we need to have the right entry
//
if (!bNoHeader) { // ONLY valid for OR sections
csContents.Format(_T("[%s]\n"), (LPCTSTR)m_csName);
}
for (i = 0; i < m_rgEntries.GetSize(); ++i) {
p = (SdbArrayElement*)m_rgEntries.GetAt(i);
const type_info& tiPtr = typeid(*p);
if (tiPtr == tiEntry) {
pEntry = (MigEntry*)p;
csContents += pEntry->dump() + _T("\n");
}
else if (tiPtr == tiSection) {
pSection = (MigSection*)p;
csContents += pSection->dump() + _T("\n");
}
else {
// if we are here -- something is seriously wrong
// _tprintf(_T("Error - bad class information\n"));
MigThrowException(_T("Bad Entry detected in section \"%s\"\n"), (LPCTSTR)m_csName);
break;
}
}
break;
case MIGOP_AND:
// and for this entry ...
// optimization:
// if we're single-entry, retrieve the contents of the child section
// and put it right in
nEntries = m_rgEntries.GetSize();
for (i = 0; i < nEntries; ++i) {
p = (SdbArrayElement*)m_rgEntries.GetAt(i);
if (nEntries > 1) {
++m_nEntry;
csSect.Format(_T("[%s.%d]\n"), (LPCTSTR)m_csName, m_nEntry);
}
else {
csSect.Format(_T("[%s]\n"), (LPCTSTR)m_csName);
}
csContents += csSect;
const type_info& tiPtr = typeid(*p);
if (tiPtr == tiEntry) { // this is an entry, dump it into the section body
pEntry = (MigEntry*)p;
// numbered entry please...
csContents += pEntry->dump() + _T("\n");
}
else if (tiPtr == tiSection) { // this is a section, dump it, get the ref into the section body
pSection = (MigSection*)p;
// optimization:
if (pSection->m_Operation == MIGOP_OR) { // sub is an "OR" -- we need not have a ref
int index;
CString csSingle;
// dump all the entries right here
csSingle = pSection->dump(NULL, &index, TRUE);
if (index >= 0) {
csContents += m_pMigDB->m_rgOut.GetAt(index) + _T("\n");
m_pMigDB->m_rgOut.RemoveAt(index);
}
else {
csContents += csSingle;
}
}
else {
csContents += pSection->dump(NULL) + _T("\n");
}
}
else {
MigThrowException(_T("Internal Error: bad migration object\n"));
break;
}
}
break;
}
if (!csContents.IsEmpty()) {
indexContents = m_pMigDB->m_rgOut.Add(csContents);
}
if (NULL != pIndexContents) {
*pIndexContents = indexContents;
}
return cs;
}
CString MigEntry::FormatName(
VOID
)
{
INT i;
TCHAR ch;
BOOL bQuoteStr = FALSE;
CString csName;
bQuoteStr = (m_csName.GetLength() > 12); // 8.3 outright
for (i = 0; i < m_csName.GetLength() && !bQuoteStr; ++i) {
ch = m_csName.GetAt(i);
bQuoteStr = _istspace(ch) || (!_istalnum(ch) && _T('.') != ch);
}
if (!bQuoteStr) { // hmmm check filename and ext part
i = m_csName.Find(_T('.'));
if (i < 0) {
bQuoteStr = (m_csName.GetLength() > 8);
}
else {
// check for the second dot
bQuoteStr = (m_csName.Find(_T('.'), i+1) >= 0);
if (!bQuoteStr) {
// check for the ext length
bQuoteStr = (m_csName.Mid(i).GetLength() > 4); // with .abc
}
}
}
if (!bQuoteStr) {
return m_csName;
}
// else
csName.Format(_T("\"%s\""), m_csName);
return csName;
}
CString MigEntry::dump(void)
{
INT i;
MigAttribute* pAttr;
CString cs;
CString csName;
ULONG ulResult;
// _tprintf(_T("Entry: name=\"%s\"\n"), (LPCTSTR)m_csName);
// check whether we need to enclose this into quotes
// to do such a check we need to:
// check for non-ascii stuff...
// parser has put all the ARG attributes in the beginning of the array
// put any "arg" attributes before the exe name
for (i = 0; i < m_rgAttrs.GetSize(); ++i) {
pAttr = (MigAttribute*)m_rgAttrs.GetAt(i);
if (ARG != pAttr->m_type) {
break;
}
cs += (cs.IsEmpty()? _T(""): _T(", ")) + pAttr->dump();
}
cs += (cs.IsEmpty()? _T(""): _T(", ")) + FormatName();
for (;i < m_rgAttrs.GetSize(); ++i) {
pAttr = (MigAttribute*)m_rgAttrs.GetAt(i);
cs += (cs.IsEmpty()? _T(""): _T(", ")) + pAttr->dump();
}
return cs;
}
CString MigAttribute::dump(void)
{
CString cs;
CString csTemp;
switch(m_type) {
// note -- none of the attributes below are supported
case ISMSBINARY:
case ISWIN9XBINARY:
case INWINDIR:
case INCATDIR:
case INHLPDIR:
case INSYSDIR:
case INPROGRAMFILES:
case ISNOTSYSROOT:
case INROOTDIR:
case ISWIN98:
case HASVERSION:
case ATLEASTWIN98:
cs.Format(_T("%s%s"), m_bNot ? _T("!") : _T(""), (LPCTSTR)m_csName);
break;
case CHECKSUM:
case FILESIZE:
// under old code the following two values had been strings
case FILEDATEHI:
case FILEDATELO:
cs.Format(_T("%s%s(0x%.8lX)"), m_bNot?_T("!"):_T(""), (LPCTSTR)m_csName, m_dwValue);
break;
case BINFILEVER:
case BINPRODUCTVER:
case UPTOBINFILEVER:
case UPTOBINPRODUCTVER:
// version, ull
VersionQwordToString(csTemp, m_ullValue);
cs.Format(_T("%s%s(%s)"), m_bNot? _T("!"):_T(""), (LPCTSTR)m_csName, (LPCTSTR)csTemp);
break;
case EXETYPE:
// this is dword-encoded format that really is a string, convert
//
cs.Format(_T("%s%s(\"%s\")"), m_bNot ? _T("!") : _T(""), (LPCTSTR)m_csName, ModuleTypeIndicatorToStr(m_dwValue));
break;
// these two attributes are not supported either
case ARG:
case REQFILE:
if (m_pSection) {
m_pSection->dump();
}
// fall through
default:
cs.Format(_T("%s%s(\"%s\")"), m_bNot ? _T("!") : _T(""), (LPCTSTR)m_csName, (LPCTSTR)m_csValue);
break;
}
return cs;
}
/*++
Used to be a nice statistics-spewing function
VOID DumpMigDBStats(ShimDatabase* pDatabase)
{
POSITION pos = pDatabase->m_mapMigApp.GetStartPosition();
ShimArray* prgApp;
CString csSection;
DWORD dwApps = 0;
INT i;
Print( _T("Sections compiled: %d\n\n"), pDatabase->m_mapMigApp.GetCount());
while (pos) {
pDatabase->m_mapMigApp.GetNextAssoc(pos, csSection, (LPVOID&)prgApp);
Print(_T("Section [%36s]: %8ld apps\n"), (LPCTSTR)csSection, prgApp->GetSize());
dwApps += prgApp->GetSize();
}
Print( _T("--------\n"));
Print( _T("Total %38s: %8ld entries\n"), "", dwApps);
Print( _T("\n"));
if (gfVerbose) {
Print(_T("APPS\n"));
pos = pDatabase->m_mapMigApp.GetStartPosition();
while (pos) {
pDatabase->m_mapMigApp.GetNextAssoc(pos, csSection, (LPVOID&)prgApp);
Print(_T("Section [%36s]: %8ld apps\n"), (LPCTSTR)csSection, prgApp->GetSize());
Print(_T("-------------------------------------------------------------\n"));
for (i = 0; i < prgApp->GetSize(); ++i) {
MigApp* pApp = (MigApp*)prgApp->GetAt(i);
Print(_T("%s\n"), (LPCTSTR)pApp->m_csName);
}
Print(_T("\n"));
}
}
}
--*/
BOOL MigDatabase::DumpMigDBStrings(
LPCTSTR lpszFilename
)
{
CString csOut;
POSITION pos;
CANSITextFile OutFile(
lpszFilename,
m_pAppHelpDatabase->m_pCurrentMakefile->GetLangMap(m_pAppHelpDatabase->m_pCurrentOutputFile->m_csLangID)->m_dwCodePage,
CFile::modeCreate|CFile::modeReadWrite|CFile::shareDenyWrite);
CString csStringID;
CString csStringContent;
CString csCompoundString, csCompoundStringPart;
long nCursor = 0;
//
// write header (needed for postbuild!)
//
OutFile.WriteString(_T(";\n; AppCompat additions start here\n;\n; ___APPCOMPAT_MIG_ENTRIES___\n;\n"));
//
// write out the strings section
//
pos = m_mapStringsOut.GetStartPosition();
while (pos) {
m_mapStringsOut.GetNextAssoc(pos, csStringID, csStringContent);
if (csStringContent.GetLength() > MAX_INF_STRING_LENGTH) {
nCursor = 0;
csCompoundString.Empty();
while (nCursor * MAX_INF_STRING_LENGTH < csStringContent.GetLength()) {
csOut.Format(_T("%s.%d = \"%s\"\n"),
(LPCTSTR)csStringID,
nCursor + 1,
(LPCTSTR)csStringContent.Mid(nCursor * MAX_INF_STRING_LENGTH, MAX_INF_STRING_LENGTH));
OutFile.WriteString(csOut);
csCompoundStringPart.Format(_T(" %%%s.%d%%"), csStringID, nCursor + 1);
csCompoundString += csCompoundStringPart;
nCursor++;
}
} else {
csOut.Format(_T("%s = \"%s\"\n"), (LPCTSTR)csStringID, (LPCTSTR)csStringContent);
OutFile.WriteString(csOut);
}
}
return TRUE;
}
BOOL MigDatabase::DumpMigDBInf(
LPCTSTR lpszFilename
)
{
CString csSection;
CString csOut;
SdbArray<SdbArrayElement>* prgApp;
INT i;
MigApp* pApp;
BOOL bSuccess = FALSE;
POSITION pos;
CStringArray rgShowInSimplifiedView;
// clear out help array
m_rgOut.RemoveAll();
CANSITextFile OutFile(
lpszFilename,
m_pAppHelpDatabase->m_pCurrentMakefile->GetLangMap(m_pAppHelpDatabase->m_pCurrentOutputFile->m_csLangID)->m_dwCodePage,
CFile::modeCreate|CFile::modeReadWrite|CFile::shareDenyWrite);
//
// traverse sections...
//
pos = m_mapSections.GetStartPosition();
while (pos) {
m_mapSections.GetNextAssoc(pos, csSection, (LPVOID&)prgApp);
csOut.Format(_T("[%s]\n"), (LPCTSTR)csSection);
OutFile.WriteString(csOut);
for (i = 0; i < prgApp->GetSize(); ++i) {
pApp = (MigApp*)prgApp->GetAt(i);
csOut.Format(_T("%s\n"), pApp->dump());
if (pApp->m_bShowInSimplifiedView) {
rgShowInSimplifiedView.Add(csOut);
}
OutFile.WriteString(csOut);
}
csOut.Format(_T("\n"));
OutFile.WriteString(csOut);
}
//
// Dump ShowInSimplifiedView section
//
OutFile.WriteString(_T("[ShowInSimplifiedView]\n"));
for (i = 0; i < rgShowInSimplifiedView.GetSize(); i++) {
OutFile.WriteString(rgShowInSimplifiedView[i]);
}
OutFile.WriteString(_T("\n"));
for (i = 0; i < m_rgOut.GetSize(); ++i) {
OutFile.WriteString(m_rgOut.GetAt(i));
}
bSuccess = TRUE;
return bSuccess;
}
MigSection& MigSection::operator=(SdbMatchOperation& rMatchOp)
{
MigEntry* pEntry;
MigSection* pSection;
int i;
if (rMatchOp.m_Type == SDB_MATCH_ALL) {
m_Operation = MIGOP_AND;
} else if (rMatchOp.m_Type == SDB_MATCH_ANY) {
m_Operation = MIGOP_OR;
} else {
MigThrowException(_T("Bad matching operation\n"));
}
// now translate the content
for (i = 0; i < rMatchOp.m_rgMatchingFiles.GetSize(); ++i) {
SdbMatchingFile* pMatchingFile = (SdbMatchingFile*)rMatchOp.m_rgMatchingFiles.GetAt(i);
pEntry = new MigEntry(m_pMigDB);
if (pEntry == NULL) {
AfxThrowMemoryException();
}
*pEntry = *pMatchingFile;
// add the entry in
m_rgEntries.Add(pEntry, m_pDB);
}
for (i = 0; i < rMatchOp.m_rgSubMatchOps.GetSize(); ++i) {
SdbMatchOperation* pMatchOp = (SdbMatchOperation*)rMatchOp.m_rgSubMatchOps.GetAt(i);
pSection = new MigSection(m_pMigDB);
if (pSection == NULL) {
AfxThrowMemoryException();
}
//
// format section's name
//
pSection->m_csName.Format(_T("%s_%lx"), (LPCTSTR)m_csName, i);
*pSection = *pMatchOp;
//
// patch the name of the section
//
m_rgEntries.Add(pSection, m_pDB);
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Conversion code
//
MigApp& MigApp::operator=(
SdbWin9xMigration& rMig
)
{
INT i;
SdbMatchingFile* pMatchingFile;
MigEntry* pMigEntry;
CString csSectionName;
CString csID;
BOOL bSuccess;
CString csName;
if (rMig.m_pApp == NULL) {
MigThrowException(_T("Internal Compiler Error: Migration object should contain reference to the application"));
}
// name please
csName = m_pMigDB->GetAppTitle(&rMig);
m_csName = csName;
++m_pMigDB->m_dwExeCount;
//
// step one -- translate the general stuff
// we will probably need
m_pSection = new MigSection(m_pMigDB); //
if (m_pSection == NULL) {
AfxThrowMemoryException();
}
// our matching method is always AND (meaning all the files have to be present to produce a match
// it is set when constructing the section object
//
// m_csSection -- set here the section where this exe will go
// should the function below fail -- it will throw an exception
//
m_csSection = rMig.m_csSection; // copy the section over
//
// check whether we will have description
m_csDescription = m_pMigDB->FormatDescriptionStringID(&rMig);
//
// Set the section's level
//
m_pSection->m_bTopLevel = TRUE;
// the name of the section is the name of the app
m_pSection->m_csName = csName;
m_bShowInSimplifiedView = rMig.m_bShowInSimplifiedView;
//
// on to the assignment operation
//
*m_pSection = rMig.m_MatchOp; // simple assignment
return *this;
}
MigEntry& MigEntry::operator=(
SdbMatchingFile& rMatchingFile
)
{
INT i;
MigAttribute* pAttr;
//
// this name may be '*' denoting the main exe -- in this case the name will be corrected
// on the upper level, after this assignment operation completes
//
m_csName = rMatchingFile.m_csName;
// inherit the database ptr
m_pDB = rMatchingFile.m_pDB;
// roll through the attributes now
for (i = 0; i < sizeof(g_rgMigDBAttributes)/sizeof(g_rgMigDBAttributes[0]); ++i) {
if (!g_rgMigDBAttributes[i].XMLAttrType) {
continue;
}
// now check whether this attribute is present in matching file
if (!(rMatchingFile.m_dwMask & g_rgMigDBAttributes[i].XMLAttrType)) {
// attribute not present, keep on
continue;
}
// this attribute is present, encode it
pAttr = new MigAttribute(m_pMigDB);
if (pAttr == NULL) {
AfxThrowMemoryException();
}
pAttr->m_type = g_rgMigDBAttributes[i].MigAttrType;
pAttr->m_csName = g_rgMigDBAttributes[i].szOutputName ?
g_rgMigDBAttributes[i].szOutputName :
g_rgMigDBAttributes[i].szAttributeName;
switch(g_rgMigDBAttributes[i].XMLAttrType) {
case SDB_MATCHINGINFO_SIZE:
pAttr->m_dwValue = rMatchingFile.m_dwSize;
break;
case SDB_MATCHINGINFO_CHECKSUM:
pAttr->m_dwValue = rMatchingFile.m_dwChecksum;
break;
case SDB_MATCHINGINFO_COMPANY_NAME:
pAttr->m_csValue = rMatchingFile.m_csCompanyName;
break;
case SDB_MATCHINGINFO_PRODUCT_NAME:
pAttr->m_csValue = rMatchingFile.m_csProductName;
break;
case SDB_MATCHINGINFO_PRODUCT_VERSION:
pAttr->m_csValue = rMatchingFile.m_csProductVersion;
break;
case SDB_MATCHINGINFO_FILE_DESCRIPTION:
pAttr->m_csValue = rMatchingFile.m_csFileDescription;
break;
case SDB_MATCHINGINFO_BIN_FILE_VERSION:
pAttr->m_ullValue = rMatchingFile.m_ullBinFileVersion;
break;
case SDB_MATCHINGINFO_BIN_PRODUCT_VERSION:
pAttr->m_ullValue = rMatchingFile.m_ullBinProductVersion;
break;
case SDB_MATCHINGINFO_MODULE_TYPE:
pAttr->m_dwValue = rMatchingFile.m_dwModuleType;
break;
case SDB_MATCHINGINFO_VERFILEDATEHI:
pAttr->m_dwValue = rMatchingFile.m_dwFileDateMS;
break;
case SDB_MATCHINGINFO_VERFILEDATELO:
pAttr->m_dwValue = rMatchingFile.m_dwFileDateLS;
break;
case SDB_MATCHINGINFO_VERFILEOS:
pAttr->m_dwValue = rMatchingFile.m_dwFileOS;
break;
case SDB_MATCHINGINFO_VERFILETYPE:
pAttr->m_dwValue = rMatchingFile.m_dwFileType;
break;
case SDB_MATCHINGINFO_PE_CHECKSUM:
pAttr->m_ulValue = rMatchingFile.m_ulPECheckSum;
break;
case SDB_MATCHINGINFO_FILE_VERSION:
pAttr->m_csValue = rMatchingFile.m_csFileVersion;
break;
case SDB_MATCHINGINFO_ORIGINAL_FILENAME:
pAttr->m_csValue = rMatchingFile.m_csOriginalFileName;
break;
case SDB_MATCHINGINFO_INTERNAL_NAME:
pAttr->m_csValue = rMatchingFile.m_csInternalName;
break;
case SDB_MATCHINGINFO_LEGAL_COPYRIGHT:
pAttr->m_csValue = rMatchingFile.m_csLegalCopyright;
break;
case SDB_MATCHINGINFO_UPTO_BIN_PRODUCT_VERSION:
pAttr->m_ullValue = rMatchingFile.m_ullUpToBinProductVersion;
break;
case SDB_MATCHINGINFO_UPTO_BIN_FILE_VERSION:
pAttr->m_ullValue = rMatchingFile.m_ullUpToBinFileVersion;
break;
case SDB_MATCHINGINFO_16BIT_DESCRIPTION:
pAttr->m_csValue = rMatchingFile.m_cs16BitDescription;
break;
case SDB_MATCHINGINFO_REGISTRY_ENTRY:
pAttr->m_csValue = rMatchingFile.m_csRegistryEntry;
break;
//
// case SDB_MATCHINGINFO_PREVOSMAJORVERSION
// case SDB_MATCHINGINFO_PREVOSMINORVERSION
// case SDB_MATCHINGINFO_PREVOSPLATFORMID
// case SDB_MATCHINGINFO_PREVOSBUILDNO
// there is no such attribute. it will simply be ignored
//
}
m_rgAttrs.Add(pAttr, NULL);
}
return *this;
}
TCHAR g_szIncompatible[] = _T("Incompatible");
TCHAR g_szReinstall[] = _T("Reinstall");
CString MigDatabase::GetAppTitle(
SdbWin9xMigration* pAppMig
)
{
// part one -- get the application's title
BOOL bSuccess;
CString csID;
CString csAppTitle;
LPTSTR pBuffer = csID.GetBuffer(64); // a little more than you need for guid
if (pBuffer == NULL) {
AfxThrowMemoryException();
}
bSuccess = StringFromGUID(pBuffer, &pAppMig->m_ID);
csID.ReleaseBuffer();
if (!bSuccess) {
MigThrowException(_T("Failed trying to convert GUID to string for entry \"%s\"\n"),
(LPCTSTR)pAppMig->m_pApp->m_csName);
}
//
// name of this particular exe (we don't care for it -- it won't be reflected anywhere)
//
csAppTitle.Format(_T("%s_%s"), (LPCTSTR)pAppMig->m_pApp->m_csName, (LPCTSTR)csID);
csAppTitle.Remove(_T('{'));
csAppTitle.Remove(_T('}'));
// weed out the rest of non-alnum characters
FilterStringNonAlnum(csAppTitle);
return csAppTitle;
}
CString MigDatabase::GetDescriptionStringID(
SdbWin9xMigration* pAppMig
)
{
CString csDescriptionID;
// part one -- get the application's title
BOOL bSuccess;
CString csID;
CString csAppTitle;
if (pAppMig->m_csMessage.IsEmpty()) {
return csID; // empty string
}
LPTSTR pBuffer = csID.GetBuffer(64); // a little more than you need for guid
if (pBuffer == NULL) {
AfxThrowMemoryException();
}
bSuccess = StringFromGUID(pBuffer, &pAppMig->m_ID);
csID.ReleaseBuffer();
if (!bSuccess) {
MigThrowException(_T("Failed trying to convert GUID to string for entry \"%s\"\n"),
(LPCTSTR)pAppMig->m_pApp->m_csName);
}
//
// name of this particular exe (we don't care for it -- it won't be reflected anywhere)
//
csDescriptionID.Format(_T("__Message_%s_%s"), (LPCTSTR)pAppMig->m_csMessage, (LPCTSTR)csID);
csDescriptionID.Remove(_T('{'));
csDescriptionID.Remove(_T('}'));
// weed out the rest of non-alnum characters
FilterStringNonAlnum(csDescriptionID);
return csDescriptionID;
}
CString MigDatabase::FormatDescriptionStringID(
SdbWin9xMigration* pMigApp
)
{
CString csDescriptionID;
CString csRet;
CString csCompoundStringPart;
CString csStringContent;
long nCursor;
//
// get the string
// basis is the application's name
csDescriptionID = GetDescriptionStringID(pMigApp);
if (csDescriptionID.IsEmpty()) {
return csDescriptionID;
}
csStringContent = GetDescriptionString(pMigApp);
if (csStringContent.GetLength() > MAX_INF_STRING_LENGTH) {
nCursor = 0;
while (nCursor * MAX_INF_STRING_LENGTH < csStringContent.GetLength()) {
csCompoundStringPart.Format(_T("%%%s.%d%%"), csDescriptionID, nCursor + 1);
csRet += csCompoundStringPart;
nCursor++;
}
} else {
csRet.Format(_T("%%%s%%"), csDescriptionID);
}
//
// return id
//
return csRet;
}
CString MigDatabase::GetDescriptionString(
SdbWin9xMigration* pMigApp
)
{
CString csDescription;
SdbMessage* pMessage;
SdbDatabase* pMessageDB;
CString csDetails;
BOOL bSuccess;
//
// get apphelp database
//
pMessageDB = m_pMessageDatabase;
if (pMessageDB == NULL) {
MigThrowException(_T("Internal error: cannot produce description without apphelp database\n"));
}
if (pMigApp->m_csMessage.IsEmpty()) {
return csDescription;
}
//
// lookup this app in the apphelp db
//
pMessage = (SdbMessage *)pMessageDB->m_rgMessages.LookupName(pMigApp->m_csMessage, pMessageDB->m_pCurrentMakefile->m_csLangID);
if (pMessage == NULL) {
MigThrowException(_T("Exe \"%s\" has bad apphelp reference object\n"), (LPCTSTR)pMigApp->m_csMessage);
}
bSuccess = pMessageDB->ConstructMigrationMessage(pMigApp,
pMessage,
&csDetails);
if (!bSuccess) {
MigThrowException(_T("Failed to construct Migration message %s for \"%s\"\n"),
(LPCTSTR)pMigApp->m_pApp->m_csName, pMigApp->m_csMessage);
}
//
// 2. now that we have csDetails, flatten it
//
csDescription = FlattenString(csDetails);
return csDescription;
}
BOOL MigDatabase::AddApp(
MigApp* pApp
)
{
SdbArray<MigApp>* prgApp;
CString csSection;
csSection = pApp->m_csSection;
csSection.MakeUpper();
if (m_mapSections.Lookup(csSection, (LPVOID&)prgApp)) {
if (g_bStrict && NULL != prgApp->LookupName(pApp->m_csName)) {
//
// can't do that -- duplicate name
//
MigThrowException(_T("Duplicate application name found for app \"%s\"\n"), (LPCTSTR)pApp->m_csName);
}
prgApp->Add(pApp, m_pFixDatabase, FALSE);
} else {
prgApp = new SdbArray<MigApp>;
if (prgApp == NULL) {
AfxThrowMemoryException();
}
prgApp->Add(pApp, m_pFixDatabase, FALSE);
m_mapSections.SetAt(csSection, (LPVOID&)prgApp);
}
return TRUE;
}
BOOL MigDatabase::Populate(
VOID
)
{
//
// roll through all the outer objects (exes and generate migdb objects)
//
int i, iMig;
SdbExe* pExe;
MigApp* pMigApp;
SdbDatabase* pFixDatabase = m_pFixDatabase;
SdbApp* pApp;
SdbWin9xMigration* pMigration;
if (pFixDatabase == NULL) {
MigThrowException(_T("Cannot produce migdb entries without fix db\n"));
}
for (i = 0; i < pFixDatabase->m_rgApps.GetSize(); i++) {
//
// for each app check whether it has migration info
//
pApp = (SdbApp*)pFixDatabase->m_rgApps.GetAt(i);
for (iMig = 0; iMig < pApp->m_rgWin9xMigEntries.GetSize(); ++iMig) {
pMigration = (SdbWin9xMigration*)pApp->m_rgWin9xMigEntries.GetAt(iMig);
pMigApp = new MigApp(this);
if (pMigApp == NULL) {
AfxThrowMemoryException();
}
// we have a brand new migration object, assign it
*pMigApp = *pMigration;
// once that is done, pMigApp->m_csSection has the destination of it
// this function will throw an exception if an error occurs
AddApp(pMigApp);
}
}
return TRUE;
}
BOOL MigDatabase::PopulateStrings(
VOID
)
{
SdbWin9xMigration* pMigration;
SdbApp* pApp;
CString csDescriptionID;
CString csDescription;
CString csAppTitleID;
CString csAppTitle;
CString csTemp;
int i, iMig;
//
// get all the strings
//
for (i = 0; i < m_pAppHelpDatabase->m_rgApps.GetSize(); i++) {
//
// for each app check whether it has migration info
//
pApp = (SdbApp*)m_pAppHelpDatabase->m_rgApps.GetAt(i);
for (iMig = 0; iMig < pApp->m_rgWin9xMigEntries.GetSize(); ++iMig) {
pMigration = (SdbWin9xMigration*)pApp->m_rgWin9xMigEntries.GetAt(iMig);
//
// Set up title strings
//
csAppTitleID = GetAppTitle(pMigration);
csAppTitle = pMigration->m_pApp->GetLocalizedAppName();
if (m_mapStringsOut.Lookup(csAppTitleID, csTemp)) {
MigThrowException(_T("Duplicate String ID \"%s\" found for entry \"%s\"\n"),
csAppTitleID,
pMigration->m_pApp->m_csName);
}
m_mapStringsOut.SetAt(csAppTitleID, csAppTitle);
csDescription = GetDescriptionString(pMigration);
csDescriptionID = GetDescriptionStringID(pMigration);
if (csDescriptionID.IsEmpty()) { // we allow description to be empty
continue;
}
if (m_mapStringsOut.Lookup(csDescriptionID, csTemp)) {
MigThrowException(_T("Duplicate String ID \"%s\" found for entry \"%s\"\n"),
csDescriptionID,
pMigration->m_pApp->m_csName);
}
m_mapStringsOut.SetAt(csDescriptionID, csDescription);
}
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////
//
// Top-level function
//
// if supplied: pAppHelpDatabase and pFixDatabase ->> migapp.inx is produced
// pAppHelpDatabase and pMessageDatabas ->> migapp.txt is produced
//
BOOL WriteMigDBFile(
SdbDatabase* pFixDatabase, // may be NULL
SdbDatabase* pAppHelpDatabase, // always supplied
SdbDatabase* pMessageDatabase, // may be NULL
LPCTSTR lpszFileName // always supplied
)
{
MigDatabase* pMigDatabase = NULL;
BOOL bSuccess = FALSE;
// construct migdatabase object and populate it
try {
// construct
pMigDatabase = new MigDatabase;
if (pMigDatabase == NULL) {
AfxThrowMemoryException();
}
// init MigDatabase object
//
// [markder] Make them all the same so that
// we can process messages/fixes at the same
// time.
//
pMigDatabase->m_pFixDatabase = pAppHelpDatabase;
pMigDatabase->m_pAppHelpDatabase = pAppHelpDatabase;
pMigDatabase->m_pMessageDatabase = pAppHelpDatabase;
bSuccess = pMigDatabase->Populate();
if (!bSuccess) {
throw new CMigDBException(_T("Unknown error populating MIGDB additions."));
}
bSuccess = pMigDatabase->PopulateStrings();
if (!bSuccess) {
throw new CMigDBException(_T("Unknown error populating MIGDB additions."));
}
if (pFixDatabase != NULL) {
//
// produce migdb.inf
//
bSuccess = pMigDatabase->DumpMigDBInf(lpszFileName);
} else { // dumping the strings
bSuccess = pMigDatabase->DumpMigDBStrings(lpszFileName);
}
delete pMigDatabase;
//
// can only get here if we don't catch any exceptions
//
return bSuccess;
} catch(CMigDBException* pMigdbException) {
SDBERROR((LPCTSTR)pMigdbException->m_csError);
pMigdbException->Delete();
} catch(CFileException* pFileException) {
//
// a little more tricky
//
CString csError;
int nSize = 1024;
BOOL bError;
bError = pFileException->GetErrorMessage(csError.GetBuffer(nSize), nSize);
csError.ReleaseBuffer();
if (bError) {
SDBERROR((LPCTSTR)csError);
}
pFileException->Delete();
} catch(CMemoryException* pMemoryException) {
SDBERROR(_T("Memory Allocation Failure\n"));
pMemoryException->Delete();
}
return FALSE;
}