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
39 KiB
1401 lines
39 KiB
//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;
|
|
|
|
}
|
|
|
|
|
|
|