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

  1. //------------------------------------------------------------------------------
  2. //
  3. // File: impfile.cpp
  4. // Copyright (C) 1995-1997 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // Purpose:
  8. // Implementation of CLocImpFile, which provides the ILocFile interface for
  9. // the parser.
  10. //
  11. // MAJOR IMPLEMENTATION FILE.
  12. //
  13. // Owner:
  14. //
  15. //------------------------------------------------------------------------------
  16. #include "stdafx.h"
  17. #include "dllvars.h"
  18. #include "resource.h"
  19. #include "impfile.h"
  20. #include "impparse.h"
  21. #include "xml_supp.h"
  22. # define MAX_BUFFER 8192
  23. // TODO: Format constants go here.
  24. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  25. //
  26. // Constructor for CLocImpFile.
  27. //------------------------------------------------------------------------------
  28. CLocImpFile::CLocImpFile(
  29. ILocParser *pParentClass) // Pointer to parent class, normally NULL.
  30. {
  31. //
  32. // C.O.M. initialization
  33. //
  34. m_pParentClass = pParentClass;
  35. m_ulRefCount = 0;
  36. //
  37. // IMP file initialization
  38. //
  39. m_pOpenSourceFile = NULL;
  40. m_pReporter = NULL;
  41. m_FileType = ftMNCFileType;
  42. AddRef();
  43. IncrementClassCount();
  44. m_dwCountOfStringTables = 0;
  45. m_pstmSourceString = NULL;
  46. m_pstgSourceStringTable = NULL;
  47. m_pstgSourceParent = NULL;
  48. m_pstmTargetString = NULL;
  49. m_pstgTargetStringTable = NULL;
  50. m_pstgTargetParent = NULL;
  51. m_bXMLBased = false;
  52. // Format initialization.
  53. // TODO: initialize implementation member variables here.
  54. return;
  55. } // end of CLocImpFile::CLocImpFile()
  56. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  57. //
  58. // Destructor for CLocImpFile.
  59. //------------------------------------------------------------------------------
  60. CLocImpFile::~CLocImpFile()
  61. {
  62. DEBUGONLY(AssertValid());
  63. if (m_pOpenSourceFile != NULL)
  64. {
  65. m_pOpenSourceFile->Close();
  66. delete m_pOpenSourceFile;
  67. }
  68. DecrementClassCount();
  69. // Format deinitialization.
  70. // TODO: perform any implementation cleanup here.
  71. return;
  72. } // end of CLocImpFile::~CLocImpFile()
  73. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  74. //
  75. // Increment the object reference count. Return the new reference count.
  76. //------------------------------------------------------------------------------
  77. ULONG
  78. CLocImpFile::AddRef()
  79. {
  80. if (m_pParentClass != NULL)
  81. {
  82. m_pParentClass->AddRef();
  83. }
  84. return ++m_ulRefCount;
  85. } // end of CLocImpFile::AddRef()
  86. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  87. //
  88. // Decrement the object reference count. If it goes to 0, delete the object.
  89. // Return the new reference count.
  90. //------------------------------------------------------------------------------
  91. ULONG
  92. CLocImpFile::Release()
  93. {
  94. LTASSERT(m_ulRefCount != 0);
  95. if (m_pParentClass != NULL)
  96. {
  97. m_pParentClass->Release();
  98. }
  99. m_ulRefCount--;
  100. if (0 == m_ulRefCount)
  101. {
  102. delete this;
  103. return 0;
  104. }
  105. return m_ulRefCount;
  106. } // end of CLocImpFile::Release()
  107. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  108. //
  109. // Query whether this object supports a given interface.
  110. //
  111. // Return values: some kind of result code
  112. // ppvObj will point to this object if it supports the desired
  113. // interface, be NULL if not.
  114. //------------------------------------------------------------------------------
  115. HRESULT
  116. CLocImpFile::QueryInterface(
  117. REFIID iid, // Desired interface.
  118. LPVOID *ppvObj) // Return pointer to object with interface.
  119. // Note that it's a hidden double pointer.
  120. {
  121. LTASSERT(ppvObj != NULL);
  122. if (m_pParentClass != NULL)
  123. {
  124. return m_pParentClass->QueryInterface(iid, ppvObj);
  125. }
  126. else
  127. {
  128. SCODE scRetVal = E_NOINTERFACE;
  129. *ppvObj = NULL;
  130. if (IID_IUnknown == iid)
  131. {
  132. *ppvObj = (IUnknown *)this;
  133. scRetVal = S_OK;
  134. }
  135. else if (IID_ILocFile == iid)
  136. {
  137. *ppvObj = (ILocFile *)this;
  138. scRetVal = S_OK;
  139. }
  140. if (S_OK == scRetVal)
  141. {
  142. AddRef();
  143. }
  144. return ResultFromScode(scRetVal);
  145. }
  146. } // end of CLocImpFile::QueryInterface()
  147. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  148. //
  149. // Check object for validity. Asserts if not! (debug only)
  150. //------------------------------------------------------------------------------
  151. void
  152. CLocImpFile::AssertValidInterface()
  153. const
  154. {
  155. AssertValid();
  156. return;
  157. } // end of CLocImpFile::AssertValidInterface()
  158. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  159. //
  160. // Open the file and make sure it is the correct type. Return TRUE if it is,
  161. // FALSE if not or on error.
  162. //------------------------------------------------------------------------------
  163. BOOL
  164. CLocImpFile::OpenFile(
  165. const CFileSpec &fsFileSpec, // Name of file to open.
  166. CReporter &Reporter) // Reporter object for messages.
  167. {
  168. DEBUGONLY(fsFileSpec.AssertValid());
  169. DEBUGONLY(Reporter.AssertValid());
  170. const CPascalString &pstrFileName = fsFileSpec.GetFileName();
  171. BOOL fRetVal = FALSE;
  172. LTTRACEPOINT("OpenFile()");
  173. // Set reporter pointer for the duration of this function.
  174. m_pReporter = &Reporter;
  175. try
  176. {
  177. CFileException excFile;
  178. m_pstrFileName = pstrFileName; // Initialize source filename.
  179. m_idFile = fsFileSpec.GetFileId();
  180. if (m_pOpenSourceFile != NULL)
  181. {
  182. // If source file pointer seems to be open already, close it.
  183. m_pOpenSourceFile->Close();
  184. delete m_pOpenSourceFile;
  185. m_pOpenSourceFile = NULL;
  186. }
  187. // Open the source file. Doesn't throw an exception if the open
  188. // fails, but does return FALSE and put the info in an exception
  189. // structure if you supply one.
  190. m_pOpenSourceFile = new CLFile;
  191. fRetVal = m_pOpenSourceFile->Open(m_pstrFileName,
  192. CFile::modeRead | CFile::shareDenyNone, &excFile);
  193. if (!fRetVal)
  194. {
  195. ReportException(&excFile);
  196. m_pOpenSourceFile->Abort();
  197. delete m_pOpenSourceFile;
  198. m_pOpenSourceFile = NULL;
  199. // fRetCode is already FALSE.
  200. }
  201. else
  202. {
  203. // Verify() assumes it is in a try/catch frame.
  204. fRetVal = Verify();
  205. }
  206. }
  207. catch(CException *e)
  208. {
  209. ReportException(e);
  210. delete m_pOpenSourceFile;
  211. m_pOpenSourceFile = NULL;
  212. fRetVal = FALSE;
  213. // m_pReporter will be NULLed by normal cleanup code below.
  214. e->Delete();
  215. }
  216. catch(...)
  217. {
  218. // Reset the reporter pointer, no idea if it will still be valid by
  219. // the time the destructor gets called. The only other thing that
  220. // needs to be cleaned up is the source file, which will be handled in
  221. // the destructor.
  222. m_pReporter = NULL;
  223. throw;
  224. }
  225. m_pReporter = NULL;
  226. return fRetVal;
  227. } // end of CLocImpFile::OpenFile()
  228. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  229. //
  230. // Return the file type (a ft* constant from impfile.h). If you only have one
  231. // file type, you can just return it directly.
  232. //------------------------------------------------------------------------------
  233. FileType
  234. CLocImpFile::GetFileType()
  235. const
  236. {
  237. return m_FileType;
  238. } // end of CLocImpFile::GetFileType()
  239. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  240. //
  241. // Return the file description in strDesc, according to the file type. If you
  242. // have only one file type, you can just return a string directly.
  243. //------------------------------------------------------------------------------
  244. void
  245. CLocImpFile::GetFileTypeDescription(
  246. CLString &strDesc) // Place to return file description string.
  247. const
  248. {
  249. LTVERIFY(strDesc.LoadString(g_hDll, IDS_IMP_FILE_DESC));
  250. return;
  251. } // end of CLocImpFile::GetFileTypeDescription()
  252. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  253. //
  254. // Return the names of any associated files as a list of strings in lstFiles.
  255. // Returns TRUE if there are any, FALSE if not.
  256. //------------------------------------------------------------------------------
  257. BOOL
  258. CLocImpFile::GetAssociatedFiles(
  259. CStringList &lstFiles) // Return associated file names here.
  260. const
  261. {
  262. DEBUGONLY(lstFiles.AssertValid());
  263. LTASSERT(lstFiles.GetCount() == 0);
  264. // TODO: If your files have associated files, put them in lstFiles here.
  265. UNREFERENCED_PARAMETER(lstFiles);
  266. return FALSE;
  267. } // end of CLocImpFile::GetAssociatedFiles()
  268. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  269. //
  270. // Enumerate all the localizable items in this file. Returns TRUE on success,
  271. // FALSE on error.
  272. //------------------------------------------------------------------------------
  273. BOOL
  274. CLocImpFile::EnumerateFile(
  275. CLocItemHandler &ihItemHandler, // Localizable-item handler and
  276. // reporter object all in one!
  277. const CLocLangId &lid, // Source language ID object.
  278. const DBID &dbidFileId) // Database ID of file, used as parent
  279. // for all top-level items in the
  280. // file.
  281. {
  282. DEBUGONLY(ihItemHandler.AssertValid());
  283. DEBUGONLY(lid.AssertValid());
  284. DEBUGONLY(dbidFileId.AssertValid());
  285. LTTRACEPOINT("EnumerateFile()");
  286. // Set reporter pointer for the duration of this function.
  287. m_pReporter = &ihItemHandler;
  288. if (NULL == m_pOpenSourceFile)
  289. {
  290. // Source file isn't open, whoops.
  291. LTASSERT(0 && "Source file isn't open in CLocImpFile::EnumerateFile()");
  292. return FALSE;
  293. }
  294. // Retrieve and store the ANSI code page value. Note that some types
  295. // of files use OEM code pages instead, or even use both. To get the
  296. // OEM code page, do GetCodePage(cpDos) instead.
  297. m_cpSource = lid.GetCodePage(cpAnsi);
  298. BOOL bRet = TRUE;
  299. try
  300. {
  301. bRet = EnumerateStrings(ihItemHandler,dbidFileId,FALSE);
  302. }
  303. catch(CException *e)
  304. {
  305. ReportException(e);
  306. bRet = FALSE;
  307. // m_pReporter will be NULLed by normal cleanup code below.
  308. e->Delete();
  309. }
  310. catch (...)
  311. {
  312. // Reset the reporter pointer, no idea if it will still be valid by
  313. // the time the destructor gets called. Reset the process pointer,
  314. // since it definitely won't be valid! The only other thing that
  315. // needs to be cleaned up is the source file, which will be handled in
  316. // the destructor.
  317. m_pReporter = NULL;
  318. throw;
  319. }
  320. m_pReporter = NULL; // Reset reporter pointer.
  321. return bRet;
  322. } // end of CLocImpFile::EnumerateFile()
  323. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  324. //
  325. // Create a new target file be replacing resources in the source file with the
  326. // localized items from Espresso.
  327. //------------------------------------------------------------------------------
  328. BOOL
  329. CLocImpFile::GenerateFile(
  330. const CPascalString &pstrTargetFile,// Name of target file.
  331. CLocItemHandler &ihItemHandler, // Localizable-item handler and
  332. // reporter object all in one!
  333. const CLocLangId &lidSource, // Source language ID object.
  334. const CLocLangId &lidTarget, // Target language ID object.
  335. const DBID &dbidParent) // Database ID of file, used as
  336. // parent for all top-level items
  337. // in the file.
  338. {
  339. DEBUGONLY(pstrTargetFile.AssertValid());
  340. DEBUGONLY(ihItemHandler.AssertValid());
  341. DEBUGONLY(lidSource.AssertValid());
  342. DEBUGONLY(lidTarget.AssertValid());
  343. DEBUGONLY(dbidParent.AssertValid());
  344. BOOL fRetVal = FALSE;
  345. // Set reporter pointer for the duration of this function.
  346. m_pReporter = &ihItemHandler;
  347. if (NULL == m_pOpenSourceFile)
  348. {
  349. // Source file isn't open, whoops.
  350. LTASSERT(0 && "Source file isn't open in CLocImpFile::GenerateFile()");
  351. return FALSE;
  352. }
  353. // Retrieve and store the ANSI code page values for the source and target
  354. // files. Note that some types of files use OEM code pages instead, or
  355. // even use both. To get the OEM code page, do GetCodePage(cpDos) instead.
  356. m_cpSource = lidSource.GetCodePage(cpAnsi);
  357. m_cpTarget = lidTarget.GetCodePage(cpAnsi);
  358. try
  359. {
  360. m_pstrTargetFile = pstrTargetFile; // Initialize target filename.
  361. CFileStatus fsFileStatus;
  362. CLFile::CopyFile(m_pstrFileName,m_pstrTargetFile,FALSE);
  363. CLFile::GetStatus(m_pstrTargetFile, fsFileStatus);
  364. if(fsFileStatus.m_attribute & CFile::readOnly)
  365. {
  366. fsFileStatus.m_attribute &= ~CFile::readOnly;
  367. CLFile::SetStatus(m_pstrTargetFile, fsFileStatus);
  368. }
  369. fRetVal = EnumerateStrings(ihItemHandler,dbidParent,TRUE);
  370. }
  371. catch(CException *e)
  372. {
  373. ReportException(e, ImpEitherError);
  374. fRetVal = FALSE;
  375. // m_pReporter will be NULLed by normal cleanup code.
  376. e->Delete();
  377. }
  378. catch(...)
  379. {
  380. // Generic exception handling is needed here because otherwise
  381. // target file will not be cleaned up. Also, no idea if reporter
  382. // pointer will still be valid by the time the destructor is
  383. // called. The process pointer definitely won't be valid, so reset
  384. // it too. The source file will be cleaned up by the destructor.
  385. m_pReporter = NULL;
  386. throw;
  387. }
  388. // Cleanup.
  389. if (!fRetVal)
  390. {
  391. try
  392. {
  393. // Nuke the target file if the generate failed.
  394. CLFile::Remove(pstrTargetFile);
  395. }
  396. catch(CException *e)
  397. {
  398. ReportException(e, ImpTargetError);
  399. // fRetVal is already FALSE
  400. // m_pReporter will be NULLed by normal cleanup code.
  401. e->Delete();
  402. }
  403. catch(...)
  404. {
  405. // Generic exception handling is needed here because otherwise
  406. // target file will not be cleaned up. Also, no idea if reporter
  407. // pointer will still be valid by the time the destructor is
  408. // called. The process pointer is already NULL. The source file
  409. // will be cleaned up by the destructor.
  410. m_pReporter = NULL;
  411. throw;
  412. }
  413. }
  414. // Normal cleanup code.
  415. m_pReporter = NULL; // Reset reporter pointer.
  416. return fRetVal;
  417. } // end of CLocImpFile::GenerateFile()
  418. //------------------------------------------------------------------------------
  419. //
  420. // TODO:
  421. // Verify that a file is a ???, as best we can. When we're reasonably sure,
  422. // set the reporter confidence level to high -- until then, messages will be
  423. // discarded, not displayed. This is also the place where m_FileType is set.
  424. //
  425. // Returns TRUE if so, FALSE if not or on error, or throws an exception.
  426. //
  427. // Normally there is need to catch exceptions in this function, they will
  428. // be caught and handled by a higher level. To avoid memory leaks, consider
  429. // using automatic variables or CByteArrays (as described and demonstrated in
  430. // the utility function FindSignature() below) instead of dynamic allocation.
  431. //------------------------------------------------------------------------------
  432. BOOL
  433. CLocImpFile::Verify()
  434. {
  435. DEBUGONLY(AssertValid());
  436. LTASSERT(m_pReporter != NULL);
  437. DEBUGONLY(m_pReporter->AssertValid());
  438. // ...
  439. // Set confidence level to high and return that we recognize this file.
  440. m_pReporter->SetConfidenceLevel(CReporter::High);
  441. return TRUE;
  442. } // end of CLocImpFile::Verify()
  443. //------------------------------------------------------------------------------
  444. //
  445. // Reports the exception described by *pException. Since the message can be
  446. // retrieved directly from the exception, there is no need (as far as reporting
  447. // goes) to catch or handle different kinds of exceptions separately. Normally,
  448. // there is no reason for your code to call this function, since under normal
  449. // circumstances you don't have to catch exceptions.
  450. //
  451. // THIS FUNCTION IS USED BY THE FRAMEWORK! DO NOT REMOVE IT!
  452. //------------------------------------------------------------------------------
  453. void
  454. CLocImpFile::ReportException(
  455. CException *pException, // Exception to be reported.
  456. ImpFileError WhichFile) // Defaults to ImpSourceError (most common).
  457. const
  458. {
  459. const UINT MAX_MESSAGE = 256;
  460. CLString strContext;
  461. CLString strMessage;
  462. char *pszMessage;
  463. LTASSERT(m_pReporter != NULL);
  464. DEBUGONLY(m_pReporter->AssertValid());
  465. pszMessage = strMessage.GetBuffer(MAX_MESSAGE);
  466. LTASSERT(pszMessage != NULL);
  467. pException->GetErrorMessage(pszMessage, MAX_MESSAGE);
  468. strMessage.ReleaseBuffer();
  469. switch (WhichFile)
  470. {
  471. case ImpNeitherError: // By convention, report errors not really in any
  472. // file against the source file.
  473. case ImpSourceError:
  474. m_pstrFileName.ConvertToCLString(strContext, CP_ACP);
  475. break;
  476. case ImpTargetError:
  477. m_pstrTargetFile.ConvertToCLString(strContext, CP_ACP);
  478. break;
  479. case ImpEitherError:
  480. {
  481. CLString strSource, strTarget;
  482. m_pstrFileName.ConvertToCLString(strSource, CP_ACP);
  483. m_pstrTargetFile.ConvertToCLString(strTarget, CP_ACP);
  484. strContext.Format(g_hDll, IDS_IMP_OR, (const char *) strSource,
  485. (const char *) strTarget);
  486. }
  487. break;
  488. default:
  489. LTASSERT(0 && "WhichFile is bad during CLocImpFile::ReportException");
  490. break;
  491. }
  492. CContext ctx(strContext, m_idFile, otFile, vProjWindow);
  493. m_pReporter->IssueMessage(esError, ctx, strMessage);
  494. return;
  495. } // end of CLocImpFile::ReportException()
  496. //------------------------------------------------------------------------------
  497. //
  498. // Reports a message to the user. Note that the message will be discarded
  499. // unless the reporter's confidence level had been set high (see Verify()).
  500. //------------------------------------------------------------------------------
  501. void
  502. CLocImpFile::ReportMessage(
  503. MessageSeverity sev, // Severity of message.
  504. // (esError, esWarning, esNote)
  505. UINT nMsgId, // ID of string resource to load for message.
  506. ImpFileError WhichFile) // Defaults to ImpSourceError (most common).
  507. const
  508. {
  509. CLString strContext;
  510. LTASSERT(m_pReporter != NULL);
  511. DEBUGONLY(m_pReporter->AssertValid());
  512. switch (WhichFile)
  513. {
  514. case ImpNeitherError: // By convention, report errors not really in any
  515. // file against the source file.
  516. case ImpSourceError:
  517. m_pstrFileName.ConvertToCLString(strContext, CP_ACP);
  518. break;
  519. case ImpTargetError:
  520. m_pstrTargetFile.ConvertToCLString(strContext, CP_ACP);
  521. break;
  522. case ImpEitherError:
  523. {
  524. CLString strSource, strTarget;
  525. m_pstrFileName.ConvertToCLString(strSource, CP_ACP);
  526. m_pstrTargetFile.ConvertToCLString(strTarget, CP_ACP);
  527. strContext.Format(g_hDll, IDS_IMP_OR, (const char *) strSource,
  528. (const char *) strTarget);
  529. }
  530. break;
  531. default:
  532. LTASSERT(0 && "WhichFile is bad during CLocImpFile::ReportMessage");
  533. break;
  534. }
  535. CContext ctx(strContext, m_idFile, otFile, vProjWindow);
  536. m_pReporter->IssueMessage(sev, ctx, g_hDll, nMsgId);
  537. return;
  538. } // end of CLocImpFile::ReportMessage()
  539. #ifdef LTASSERT_ACTIVE
  540. //------------------------------------------------------------------------------
  541. //
  542. // Asserts if the object is not valid. Any functions you add should probably
  543. // call this function (in DEBUGONLY()) first thing -- see Verify() and Enum().
  544. //------------------------------------------------------------------------------
  545. void
  546. CLocImpFile::AssertValid()
  547. const
  548. {
  549. // Check base class.
  550. CLObject::AssertValid();
  551. // Check C.O.M. data. m_pParentClass should always be NULL.
  552. // Correct range for m_ulRefCount is unknown, but make sure it hasn't
  553. // wrapped around by checking for less than 100 (if we ever exceed
  554. // 100 references from below, there's probably something wrong too!).
  555. LTASSERT(NULL == m_pParentClass);
  556. LTASSERT(m_ulRefCount < 100);
  557. // Check filename strings.
  558. m_pstrFileName.AssertValid();
  559. m_pstrTargetFile.AssertValid();
  560. // If the file object pointers are non-NULL, check the objects.
  561. if (m_pOpenSourceFile != NULL)
  562. {
  563. m_pOpenSourceFile->AssertValid();
  564. }
  565. // If the reporter pointer is non-NULL, check the object.
  566. if (m_pReporter != NULL)
  567. {
  568. m_pReporter->AssertValid();
  569. }
  570. // If the process object pointer is non-NULL, check the object.
  571. // Make sure m_FileType is one of the valid types.
  572. switch (m_FileType)
  573. {
  574. case ftMNCFileType:
  575. case ftUnknown:
  576. // TODO: add cases for all ft* constants in impfile.h here.
  577. // case ftFoo1FileType:
  578. // case ftFoo2FileType:
  579. // These are all OK. Do nothing.
  580. break;
  581. default:
  582. // This is bad!
  583. LTASSERT(0 && "m_FileType is bad during CLocImpFile::AssertValid()");
  584. }
  585. // Can't check code page values, they could be just about anything
  586. // and still valid.
  587. // TODO: check any checkable implementation member variables here.
  588. return;
  589. } // end of CLocImpFile::AssertValid()
  590. #endif // _DEBUG
  591. //Creating a parent node
  592. //ihItemHandler -> Required to send item
  593. //dbidFileId -> Id of the parent of node
  594. //pNewParentId -> New Id will be assigned can be used if this node has
  595. // child
  596. //szNodeRes -> Res ID of the node
  597. //szNodeString -> String of the node
  598. // <- Returns success or failure
  599. BOOL CLocImpFile::CreateParentNode(CLocItemHandler & ihItemHandler,
  600. const DBID & dbidFileId,
  601. DBID & pNewParentId,
  602. const char * szNodeRes,
  603. const char * szNodeString)
  604. {
  605. BOOL fRetVal = TRUE;
  606. CLocItemSet isItemSet;
  607. CLocUniqueId uid;
  608. CPascalString pstrText,pstrId;
  609. try
  610. {
  611. CLocItem *pLocItem = new CLocItem();
  612. pstrId.SetString(szNodeRes,strlen(szNodeRes),m_cpSource);
  613. uid.GetResId().SetId(pstrId);
  614. pstrText.SetString(szNodeString,strlen(szNodeString),m_cpSource);
  615. uid.GetTypeId().SetId(pstrText);
  616. uid.SetParentId(dbidFileId);
  617. //set up pLocItem
  618. pLocItem->SetUniqueId(uid);
  619. pLocItem->SetFDisplayable(TRUE);
  620. pLocItem->SetFExpandable(TRUE);
  621. pLocItem->SetFNoResTable(TRUE);
  622. pLocItem->SetIconType(CIT::Expandable);
  623. //Add the node to Item set
  624. isItemSet.Add(pLocItem);
  625. //Send node to espresso
  626. fRetVal = ihItemHandler.HandleItemSet(isItemSet);
  627. // If OK, retrieve DBID.
  628. if (fRetVal)
  629. {
  630. pNewParentId.Clear();
  631. pNewParentId = pLocItem->GetMyDatabaseId();
  632. }
  633. isItemSet.ClearItemSet();
  634. }
  635. catch (CMemoryException *pMemoryException)
  636. {
  637. CLString strContext;
  638. strContext.LoadString(g_hDll, IDS_MNC_GENERIC_LOCATION);
  639. m_pReporter->IssueMessage(esError, strContext, g_hDll, IDS_MNC_NO_MEMORY,
  640. g_locNull);
  641. fRetVal = FALSE;
  642. pMemoryException->Delete();
  643. }
  644. catch(CException *pException)
  645. {
  646. ReportException(pException);
  647. pException->Delete();
  648. fRetVal = FALSE;
  649. }
  650. return fRetVal;
  651. }
  652. //Creating a child node
  653. //ihItemHandler -> Required to send item
  654. //dbidFileId -> Id of the parent of node
  655. //pNewParentId -> New Id to be use for items belonging to this child
  656. //szNodeRes -> Res ID of the node
  657. //szNodeString -> String of the node
  658. // <- Returns success or failure
  659. BOOL CLocImpFile::CreateChildNode(CLocItemHandler & ihItemHandler,
  660. const DBID & dbidFileId,
  661. DBID & pNewParentId,
  662. const char * szNodeRes,
  663. const char * szNodeString)
  664. {
  665. BOOL fRetVal = TRUE;
  666. CLocItemSet isItemSet;
  667. CLocUniqueId uid;
  668. CPascalString pstrText,pstrId;
  669. try
  670. {
  671. CLocItem *pLocItem = new CLocItem();
  672. pstrId.SetString(szNodeRes,strlen(szNodeRes),m_cpSource);
  673. pstrText.SetString(szNodeString,strlen(szNodeString),m_cpSource);
  674. uid.GetResId().SetId(pstrId);
  675. uid.GetTypeId().SetId(pstrText);
  676. uid.SetParentId(dbidFileId);
  677. //set up pLocItem
  678. pLocItem->SetUniqueId(uid);
  679. pLocItem->SetFDisplayable(TRUE);
  680. pLocItem->SetFExpandable(FALSE);
  681. pLocItem->SetFNoResTable(TRUE);
  682. pLocItem->SetIconType(CIT::String);
  683. //Add the node to Item set
  684. isItemSet.Add(pLocItem);
  685. //Send node to espresso
  686. fRetVal = ihItemHandler.HandleItemSet(isItemSet);
  687. // If OK, retrieve DBID.
  688. if (fRetVal)
  689. {
  690. pNewParentId.Clear();
  691. pNewParentId = pLocItem->GetMyDatabaseId();
  692. }
  693. isItemSet.ClearItemSet();
  694. }
  695. catch (CMemoryException *pMemoryException)
  696. {
  697. CLString strContext;
  698. strContext.LoadString(g_hDll, IDS_MNC_GENERIC_LOCATION);
  699. m_pReporter->IssueMessage(esError, strContext, g_hDll, IDS_MNC_NO_MEMORY,
  700. g_locNull);
  701. fRetVal = FALSE;
  702. pMemoryException->Delete();
  703. }
  704. catch(CException *pException)
  705. {
  706. ReportException(pException);
  707. pException->Delete();
  708. fRetVal = FALSE;
  709. }
  710. return fRetVal;
  711. }
  712. BOOL CLocImpFile::EnumerateStrings(CLocItemHandler & ihItemHandler,
  713. const DBID & dbidFileId,
  714. BOOL fGenerating)
  715. {
  716. BOOL fRetVal = TRUE;
  717. try
  718. {
  719. fRetVal = OpenStream(FALSE);
  720. if(!fRetVal)
  721. goto exit_clean;
  722. if(fGenerating)
  723. fRetVal = OpenStream(TRUE);
  724. if(!fRetVal)
  725. goto exit_clean;
  726. if (m_bXMLBased)
  727. fRetVal = ProcessXMLStrings(ihItemHandler,dbidFileId,fGenerating);
  728. else
  729. fRetVal = ProcessStrings(ihItemHandler,dbidFileId,fGenerating);
  730. }
  731. catch(CException *pException)
  732. {
  733. ReportException(pException);
  734. pException->Delete();
  735. fRetVal = FALSE;
  736. }
  737. exit_clean:
  738. if(m_pstmSourceString)
  739. m_pstmSourceString->Release();
  740. if(m_pstgSourceStringTable)
  741. m_pstgSourceStringTable->Release();
  742. if(m_pstgSourceParent)
  743. m_pstgSourceParent->Release();
  744. if(fGenerating)
  745. {
  746. if(m_pstmTargetString)
  747. m_pstmTargetString->Release();
  748. if(m_pstgTargetStringTable)
  749. m_pstgTargetStringTable->Release();
  750. if(m_pstgTargetParent)
  751. m_pstgTargetParent->Release();
  752. }
  753. return fRetVal;
  754. }
  755. BOOL CLocImpFile::ProcessStrings(CLocItemHandler & ihItemHandler,
  756. const DBID & dbidFileId,
  757. BOOL fGenerating)
  758. {
  759. DBID dbidParentId,dbidNodeId;
  760. BOOL fRetVal = TRUE;
  761. BOOL bUseBraces = ::IsConfiguredToUseBracesForStringTables();
  762. fRetVal = CreateParentNode(ihItemHandler,dbidFileId,dbidParentId,"String Table","String Table");
  763. for(DWORD i=0; i < m_dwCountOfStringTables;i++)
  764. {
  765. ULONG dwBytesRead;
  766. OLECHAR FAR* psz;
  767. char szTemp[MAX_BUFFER];
  768. CLocItemSet lsItemSet;
  769. int nLength = 0;
  770. dbidNodeId.Clear();
  771. m_pstmSourceString->Read(&m_clsidSnapIn,sizeof(CLSID),&dwBytesRead);
  772. StringFromCLSID(m_clsidSnapIn,&psz);
  773. wcstombs(szTemp,psz,MAX_BUFFER);
  774. nLength = strlen(szTemp);
  775. LTASSERT((szTemp[0] == '{') && (szTemp[nLength - 1] == '}'));
  776. // strip braces if configured so
  777. CString strGUID(szTemp);
  778. if ( !bUseBraces && strGUID[0] == _T('{') && strGUID[strGUID.GetLength() - 1] == _T('}'))
  779. strGUID = strGUID.Mid(1, strGUID.GetLength() - 2);
  780. fRetVal = CreateChildNode(ihItemHandler,dbidParentId,dbidNodeId,strGUID,strGUID);
  781. m_pstmSourceString->Read(&m_dwCountOfStrings,sizeof(DWORD),&dwBytesRead);
  782. if(fGenerating)
  783. {
  784. HRESULT hr;
  785. DWORD dwBytesWritten;
  786. hr = m_pstmTargetString->Write(&m_clsidSnapIn,sizeof(CLSID),&dwBytesWritten);
  787. hr = m_pstmTargetString->Write(&m_dwCountOfStrings,sizeof(DWORD),&dwBytesWritten);
  788. }
  789. for(DWORD j = 0;j < m_dwCountOfStrings;j++)
  790. {
  791. DWORD dwCharCount;
  792. m_pstmSourceString->Read(&m_dwID,sizeof(DWORD),&dwBytesRead);
  793. m_pstmSourceString->Read(&m_dwRefCount,sizeof(DWORD),&dwBytesRead);
  794. m_pstmSourceString->Read(&dwCharCount,sizeof(DWORD),&dwBytesRead);
  795. WCHAR *pString;
  796. pString = new WCHAR[dwCharCount + 1];
  797. m_pstmSourceString->Read(pString,dwCharCount * 2,&dwBytesRead);
  798. pString[dwCharCount] = L'\0';
  799. int nSize = WideCharToMultiByte(m_cpSource,0,pString,dwCharCount,szTemp,dwCharCount*2,NULL,NULL);
  800. szTemp[nSize] = '\0';
  801. AddItemToSet(lsItemSet,dbidNodeId,m_dwID,szTemp);
  802. delete []pString;
  803. if(!fGenerating)
  804. fRetVal = ihItemHandler.HandleItemSet(lsItemSet);
  805. else
  806. fRetVal = GenerateStrings(ihItemHandler,lsItemSet);
  807. lsItemSet.ClearItemSet();
  808. }
  809. }
  810. return fRetVal;
  811. }
  812. BOOL CLocImpFile::ProcessXMLStrings(CLocItemHandler & ihItemHandler,
  813. const DBID & dbidFileId,
  814. BOOL fGenerating)
  815. {
  816. DBID dbidParentId,dbidNodeId;
  817. BOOL bOK = TRUE;
  818. BOOL bUseBraces = ::IsConfiguredToUseBracesForStringTables();
  819. // check if we have a table
  820. if (m_spStringTablesNode == NULL)
  821. return FALSE;
  822. // create node
  823. bOK = CreateParentNode(ihItemHandler, dbidFileId, dbidParentId, "String Table", "String Table");
  824. if (!bOK)
  825. return bOK;
  826. // read the strings from XML document
  827. CStringTableMap mapStringTables;
  828. HRESULT hr = ReadXMLStringTables(m_spStringTablesNode, mapStringTables);
  829. if (FAILED(hr))
  830. return FALSE;
  831. // iterate thru read data
  832. CStringTableMap::iterator it;
  833. for (it = mapStringTables.begin(); it != mapStringTables.end(); ++it)
  834. {
  835. std::wstring wstrGUID = it->first;
  836. const CStringMap& rStrings = it->second;
  837. dbidNodeId.Clear();
  838. // convert 2 ansi
  839. CString strGUID;
  840. wcstombs(strGUID.GetBuffer(wstrGUID.length()), wstrGUID.c_str(), wstrGUID.length());
  841. strGUID.ReleaseBuffer();
  842. // strip braces if configured so
  843. if ( !bUseBraces && strGUID[0] == _T('{') && strGUID[strGUID.GetLength() - 1] == _T('}'))
  844. strGUID = strGUID.Mid(1, strGUID.GetLength() - 2);
  845. bOK = CreateChildNode(ihItemHandler, dbidParentId, dbidNodeId, strGUID, strGUID);
  846. if (!bOK)
  847. return bOK;
  848. // handle the strings in map
  849. CStringMap::iterator its;
  850. for (its = rStrings.begin(); its != rStrings.end(); ++its)
  851. {
  852. DWORD dwID = its->first;
  853. std::wstring text = its->second;
  854. DWORD dwCharCount = text.length();
  855. CString strText;
  856. char *pBuffer = strText.GetBuffer(dwCharCount*2);
  857. if (pBuffer == NULL)
  858. return FALSE;
  859. int nSize = WideCharToMultiByte(m_cpSource, 0, text.c_str(), dwCharCount,
  860. pBuffer, dwCharCount*2, NULL, NULL);
  861. pBuffer[nSize] = '\0';
  862. strText.ReleaseBuffer();
  863. // use/update the string
  864. CLocItemSet lsItemSet;
  865. AddItemToSet(lsItemSet, dbidNodeId, dwID, strText);
  866. bOK = ihItemHandler.HandleItemSet(lsItemSet);
  867. if (!bOK)
  868. return bOK;
  869. if(fGenerating)
  870. {
  871. CLocItem *pLocItem = lsItemSet.GetAt(0);
  872. if (!pLocItem)
  873. return FALSE;
  874. std::wstring strNewVal = pLocItem->GetLocString().GetString();
  875. hr = UpdateXMLString(m_spTargetStringTablesNode, wstrGUID, dwID, strNewVal);
  876. CString strMsg = strGUID;
  877. if (FAILED(hr))
  878. return FALSE;
  879. }
  880. lsItemSet.ClearItemSet();
  881. if (!bOK)
  882. return bOK;
  883. }
  884. }
  885. // save XML document to the file
  886. if (fGenerating)
  887. {
  888. hr = SaveXMLContents(m_pstrTargetFile, m_spTargetStringTablesNode);
  889. if (FAILED(hr))
  890. return FALSE;
  891. }
  892. return TRUE;
  893. }
  894. BOOL CLocImpFile::AddItemToSet(CLocItemSet & isItemSet,
  895. const DBID &dbidNodeId,
  896. DWORD dwID,
  897. LPCSTR szText)
  898. {
  899. BOOL fRetVal = TRUE;
  900. CPascalString pstrText;
  901. CLocUniqueId uid;
  902. ULONG lItemType = 1;
  903. try
  904. {
  905. CLocItem * pNewItem = new CLocItem;
  906. pstrText.SetString(szText,strlen(szText),m_cpSource);
  907. uid.GetResId().SetId(dwID);
  908. uid.GetTypeId().SetId(lItemType);
  909. uid.SetParentId(dbidNodeId);
  910. pNewItem->SetUniqueId(uid);
  911. CLocString lsString;
  912. pNewItem->SetIconType(CIT::String);
  913. lsString.SetString(pstrText);
  914. pNewItem->SetFDevLock(FALSE);
  915. pNewItem->SetFUsrLock(FALSE);
  916. pNewItem->SetFExpandable(FALSE);
  917. pNewItem->SetFDisplayable(FALSE);
  918. pNewItem->SetFNoResTable(FALSE);
  919. lsString.SetCodePageType(cpAnsi);
  920. lsString.SetStringType(CST::Text);
  921. pNewItem->SetLocString(lsString);
  922. isItemSet.Add(pNewItem);
  923. fRetVal = TRUE;
  924. }
  925. catch (CMemoryException *pMemoryException)
  926. {
  927. CLString strContext;
  928. strContext.LoadString(g_hDll, IDS_MNC_GENERIC_LOCATION);
  929. m_pReporter->IssueMessage(esError, strContext, g_hDll, IDS_MNC_NO_MEMORY,
  930. g_locNull);
  931. fRetVal = FALSE;
  932. pMemoryException->Delete();
  933. }
  934. catch(CException *pException)
  935. {
  936. ReportException(pException);
  937. pException->Delete();
  938. fRetVal = FALSE;
  939. }
  940. return fRetVal;
  941. }
  942. BOOL CLocImpFile::OpenStream(BOOL fGenerating)
  943. {
  944. BOOL fRetVal = TRUE;
  945. HRESULT hr;
  946. if(!fGenerating)
  947. {
  948. hr = StgOpenStorage(m_pstrFileName,NULL,STGM_TRANSACTED | STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&m_pstgSourceParent);
  949. if(!FAILED(hr))
  950. {
  951. CPascalString pstrStorage,pstrStream;
  952. pstrStorage.SetString("String Table",strlen("String Table"),cpAnsi);
  953. pstrStream.SetString("Strings",strlen("Strings"),cpAnsi);
  954. hr = m_pstgSourceParent->OpenStorage(pstrStorage,NULL,STGM_READ | STGM_SHARE_EXCLUSIVE,NULL,0,&m_pstgSourceStringTable);
  955. if(!FAILED(hr))
  956. {
  957. HRESULT hr = m_pstgSourceStringTable->OpenStream(pstrStream,0,STGM_READ | STGM_SHARE_EXCLUSIVE,0,&m_pstmSourceString);
  958. if(!FAILED(hr))
  959. {
  960. DWORD dwBytesRead;
  961. m_pstmSourceString->Read(&m_dwCountOfStringTables,sizeof(DWORD),&dwBytesRead);
  962. }
  963. else
  964. fRetVal = FALSE;
  965. }
  966. else
  967. {
  968. fRetVal = FALSE;
  969. }
  970. }
  971. else
  972. {
  973. // try to open this as XML document
  974. m_spStringTablesNode.Release(); // release the old one (if such exist)
  975. hr = OpenXMLStringTable(m_pstrFileName, &m_spStringTablesNode);
  976. if (SUCCEEDED(hr))
  977. m_bXMLBased = true;
  978. if (FAILED(hr))
  979. {
  980. CLString strMessage, strFilePath;
  981. m_pstrFileName.ConvertToCLString(strFilePath, CP_ACP);
  982. strMessage.Format(g_hDll, IDS_MSC_ERR_OPENSTORAGE, strFilePath);
  983. LTASSERT(m_pReporter != NULL);
  984. m_pReporter->IssueMessage(esError, CLString(g_hDll, IDS_MNC_GENERIC_LOCATION),strMessage);
  985. fRetVal = FALSE;
  986. }
  987. }
  988. }
  989. else if (!m_bXMLBased)
  990. {
  991. hr = StgOpenStorage(m_pstrTargetFile,NULL,STGM_READWRITE | STGM_SHARE_EXCLUSIVE,NULL,0,&m_pstgTargetParent);
  992. if(!FAILED(hr))
  993. {
  994. CPascalString pstrStorage,pstrStream;
  995. pstrStorage.SetString("String Table",strlen("String Table"),cpAnsi);
  996. pstrStream.SetString("Strings",strlen("Strings"),cpAnsi);
  997. hr = m_pstgTargetParent->OpenStorage(pstrStorage,NULL,STGM_READWRITE | STGM_SHARE_EXCLUSIVE ,NULL,0,&m_pstgTargetStringTable);
  998. if(!FAILED(hr))
  999. {
  1000. HRESULT hr = m_pstgTargetStringTable->CreateStream(pstrStream, STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,0,0,&m_pstmTargetString);
  1001. if(!FAILED(hr))
  1002. {
  1003. DWORD dwBytesRead;
  1004. hr = m_pstmTargetString->Write(&m_dwCountOfStringTables,sizeof(DWORD),&dwBytesRead);
  1005. }
  1006. else
  1007. fRetVal = FALSE;
  1008. }
  1009. else
  1010. fRetVal = FALSE;
  1011. }
  1012. else
  1013. fRetVal = FALSE;
  1014. }
  1015. else
  1016. {
  1017. // try to open this as XML document
  1018. m_spTargetStringTablesNode.Release(); // release the old one (if such exist)
  1019. hr = OpenXMLStringTable(m_pstrTargetFile, &m_spTargetStringTablesNode);
  1020. if (FAILED(hr))
  1021. fRetVal = FALSE;
  1022. }
  1023. return fRetVal;
  1024. }
  1025. BOOL CLocImpFile::GenerateStrings(CLocItemHandler & ihItemHandler,
  1026. CLocItemSet & isItemSet)
  1027. {
  1028. BOOL fRetVal = TRUE;
  1029. INT iNoOfElements = 0;
  1030. DWORD dwBytesWritten,dwCharCount;
  1031. WCHAR *pLocText;
  1032. HRESULT hr;
  1033. try
  1034. {
  1035. if(ihItemHandler.HandleItemSet(isItemSet))
  1036. {
  1037. while(iNoOfElements < isItemSet.GetSize())
  1038. {
  1039. CLocItem *pLocItem;
  1040. CPascalString pstrText;
  1041. pLocItem = isItemSet.GetAt(iNoOfElements);
  1042. hr = m_pstmTargetString->Write(&m_dwID,sizeof(DWORD),&dwBytesWritten);
  1043. hr = m_pstmTargetString->Write(&m_dwRefCount,sizeof(DWORD),&dwBytesWritten);
  1044. pstrText = pLocItem->GetLocString().GetString();
  1045. dwCharCount = pstrText.GetStringLength();
  1046. hr = m_pstmTargetString->Write(&dwCharCount,sizeof(DWORD),&dwBytesWritten);
  1047. pLocText = pstrText.GetStringPointer();
  1048. hr = m_pstmTargetString->Write(pLocText,dwCharCount * 2,&dwBytesWritten);
  1049. pstrText.ReleaseStringPointer();
  1050. iNoOfElements++;
  1051. }
  1052. }
  1053. }
  1054. catch(CException *pException)
  1055. {
  1056. ReportException(pException);
  1057. pException->Delete();
  1058. fRetVal = FALSE;
  1059. }
  1060. return fRetVal;
  1061. }