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.
 
 
 
 
 
 

1307 lines
34 KiB

//------------------------------------------------------------------------------
//
// File: impfile.cpp
// Copyright (C) 1995-1997 Microsoft Corporation
// All rights reserved.
//
// Purpose:
// Implementation of CLocImpFile, which provides the ILocFile interface for
// the parser.
//
// MAJOR IMPLEMENTATION FILE.
//
// Owner:
//
//------------------------------------------------------------------------------
#include "stdafx.h"
#include "dllvars.h"
#include "resource.h"
#include "impfile.h"
#include "impparse.h"
#include "xml_supp.h"
# define MAX_BUFFER 8192
// TODO: Format constants go here.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Constructor for CLocImpFile.
//------------------------------------------------------------------------------
CLocImpFile::CLocImpFile(
ILocParser *pParentClass) // Pointer to parent class, normally NULL.
{
//
// C.O.M. initialization
//
m_pParentClass = pParentClass;
m_ulRefCount = 0;
//
// IMP file initialization
//
m_pOpenSourceFile = NULL;
m_pReporter = NULL;
m_FileType = ftMNCFileType;
AddRef();
IncrementClassCount();
m_dwCountOfStringTables = 0;
m_pstmSourceString = NULL;
m_pstgSourceStringTable = NULL;
m_pstgSourceParent = NULL;
m_pstmTargetString = NULL;
m_pstgTargetStringTable = NULL;
m_pstgTargetParent = NULL;
m_bXMLBased = false;
// Format initialization.
// TODO: initialize implementation member variables here.
return;
} // end of CLocImpFile::CLocImpFile()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Destructor for CLocImpFile.
//------------------------------------------------------------------------------
CLocImpFile::~CLocImpFile()
{
DEBUGONLY(AssertValid());
if (m_pOpenSourceFile != NULL)
{
m_pOpenSourceFile->Close();
delete m_pOpenSourceFile;
}
DecrementClassCount();
// Format deinitialization.
// TODO: perform any implementation cleanup here.
return;
} // end of CLocImpFile::~CLocImpFile()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Increment the object reference count. Return the new reference count.
//------------------------------------------------------------------------------
ULONG
CLocImpFile::AddRef()
{
if (m_pParentClass != NULL)
{
m_pParentClass->AddRef();
}
return ++m_ulRefCount;
} // end of CLocImpFile::AddRef()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Decrement the object reference count. If it goes to 0, delete the object.
// Return the new reference count.
//------------------------------------------------------------------------------
ULONG
CLocImpFile::Release()
{
LTASSERT(m_ulRefCount != 0);
if (m_pParentClass != NULL)
{
m_pParentClass->Release();
}
m_ulRefCount--;
if (0 == m_ulRefCount)
{
delete this;
return 0;
}
return m_ulRefCount;
} // end of CLocImpFile::Release()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Query whether this object supports a given interface.
//
// Return values: some kind of result code
// ppvObj will point to this object if it supports the desired
// interface, be NULL if not.
//------------------------------------------------------------------------------
HRESULT
CLocImpFile::QueryInterface(
REFIID iid, // Desired interface.
LPVOID *ppvObj) // Return pointer to object with interface.
// Note that it's a hidden double pointer.
{
LTASSERT(ppvObj != NULL);
if (m_pParentClass != NULL)
{
return m_pParentClass->QueryInterface(iid, ppvObj);
}
else
{
SCODE scRetVal = E_NOINTERFACE;
*ppvObj = NULL;
if (IID_IUnknown == iid)
{
*ppvObj = (IUnknown *)this;
scRetVal = S_OK;
}
else if (IID_ILocFile == iid)
{
*ppvObj = (ILocFile *)this;
scRetVal = S_OK;
}
if (S_OK == scRetVal)
{
AddRef();
}
return ResultFromScode(scRetVal);
}
} // end of CLocImpFile::QueryInterface()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Check object for validity. Asserts if not! (debug only)
//------------------------------------------------------------------------------
void
CLocImpFile::AssertValidInterface()
const
{
AssertValid();
return;
} // end of CLocImpFile::AssertValidInterface()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Open the file and make sure it is the correct type. Return TRUE if it is,
// FALSE if not or on error.
//------------------------------------------------------------------------------
BOOL
CLocImpFile::OpenFile(
const CFileSpec &fsFileSpec, // Name of file to open.
CReporter &Reporter) // Reporter object for messages.
{
DEBUGONLY(fsFileSpec.AssertValid());
DEBUGONLY(Reporter.AssertValid());
const CPascalString &pstrFileName = fsFileSpec.GetFileName();
BOOL fRetVal = FALSE;
LTTRACEPOINT("OpenFile()");
// Set reporter pointer for the duration of this function.
m_pReporter = &Reporter;
try
{
CFileException excFile;
m_pstrFileName = pstrFileName; // Initialize source filename.
m_idFile = fsFileSpec.GetFileId();
if (m_pOpenSourceFile != NULL)
{
// If source file pointer seems to be open already, close it.
m_pOpenSourceFile->Close();
delete m_pOpenSourceFile;
m_pOpenSourceFile = NULL;
}
// Open the source file. Doesn't throw an exception if the open
// fails, but does return FALSE and put the info in an exception
// structure if you supply one.
m_pOpenSourceFile = new CLFile;
fRetVal = m_pOpenSourceFile->Open(m_pstrFileName,
CFile::modeRead | CFile::shareDenyNone, &excFile);
if (!fRetVal)
{
ReportException(&excFile);
m_pOpenSourceFile->Abort();
delete m_pOpenSourceFile;
m_pOpenSourceFile = NULL;
// fRetCode is already FALSE.
}
else
{
// Verify() assumes it is in a try/catch frame.
fRetVal = Verify();
}
}
catch(CException *e)
{
ReportException(e);
delete m_pOpenSourceFile;
m_pOpenSourceFile = NULL;
fRetVal = FALSE;
// m_pReporter will be NULLed by normal cleanup code below.
e->Delete();
}
catch(...)
{
// Reset the reporter pointer, no idea if it will still be valid by
// the time the destructor gets called. The only other thing that
// needs to be cleaned up is the source file, which will be handled in
// the destructor.
m_pReporter = NULL;
throw;
}
m_pReporter = NULL;
return fRetVal;
} // end of CLocImpFile::OpenFile()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Return the file type (a ft* constant from impfile.h). If you only have one
// file type, you can just return it directly.
//------------------------------------------------------------------------------
FileType
CLocImpFile::GetFileType()
const
{
return m_FileType;
} // end of CLocImpFile::GetFileType()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Return the file description in strDesc, according to the file type. If you
// have only one file type, you can just return a string directly.
//------------------------------------------------------------------------------
void
CLocImpFile::GetFileTypeDescription(
CLString &strDesc) // Place to return file description string.
const
{
LTVERIFY(strDesc.LoadString(g_hDll, IDS_IMP_FILE_DESC));
return;
} // end of CLocImpFile::GetFileTypeDescription()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Return the names of any associated files as a list of strings in lstFiles.
// Returns TRUE if there are any, FALSE if not.
//------------------------------------------------------------------------------
BOOL
CLocImpFile::GetAssociatedFiles(
CStringList &lstFiles) // Return associated file names here.
const
{
DEBUGONLY(lstFiles.AssertValid());
LTASSERT(lstFiles.GetCount() == 0);
// TODO: If your files have associated files, put them in lstFiles here.
UNREFERENCED_PARAMETER(lstFiles);
return FALSE;
} // end of CLocImpFile::GetAssociatedFiles()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Enumerate all the localizable items in this file. Returns TRUE on success,
// FALSE on error.
//------------------------------------------------------------------------------
BOOL
CLocImpFile::EnumerateFile(
CLocItemHandler &ihItemHandler, // Localizable-item handler and
// reporter object all in one!
const CLocLangId &lid, // Source language ID object.
const DBID &dbidFileId) // Database ID of file, used as parent
// for all top-level items in the
// file.
{
DEBUGONLY(ihItemHandler.AssertValid());
DEBUGONLY(lid.AssertValid());
DEBUGONLY(dbidFileId.AssertValid());
LTTRACEPOINT("EnumerateFile()");
// Set reporter pointer for the duration of this function.
m_pReporter = &ihItemHandler;
if (NULL == m_pOpenSourceFile)
{
// Source file isn't open, whoops.
LTASSERT(0 && "Source file isn't open in CLocImpFile::EnumerateFile()");
return FALSE;
}
// Retrieve and store the ANSI code page value. Note that some types
// of files use OEM code pages instead, or even use both. To get the
// OEM code page, do GetCodePage(cpDos) instead.
m_cpSource = lid.GetCodePage(cpAnsi);
BOOL bRet = TRUE;
try
{
bRet = EnumerateStrings(ihItemHandler,dbidFileId,FALSE);
}
catch(CException *e)
{
ReportException(e);
bRet = FALSE;
// m_pReporter will be NULLed by normal cleanup code below.
e->Delete();
}
catch (...)
{
// Reset the reporter pointer, no idea if it will still be valid by
// the time the destructor gets called. Reset the process pointer,
// since it definitely won't be valid! The only other thing that
// needs to be cleaned up is the source file, which will be handled in
// the destructor.
m_pReporter = NULL;
throw;
}
m_pReporter = NULL; // Reset reporter pointer.
return bRet;
} // end of CLocImpFile::EnumerateFile()
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Create a new target file be replacing resources in the source file with the
// localized items from Espresso.
//------------------------------------------------------------------------------
BOOL
CLocImpFile::GenerateFile(
const CPascalString &pstrTargetFile,// Name of target file.
CLocItemHandler &ihItemHandler, // Localizable-item handler and
// reporter object all in one!
const CLocLangId &lidSource, // Source language ID object.
const CLocLangId &lidTarget, // Target language ID object.
const DBID &dbidParent) // Database ID of file, used as
// parent for all top-level items
// in the file.
{
DEBUGONLY(pstrTargetFile.AssertValid());
DEBUGONLY(ihItemHandler.AssertValid());
DEBUGONLY(lidSource.AssertValid());
DEBUGONLY(lidTarget.AssertValid());
DEBUGONLY(dbidParent.AssertValid());
BOOL fRetVal = FALSE;
// Set reporter pointer for the duration of this function.
m_pReporter = &ihItemHandler;
if (NULL == m_pOpenSourceFile)
{
// Source file isn't open, whoops.
LTASSERT(0 && "Source file isn't open in CLocImpFile::GenerateFile()");
return FALSE;
}
// Retrieve and store the ANSI code page values for the source and target
// files. Note that some types of files use OEM code pages instead, or
// even use both. To get the OEM code page, do GetCodePage(cpDos) instead.
m_cpSource = lidSource.GetCodePage(cpAnsi);
m_cpTarget = lidTarget.GetCodePage(cpAnsi);
try
{
m_pstrTargetFile = pstrTargetFile; // Initialize target filename.
CFileStatus fsFileStatus;
CLFile::CopyFile(m_pstrFileName,m_pstrTargetFile,FALSE);
CLFile::GetStatus(m_pstrTargetFile, fsFileStatus);
if(fsFileStatus.m_attribute & CFile::readOnly)
{
fsFileStatus.m_attribute &= ~CFile::readOnly;
CLFile::SetStatus(m_pstrTargetFile, fsFileStatus);
}
fRetVal = EnumerateStrings(ihItemHandler,dbidParent,TRUE);
}
catch(CException *e)
{
ReportException(e, ImpEitherError);
fRetVal = FALSE;
// m_pReporter will be NULLed by normal cleanup code.
e->Delete();
}
catch(...)
{
// Generic exception handling is needed here because otherwise
// target file will not be cleaned up. Also, no idea if reporter
// pointer will still be valid by the time the destructor is
// called. The process pointer definitely won't be valid, so reset
// it too. The source file will be cleaned up by the destructor.
m_pReporter = NULL;
throw;
}
// Cleanup.
if (!fRetVal)
{
try
{
// Nuke the target file if the generate failed.
CLFile::Remove(pstrTargetFile);
}
catch(CException *e)
{
ReportException(e, ImpTargetError);
// fRetVal is already FALSE
// m_pReporter will be NULLed by normal cleanup code.
e->Delete();
}
catch(...)
{
// Generic exception handling is needed here because otherwise
// target file will not be cleaned up. Also, no idea if reporter
// pointer will still be valid by the time the destructor is
// called. The process pointer is already NULL. The source file
// will be cleaned up by the destructor.
m_pReporter = NULL;
throw;
}
}
// Normal cleanup code.
m_pReporter = NULL; // Reset reporter pointer.
return fRetVal;
} // end of CLocImpFile::GenerateFile()
//------------------------------------------------------------------------------
//
// TODO:
// Verify that a file is a ???, as best we can. When we're reasonably sure,
// set the reporter confidence level to high -- until then, messages will be
// discarded, not displayed. This is also the place where m_FileType is set.
//
// Returns TRUE if so, FALSE if not or on error, or throws an exception.
//
// Normally there is need to catch exceptions in this function, they will
// be caught and handled by a higher level. To avoid memory leaks, consider
// using automatic variables or CByteArrays (as described and demonstrated in
// the utility function FindSignature() below) instead of dynamic allocation.
//------------------------------------------------------------------------------
BOOL
CLocImpFile::Verify()
{
DEBUGONLY(AssertValid());
LTASSERT(m_pReporter != NULL);
DEBUGONLY(m_pReporter->AssertValid());
// ...
// Set confidence level to high and return that we recognize this file.
m_pReporter->SetConfidenceLevel(CReporter::High);
return TRUE;
} // end of CLocImpFile::Verify()
//------------------------------------------------------------------------------
//
// Reports the exception described by *pException. Since the message can be
// retrieved directly from the exception, there is no need (as far as reporting
// goes) to catch or handle different kinds of exceptions separately. Normally,
// there is no reason for your code to call this function, since under normal
// circumstances you don't have to catch exceptions.
//
// THIS FUNCTION IS USED BY THE FRAMEWORK! DO NOT REMOVE IT!
//------------------------------------------------------------------------------
void
CLocImpFile::ReportException(
CException *pException, // Exception to be reported.
ImpFileError WhichFile) // Defaults to ImpSourceError (most common).
const
{
const UINT MAX_MESSAGE = 256;
CLString strContext;
CLString strMessage;
char *pszMessage;
LTASSERT(m_pReporter != NULL);
DEBUGONLY(m_pReporter->AssertValid());
pszMessage = strMessage.GetBuffer(MAX_MESSAGE);
LTASSERT(pszMessage != NULL);
pException->GetErrorMessage(pszMessage, MAX_MESSAGE);
strMessage.ReleaseBuffer();
switch (WhichFile)
{
case ImpNeitherError: // By convention, report errors not really in any
// file against the source file.
case ImpSourceError:
m_pstrFileName.ConvertToCLString(strContext, CP_ACP);
break;
case ImpTargetError:
m_pstrTargetFile.ConvertToCLString(strContext, CP_ACP);
break;
case ImpEitherError:
{
CLString strSource, strTarget;
m_pstrFileName.ConvertToCLString(strSource, CP_ACP);
m_pstrTargetFile.ConvertToCLString(strTarget, CP_ACP);
strContext.Format(g_hDll, IDS_IMP_OR, (const char *) strSource,
(const char *) strTarget);
}
break;
default:
LTASSERT(0 && "WhichFile is bad during CLocImpFile::ReportException");
break;
}
CContext ctx(strContext, m_idFile, otFile, vProjWindow);
m_pReporter->IssueMessage(esError, ctx, strMessage);
return;
} // end of CLocImpFile::ReportException()
//------------------------------------------------------------------------------
//
// Reports a message to the user. Note that the message will be discarded
// unless the reporter's confidence level had been set high (see Verify()).
//------------------------------------------------------------------------------
void
CLocImpFile::ReportMessage(
MessageSeverity sev, // Severity of message.
// (esError, esWarning, esNote)
UINT nMsgId, // ID of string resource to load for message.
ImpFileError WhichFile) // Defaults to ImpSourceError (most common).
const
{
CLString strContext;
LTASSERT(m_pReporter != NULL);
DEBUGONLY(m_pReporter->AssertValid());
switch (WhichFile)
{
case ImpNeitherError: // By convention, report errors not really in any
// file against the source file.
case ImpSourceError:
m_pstrFileName.ConvertToCLString(strContext, CP_ACP);
break;
case ImpTargetError:
m_pstrTargetFile.ConvertToCLString(strContext, CP_ACP);
break;
case ImpEitherError:
{
CLString strSource, strTarget;
m_pstrFileName.ConvertToCLString(strSource, CP_ACP);
m_pstrTargetFile.ConvertToCLString(strTarget, CP_ACP);
strContext.Format(g_hDll, IDS_IMP_OR, (const char *) strSource,
(const char *) strTarget);
}
break;
default:
LTASSERT(0 && "WhichFile is bad during CLocImpFile::ReportMessage");
break;
}
CContext ctx(strContext, m_idFile, otFile, vProjWindow);
m_pReporter->IssueMessage(sev, ctx, g_hDll, nMsgId);
return;
} // end of CLocImpFile::ReportMessage()
#ifdef LTASSERT_ACTIVE
//------------------------------------------------------------------------------
//
// Asserts if the object is not valid. Any functions you add should probably
// call this function (in DEBUGONLY()) first thing -- see Verify() and Enum().
//------------------------------------------------------------------------------
void
CLocImpFile::AssertValid()
const
{
// Check base class.
CLObject::AssertValid();
// Check C.O.M. data. m_pParentClass should always be NULL.
// Correct range for m_ulRefCount is unknown, but make sure it hasn't
// wrapped around by checking for less than 100 (if we ever exceed
// 100 references from below, there's probably something wrong too!).
LTASSERT(NULL == m_pParentClass);
LTASSERT(m_ulRefCount < 100);
// Check filename strings.
m_pstrFileName.AssertValid();
m_pstrTargetFile.AssertValid();
// If the file object pointers are non-NULL, check the objects.
if (m_pOpenSourceFile != NULL)
{
m_pOpenSourceFile->AssertValid();
}
// If the reporter pointer is non-NULL, check the object.
if (m_pReporter != NULL)
{
m_pReporter->AssertValid();
}
// If the process object pointer is non-NULL, check the object.
// Make sure m_FileType is one of the valid types.
switch (m_FileType)
{
case ftMNCFileType:
case ftUnknown:
// TODO: add cases for all ft* constants in impfile.h here.
// case ftFoo1FileType:
// case ftFoo2FileType:
// These are all OK. Do nothing.
break;
default:
// This is bad!
LTASSERT(0 && "m_FileType is bad during CLocImpFile::AssertValid()");
}
// Can't check code page values, they could be just about anything
// and still valid.
// TODO: check any checkable implementation member variables here.
return;
} // end of CLocImpFile::AssertValid()
#endif // _DEBUG
//Creating a parent node
//ihItemHandler -> Required to send item
//dbidFileId -> Id of the parent of node
//pNewParentId -> New Id will be assigned can be used if this node has
// child
//szNodeRes -> Res ID of the node
//szNodeString -> String of the node
// <- Returns success or failure
BOOL CLocImpFile::CreateParentNode(CLocItemHandler & ihItemHandler,
const DBID & dbidFileId,
DBID & pNewParentId,
const char * szNodeRes,
const char * szNodeString)
{
BOOL fRetVal = TRUE;
CLocItemSet isItemSet;
CLocUniqueId uid;
CPascalString pstrText,pstrId;
try
{
CLocItem *pLocItem = new CLocItem();
pstrId.SetString(szNodeRes,strlen(szNodeRes),m_cpSource);
uid.GetResId().SetId(pstrId);
pstrText.SetString(szNodeString,strlen(szNodeString),m_cpSource);
uid.GetTypeId().SetId(pstrText);
uid.SetParentId(dbidFileId);
//set up pLocItem
pLocItem->SetUniqueId(uid);
pLocItem->SetFDisplayable(TRUE);
pLocItem->SetFExpandable(TRUE);
pLocItem->SetFNoResTable(TRUE);
pLocItem->SetIconType(CIT::Expandable);
//Add the node to Item set
isItemSet.Add(pLocItem);
//Send node to espresso
fRetVal = ihItemHandler.HandleItemSet(isItemSet);
// If OK, retrieve DBID.
if (fRetVal)
{
pNewParentId.Clear();
pNewParentId = pLocItem->GetMyDatabaseId();
}
isItemSet.ClearItemSet();
}
catch (CMemoryException *pMemoryException)
{
CLString strContext;
strContext.LoadString(g_hDll, IDS_MNC_GENERIC_LOCATION);
m_pReporter->IssueMessage(esError, strContext, g_hDll, IDS_MNC_NO_MEMORY,
g_locNull);
fRetVal = FALSE;
pMemoryException->Delete();
}
catch(CException *pException)
{
ReportException(pException);
pException->Delete();
fRetVal = FALSE;
}
return fRetVal;
}
//Creating a child node
//ihItemHandler -> Required to send item
//dbidFileId -> Id of the parent of node
//pNewParentId -> New Id to be use for items belonging to this child
//szNodeRes -> Res ID of the node
//szNodeString -> String of the node
// <- Returns success or failure
BOOL CLocImpFile::CreateChildNode(CLocItemHandler & ihItemHandler,
const DBID & dbidFileId,
DBID & pNewParentId,
const char * szNodeRes,
const char * szNodeString)
{
BOOL fRetVal = TRUE;
CLocItemSet isItemSet;
CLocUniqueId uid;
CPascalString pstrText,pstrId;
try
{
CLocItem *pLocItem = new CLocItem();
pstrId.SetString(szNodeRes,strlen(szNodeRes),m_cpSource);
pstrText.SetString(szNodeString,strlen(szNodeString),m_cpSource);
uid.GetResId().SetId(pstrId);
uid.GetTypeId().SetId(pstrText);
uid.SetParentId(dbidFileId);
//set up pLocItem
pLocItem->SetUniqueId(uid);
pLocItem->SetFDisplayable(TRUE);
pLocItem->SetFExpandable(FALSE);
pLocItem->SetFNoResTable(TRUE);
pLocItem->SetIconType(CIT::String);
//Add the node to Item set
isItemSet.Add(pLocItem);
//Send node to espresso
fRetVal = ihItemHandler.HandleItemSet(isItemSet);
// If OK, retrieve DBID.
if (fRetVal)
{
pNewParentId.Clear();
pNewParentId = pLocItem->GetMyDatabaseId();
}
isItemSet.ClearItemSet();
}
catch (CMemoryException *pMemoryException)
{
CLString strContext;
strContext.LoadString(g_hDll, IDS_MNC_GENERIC_LOCATION);
m_pReporter->IssueMessage(esError, strContext, g_hDll, IDS_MNC_NO_MEMORY,
g_locNull);
fRetVal = FALSE;
pMemoryException->Delete();
}
catch(CException *pException)
{
ReportException(pException);
pException->Delete();
fRetVal = FALSE;
}
return fRetVal;
}
BOOL CLocImpFile::EnumerateStrings(CLocItemHandler & ihItemHandler,
const DBID & dbidFileId,
BOOL fGenerating)
{
BOOL fRetVal = TRUE;
try
{
fRetVal = OpenStream(FALSE);
if(!fRetVal)
goto exit_clean;
if(fGenerating)
fRetVal = OpenStream(TRUE);
if(!fRetVal)
goto exit_clean;
if (m_bXMLBased)
fRetVal = ProcessXMLStrings(ihItemHandler,dbidFileId,fGenerating);
else
fRetVal = ProcessStrings(ihItemHandler,dbidFileId,fGenerating);
}
catch(CException *pException)
{
ReportException(pException);
pException->Delete();
fRetVal = FALSE;
}
exit_clean:
if(m_pstmSourceString)
m_pstmSourceString->Release();
if(m_pstgSourceStringTable)
m_pstgSourceStringTable->Release();
if(m_pstgSourceParent)
m_pstgSourceParent->Release();
if(fGenerating)
{
if(m_pstmTargetString)
m_pstmTargetString->Release();
if(m_pstgTargetStringTable)
m_pstgTargetStringTable->Release();
if(m_pstgTargetParent)
m_pstgTargetParent->Release();
}
return fRetVal;
}
BOOL CLocImpFile::ProcessStrings(CLocItemHandler & ihItemHandler,
const DBID & dbidFileId,
BOOL fGenerating)
{
DBID dbidParentId,dbidNodeId;
BOOL fRetVal = TRUE;
BOOL bUseBraces = ::IsConfiguredToUseBracesForStringTables();
fRetVal = CreateParentNode(ihItemHandler,dbidFileId,dbidParentId,"String Table","String Table");
for(DWORD i=0; i < m_dwCountOfStringTables;i++)
{
ULONG dwBytesRead;
OLECHAR FAR* psz;
char szTemp[MAX_BUFFER];
CLocItemSet lsItemSet;
int nLength = 0;
dbidNodeId.Clear();
m_pstmSourceString->Read(&m_clsidSnapIn,sizeof(CLSID),&dwBytesRead);
StringFromCLSID(m_clsidSnapIn,&psz);
wcstombs(szTemp,psz,MAX_BUFFER);
nLength = strlen(szTemp);
LTASSERT((szTemp[0] == '{') && (szTemp[nLength - 1] == '}'));
// strip braces if configured so
CString strGUID(szTemp);
if ( !bUseBraces && strGUID[0] == _T('{') && strGUID[strGUID.GetLength() - 1] == _T('}'))
strGUID = strGUID.Mid(1, strGUID.GetLength() - 2);
fRetVal = CreateChildNode(ihItemHandler,dbidParentId,dbidNodeId,strGUID,strGUID);
m_pstmSourceString->Read(&m_dwCountOfStrings,sizeof(DWORD),&dwBytesRead);
if(fGenerating)
{
HRESULT hr;
DWORD dwBytesWritten;
hr = m_pstmTargetString->Write(&m_clsidSnapIn,sizeof(CLSID),&dwBytesWritten);
hr = m_pstmTargetString->Write(&m_dwCountOfStrings,sizeof(DWORD),&dwBytesWritten);
}
for(DWORD j = 0;j < m_dwCountOfStrings;j++)
{
DWORD dwCharCount;
m_pstmSourceString->Read(&m_dwID,sizeof(DWORD),&dwBytesRead);
m_pstmSourceString->Read(&m_dwRefCount,sizeof(DWORD),&dwBytesRead);
m_pstmSourceString->Read(&dwCharCount,sizeof(DWORD),&dwBytesRead);
WCHAR *pString;
pString = new WCHAR[dwCharCount + 1];
m_pstmSourceString->Read(pString,dwCharCount * 2,&dwBytesRead);
pString[dwCharCount] = L'\0';
int nSize = WideCharToMultiByte(m_cpSource,0,pString,dwCharCount,szTemp,dwCharCount*2,NULL,NULL);
szTemp[nSize] = '\0';
AddItemToSet(lsItemSet,dbidNodeId,m_dwID,szTemp);
delete []pString;
if(!fGenerating)
fRetVal = ihItemHandler.HandleItemSet(lsItemSet);
else
fRetVal = GenerateStrings(ihItemHandler,lsItemSet);
lsItemSet.ClearItemSet();
}
}
return fRetVal;
}
BOOL CLocImpFile::ProcessXMLStrings(CLocItemHandler & ihItemHandler,
const DBID & dbidFileId,
BOOL fGenerating)
{
DBID dbidParentId,dbidNodeId;
BOOL bOK = TRUE;
BOOL bUseBraces = ::IsConfiguredToUseBracesForStringTables();
// check if we have a table
if (m_spStringTablesNode == NULL)
return FALSE;
// create node
bOK = CreateParentNode(ihItemHandler, dbidFileId, dbidParentId, "String Table", "String Table");
if (!bOK)
return bOK;
// read the strings from XML document
CStringTableMap mapStringTables;
HRESULT hr = ReadXMLStringTables(m_spStringTablesNode, mapStringTables);
if (FAILED(hr))
return FALSE;
// iterate thru read data
CStringTableMap::iterator it;
for (it = mapStringTables.begin(); it != mapStringTables.end(); ++it)
{
std::wstring wstrGUID = it->first;
const CStringMap& rStrings = it->second;
dbidNodeId.Clear();
// convert 2 ansi
CString strGUID;
wcstombs(strGUID.GetBuffer(wstrGUID.length()), wstrGUID.c_str(), wstrGUID.length());
strGUID.ReleaseBuffer();
// strip braces if configured so
if ( !bUseBraces && strGUID[0] == _T('{') && strGUID[strGUID.GetLength() - 1] == _T('}'))
strGUID = strGUID.Mid(1, strGUID.GetLength() - 2);
bOK = CreateChildNode(ihItemHandler, dbidParentId, dbidNodeId, strGUID, strGUID);
if (!bOK)
return bOK;
// handle the strings in map
CStringMap::iterator its;
for (its = rStrings.begin(); its != rStrings.end(); ++its)
{
DWORD dwID = its->first;
std::wstring text = its->second;
DWORD dwCharCount = text.length();
CString strText;
char *pBuffer = strText.GetBuffer(dwCharCount*2);
if (pBuffer == NULL)
return FALSE;
int nSize = WideCharToMultiByte(m_cpSource, 0, text.c_str(), dwCharCount,
pBuffer, dwCharCount*2, NULL, NULL);
pBuffer[nSize] = '\0';
strText.ReleaseBuffer();
// use/update the string
CLocItemSet lsItemSet;
AddItemToSet(lsItemSet, dbidNodeId, dwID, strText);
bOK = ihItemHandler.HandleItemSet(lsItemSet);
if (!bOK)
return bOK;
if(fGenerating)
{
CLocItem *pLocItem = lsItemSet.GetAt(0);
if (!pLocItem)
return FALSE;
std::wstring strNewVal = pLocItem->GetLocString().GetString();
hr = UpdateXMLString(m_spTargetStringTablesNode, wstrGUID, dwID, strNewVal);
CString strMsg = strGUID;
if (FAILED(hr))
return FALSE;
}
lsItemSet.ClearItemSet();
if (!bOK)
return bOK;
}
}
// save XML document to the file
if (fGenerating)
{
hr = SaveXMLContents(m_pstrTargetFile, m_spTargetStringTablesNode);
if (FAILED(hr))
return FALSE;
}
return TRUE;
}
BOOL CLocImpFile::AddItemToSet(CLocItemSet & isItemSet,
const DBID &dbidNodeId,
DWORD dwID,
LPCSTR szText)
{
BOOL fRetVal = TRUE;
CPascalString pstrText;
CLocUniqueId uid;
ULONG lItemType = 1;
try
{
CLocItem * pNewItem = new CLocItem;
pstrText.SetString(szText,strlen(szText),m_cpSource);
uid.GetResId().SetId(dwID);
uid.GetTypeId().SetId(lItemType);
uid.SetParentId(dbidNodeId);
pNewItem->SetUniqueId(uid);
CLocString lsString;
pNewItem->SetIconType(CIT::String);
lsString.SetString(pstrText);
pNewItem->SetFDevLock(FALSE);
pNewItem->SetFUsrLock(FALSE);
pNewItem->SetFExpandable(FALSE);
pNewItem->SetFDisplayable(FALSE);
pNewItem->SetFNoResTable(FALSE);
lsString.SetCodePageType(cpAnsi);
lsString.SetStringType(CST::Text);
pNewItem->SetLocString(lsString);
isItemSet.Add(pNewItem);
fRetVal = TRUE;
}
catch (CMemoryException *pMemoryException)
{
CLString strContext;
strContext.LoadString(g_hDll, IDS_MNC_GENERIC_LOCATION);
m_pReporter->IssueMessage(esError, strContext, g_hDll, IDS_MNC_NO_MEMORY,
g_locNull);
fRetVal = FALSE;
pMemoryException->Delete();
}
catch(CException *pException)
{
ReportException(pException);
pException->Delete();
fRetVal = FALSE;
}
return fRetVal;
}
BOOL CLocImpFile::OpenStream(BOOL fGenerating)
{
BOOL fRetVal = TRUE;
HRESULT hr;
if(!fGenerating)
{
hr = StgOpenStorage(m_pstrFileName,NULL,STGM_TRANSACTED | STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&m_pstgSourceParent);
if(!FAILED(hr))
{
CPascalString pstrStorage,pstrStream;
pstrStorage.SetString("String Table",strlen("String Table"),cpAnsi);
pstrStream.SetString("Strings",strlen("Strings"),cpAnsi);
hr = m_pstgSourceParent->OpenStorage(pstrStorage,NULL,STGM_READ | STGM_SHARE_EXCLUSIVE,NULL,0,&m_pstgSourceStringTable);
if(!FAILED(hr))
{
HRESULT hr = m_pstgSourceStringTable->OpenStream(pstrStream,0,STGM_READ | STGM_SHARE_EXCLUSIVE,0,&m_pstmSourceString);
if(!FAILED(hr))
{
DWORD dwBytesRead;
m_pstmSourceString->Read(&m_dwCountOfStringTables,sizeof(DWORD),&dwBytesRead);
}
else
fRetVal = FALSE;
}
else
{
fRetVal = FALSE;
}
}
else
{
// try to open this as XML document
m_spStringTablesNode.Release(); // release the old one (if such exist)
hr = OpenXMLStringTable(m_pstrFileName, &m_spStringTablesNode);
if (SUCCEEDED(hr))
m_bXMLBased = true;
if (FAILED(hr))
{
CLString strMessage, strFilePath;
m_pstrFileName.ConvertToCLString(strFilePath, CP_ACP);
strMessage.Format(g_hDll, IDS_MSC_ERR_OPENSTORAGE, strFilePath);
LTASSERT(m_pReporter != NULL);
m_pReporter->IssueMessage(esError, CLString(g_hDll, IDS_MNC_GENERIC_LOCATION),strMessage);
fRetVal = FALSE;
}
}
}
else if (!m_bXMLBased)
{
hr = StgOpenStorage(m_pstrTargetFile,NULL,STGM_READWRITE | STGM_SHARE_EXCLUSIVE,NULL,0,&m_pstgTargetParent);
if(!FAILED(hr))
{
CPascalString pstrStorage,pstrStream;
pstrStorage.SetString("String Table",strlen("String Table"),cpAnsi);
pstrStream.SetString("Strings",strlen("Strings"),cpAnsi);
hr = m_pstgTargetParent->OpenStorage(pstrStorage,NULL,STGM_READWRITE | STGM_SHARE_EXCLUSIVE ,NULL,0,&m_pstgTargetStringTable);
if(!FAILED(hr))
{
HRESULT hr = m_pstgTargetStringTable->CreateStream(pstrStream, STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,0,0,&m_pstmTargetString);
if(!FAILED(hr))
{
DWORD dwBytesRead;
hr = m_pstmTargetString->Write(&m_dwCountOfStringTables,sizeof(DWORD),&dwBytesRead);
}
else
fRetVal = FALSE;
}
else
fRetVal = FALSE;
}
else
fRetVal = FALSE;
}
else
{
// try to open this as XML document
m_spTargetStringTablesNode.Release(); // release the old one (if such exist)
hr = OpenXMLStringTable(m_pstrTargetFile, &m_spTargetStringTablesNode);
if (FAILED(hr))
fRetVal = FALSE;
}
return fRetVal;
}
BOOL CLocImpFile::GenerateStrings(CLocItemHandler & ihItemHandler,
CLocItemSet & isItemSet)
{
BOOL fRetVal = TRUE;
INT iNoOfElements = 0;
DWORD dwBytesWritten,dwCharCount;
WCHAR *pLocText;
HRESULT hr;
try
{
if(ihItemHandler.HandleItemSet(isItemSet))
{
while(iNoOfElements < isItemSet.GetSize())
{
CLocItem *pLocItem;
CPascalString pstrText;
pLocItem = isItemSet.GetAt(iNoOfElements);
hr = m_pstmTargetString->Write(&m_dwID,sizeof(DWORD),&dwBytesWritten);
hr = m_pstmTargetString->Write(&m_dwRefCount,sizeof(DWORD),&dwBytesWritten);
pstrText = pLocItem->GetLocString().GetString();
dwCharCount = pstrText.GetStringLength();
hr = m_pstmTargetString->Write(&dwCharCount,sizeof(DWORD),&dwBytesWritten);
pLocText = pstrText.GetStringPointer();
hr = m_pstmTargetString->Write(pLocText,dwCharCount * 2,&dwBytesWritten);
pstrText.ReleaseStringPointer();
iNoOfElements++;
}
}
}
catch(CException *pException)
{
ReportException(pException);
pException->Delete();
fRetVal = FALSE;
}
return fRetVal;
}