Leaked source code of windows server 2003
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.

2626 lines
83 KiB

  1. /******************************************************************************
  2. Source File: Glyph Translation.CPP
  3. This implements the classes which encode glyph mapping information.
  4. Copyright (c) 1997 by Microsoft Corporation. All rights reserved.
  5. A Pretty Penny Enterprises Production
  6. Change History:
  7. 02-13-97 Bob_Kjelgaard@Prodigy.Net
  8. ******************************************************************************/
  9. #include "StdAfx.H"
  10. #include "Resource.H"
  11. // Psuedo definition of DESIGNVECTOR.
  12. #if (_WIN32_WINNT < 0x0500)
  13. typedef unsigned long DESIGNVECTOR;
  14. #endif
  15. #include "GTT.H"
  16. #include <CodePage.H>
  17. #include <wingdi.h>
  18. #include <winddi.h>
  19. #include <prntfont.h>
  20. #include <uni16res.h>
  21. #define _FMNEWFM_H_
  22. #include "ProjRec.h"
  23. #include "ChildFrm.H"
  24. #include "GTTView.H"
  25. #include "minidev.h"
  26. extern "C"
  27. BOOL
  28. BConvertCTT2GTT(
  29. IN HANDLE hHeap,
  30. IN PTRANSTAB pCTTData,
  31. IN DWORD dwCodePage,
  32. IN WCHAR wchFirst,
  33. IN WCHAR wchLast,
  34. IN PBYTE pCPSel,
  35. IN PBYTE pCPUnSel,
  36. IN OUT PUNI_GLYPHSETDATA *ppGlyphSetData,
  37. IN DWORD dwGlySize);
  38. extern "C"
  39. PUNI_GLYPHSETDATA
  40. PGetDefaultGlyphset(
  41. IN HANDLE hHeap,
  42. IN WORD wFirstChar,
  43. IN WORD wLastChar,
  44. IN DWORD dwCodePage) ;
  45. struct sRLE {
  46. enum {Direct = 10, Paired, LengthOffset, LengthIndexOffset, Offset};
  47. WORD m_wFormat;
  48. WORD m_widRLE; // Must have unique "magic" value 0x78FE
  49. DWORD m_dwcbThis; // Total size of the memory image.
  50. WCHAR m_wcFirst, m_wcLast;
  51. // Handle mapping data follows
  52. DWORD m_dwcbImage; // Size of the handle mapping data only
  53. DWORD m_dwFlag;
  54. DWORD m_dwcGlyphs, m_dwcRuns;
  55. };
  56. union uencCTT {
  57. WORD wOffset;
  58. BYTE m_bDirect; // This member is used in GTT only!
  59. BYTE abPaired[2];
  60. };
  61. struct sMapTableEntry {
  62. enum {Composed = 1, Direct = 2, Paired = 4, Format = 7, SingleByte,
  63. DoubleByte = 0x10, DBCS = 0x18, Replace = 0x20, Add = 0x40,
  64. Disable = 0x80, PredefinedMask = 0xE0};
  65. BYTE m_bCodePageIndex, m_bfType;
  66. uencCTT m_uectt;
  67. };
  68. // Since I don't build the map table in memory, there is no need to declare
  69. // the fact that the array of entries follows it
  70. struct sMapTable {
  71. DWORD m_dwcbImage, m_dwcEntries;
  72. sMapTable(unsigned ucEntries) {
  73. m_dwcbImage = sizeof *this + ucEntries * sizeof (sMapTableEntry);
  74. m_dwcEntries = ucEntries; }
  75. };
  76. // Use a static for Code Page information- gets the max benefit from caching
  77. static CCodePageInformation* pccpi = NULL ; // Use a static CCodePageInformation to derive more benefit from caching
  78. /******************************************************************************
  79. CInvocation class implementation
  80. ******************************************************************************/
  81. IMPLEMENT_SERIAL(CInvocation, CObject, 0)
  82. void CInvocation::Encode(BYTE c, CString& cs) const {
  83. if (isprint(c))
  84. if (c != _TEXT('\\'))
  85. cs = c;
  86. else
  87. cs = _TEXT("\\\\");
  88. else
  89. cs.Format(_TEXT("\\x%2.2x"), c);
  90. }
  91. /******************************************************************************
  92. CInvocation::Init
  93. This copies a series of bytes into the invocation. Since the data structures
  94. used to represent these lend themselves most readily to this, this is the
  95. normal method used in reading info from a file.
  96. ******************************************************************************/
  97. void CInvocation::Init(PBYTE pb, unsigned ucb) {
  98. m_cbaEncoding.RemoveAll();
  99. while (ucb--)
  100. m_cbaEncoding.Add(*pb++);
  101. }
  102. void CInvocation::GetInvocation(CString& cs) const {
  103. CString csWork;
  104. cs.Empty();
  105. for (int i = 0; i < m_cbaEncoding.GetSize(); i++) {
  106. Encode(m_cbaEncoding[i], csWork);
  107. cs += csWork;
  108. }
  109. }
  110. // This member converts a C-Style encoding of an invocation into
  111. // byte form and stores it.
  112. void CInvocation::SetInvocation(LPCTSTR lpstrNew) {
  113. CString csWork(lpstrNew);
  114. m_cbaEncoding.RemoveAll();
  115. while (!csWork.IsEmpty()) {
  116. CString csClean = csWork.SpanExcluding("\\");
  117. if (!csClean.IsEmpty()) {
  118. for (int i = 0; i < csClean.GetLength(); i++)
  119. m_cbaEncoding.Add((BYTE) csClean[i]);
  120. csWork = csWork.Mid(csClean.GetLength());
  121. continue;
  122. }
  123. // A backslash has been found. If the string ends with a backslash, we
  124. // can't let the function assert in the switch statement so just return
  125. // and ignore the terminating backslash. Yes, I know the string is
  126. // invalid if it ends this way but, according to MS, this isn't a field
  127. // they want validated.
  128. if (csWork.GetLength() <= 1)
  129. return ;
  130. // OK, we have something to decode
  131. switch (csWork[1]) {
  132. case _TEXT('r'):
  133. m_cbaEncoding.Add(13);
  134. csWork = csWork.Mid(2);
  135. continue;
  136. case _TEXT('n'):
  137. m_cbaEncoding.Add(10);
  138. csWork = csWork.Mid(2);
  139. continue;
  140. case _TEXT('b'):
  141. m_cbaEncoding.Add('\b');
  142. csWork = csWork.Mid(2);
  143. continue;
  144. case _TEXT('\t'):
  145. m_cbaEncoding.Add(9);
  146. csWork = csWork.Mid(2);
  147. continue;
  148. case _TEXT('x'):
  149. case _TEXT('X'):
  150. {
  151. CString csNumber = csWork.Mid(2,2).SpanIncluding(
  152. _TEXT("1234567890abcdefABCDEF"));
  153. csWork = csWork.Mid(2 + csNumber.GetLength());
  154. unsigned u;
  155. #if defined(UNICODE) || defined(_UNICODE)
  156. #define _tsscanf swscanf
  157. #else
  158. #define _tsscanf sscanf
  159. #endif
  160. _tsscanf(csNumber, _TEXT("%x"), &u);
  161. m_cbaEncoding.Add((BYTE)u);
  162. continue;
  163. }
  164. // TODO: octal encodings are pretty common
  165. default:
  166. m_cbaEncoding.Add(
  167. (BYTE) csWork[(int)(csWork.GetLength() != 1)]);
  168. csWork = csWork.Mid(2);
  169. continue;
  170. }
  171. }
  172. // We've done it!
  173. }
  174. // This member function records the offset for its image (if any) and updates
  175. // the given offset to reflect this
  176. void CInvocation::NoteOffset(DWORD& dwOffset) {
  177. m_dwOffset = Length() ? dwOffset : 0;
  178. dwOffset += Length();
  179. }
  180. // I/O routines, both native and document form
  181. void CInvocation::WriteSelf(CFile& cfTarget) const {
  182. DWORD dwWork = Length();
  183. cfTarget.Write(&dwWork, sizeof dwWork);
  184. cfTarget.Write(&m_dwOffset, sizeof m_dwOffset);
  185. }
  186. void CInvocation::WriteEncoding(CFile& cfTarget, BOOL bWriteLength) const {
  187. if (bWriteLength) {
  188. WORD w = (WORD)Length();
  189. cfTarget.Write(&w, sizeof w);
  190. }
  191. cfTarget.Write(m_cbaEncoding.GetData(), Length());
  192. }
  193. void CInvocation::Serialize(CArchive& car) {
  194. CObject::Serialize(car);
  195. m_cbaEncoding.Serialize(car);
  196. }
  197. /******************************************************************************
  198. CGlyphHandle class implementation
  199. ******************************************************************************/
  200. CGlyphHandle::CGlyphHandle()
  201. {
  202. m_wPredefined = m_wIndex = 0;
  203. m_dwCodePage = m_dwidCodePage = m_dwOffset = 0;
  204. // Allocate a CCodePageInformation class if needed.
  205. if (pccpi == NULL)
  206. pccpi = new CCodePageInformation ;
  207. }
  208. unsigned CGlyphHandle::CompactSize() const {
  209. return (m_ciEncoding.Length() < 3) ? 0 : m_ciEncoding.Length();
  210. }
  211. /******************************************************************************
  212. CGlyphHandle::operator ==
  213. Returns true if the encoding, code point, and code page IDs (but maybe not
  214. the indices) are the same.
  215. ******************************************************************************/
  216. BOOL CGlyphHandle::operator ==(CGlyphHandle& cghRef) {
  217. if (cghRef.m_wCodePoint != m_wCodePoint ||
  218. cghRef.m_dwCodePage != m_dwCodePage ||
  219. m_ciEncoding.Length() != cghRef.m_ciEncoding.Length())
  220. return FALSE;
  221. for (int i = 0; i < (int) m_ciEncoding.Length(); i++)
  222. if (m_ciEncoding[i] != cghRef.m_ciEncoding[i])
  223. return FALSE;
  224. return TRUE;
  225. }
  226. /******************************************************************************
  227. CGlyphHandle::Init
  228. This function has three overloads, for intializing from direc, paired, or
  229. composed data.
  230. ******************************************************************************/
  231. void CGlyphHandle::Init(BYTE b, WORD wIndex, WORD wCode) {
  232. m_wIndex = wIndex;
  233. m_wCodePoint = wCode;
  234. m_ciEncoding.Init(&b, 1);
  235. }
  236. void CGlyphHandle::Init(BYTE ab[2], WORD wIndex, WORD wCode) {
  237. m_wIndex = wIndex;
  238. m_wCodePoint = wCode;
  239. m_ciEncoding.Init(ab, 2);
  240. }
  241. void CGlyphHandle::Init(PBYTE pb, unsigned ucb, WORD wIndex, WORD wCode) {
  242. m_wIndex = wIndex;
  243. m_wCodePoint = wCode;
  244. m_ciEncoding.Init(pb, ucb);
  245. }
  246. /******************************************************************************
  247. CGlyphHandle::operator =
  248. This is a copy (assignment) operator for the class.
  249. ******************************************************************************/
  250. CGlyphHandle& CGlyphHandle::operator =(CGlyphHandle& cghTemplate) {
  251. m_dwCodePage = cghTemplate.m_dwCodePage;
  252. m_dwidCodePage = cghTemplate.m_dwidCodePage;
  253. m_wCodePoint = cghTemplate.m_wCodePoint;
  254. m_ciEncoding = cghTemplate.m_ciEncoding;
  255. return *this;
  256. }
  257. // This member records the current offset for the data in RLE format, and
  258. // then updates it to account for the length of any data that will go into
  259. // the extra storage at the end of the file/
  260. void CGlyphHandle::RLEOffset(DWORD& dwOffset, const BOOL bCompact) {
  261. if (m_ciEncoding.Length() < 3)
  262. return; // Don't need it, and don't use it!
  263. m_dwOffset = dwOffset;
  264. dwOffset += bCompact ? CompactSize() : MaximumSize();
  265. }
  266. /******************************************************************************
  267. CGlyphHandle::GTTOffset
  268. This member records the current offset for where our data will go, then adds
  269. the length of the encoding string to it and updates the offset. It will only
  270. be updated if the encoding must be composed data. The encoding length
  271. includes a WORD length in the GTT world. Data of 1 byte, or of 2 if DBCS or
  272. a Paired font, does not add any length.
  273. ******************************************************************************/
  274. void CGlyphHandle::GTTOffset(DWORD& dwOffset, BOOL bPaired) {
  275. if (m_ciEncoding.Length() >
  276. (unsigned) 1 + (bPaired || pccpi->IsDBCS(m_dwCodePage))) {
  277. m_dwOffset = dwOffset;
  278. dwOffset += m_ciEncoding.Length() + sizeof m_wIndex;
  279. }
  280. else
  281. m_dwOffset = 0;
  282. }
  283. // These members write our vital stuff to a given file.
  284. void CGlyphHandle::WriteRLE(CFile& cfTarget, WORD wFormat) const {
  285. // This is the RLE-specific glyph handle encoding
  286. union {
  287. DWORD dwOffset;
  288. struct {
  289. union {
  290. struct {
  291. BYTE bFirst, bSecond;
  292. };
  293. WORD wOffset;
  294. };
  295. union {
  296. struct {
  297. BYTE bIndexOrHiOffset, bLength;
  298. };
  299. WORD wIndex;
  300. };
  301. };
  302. };
  303. switch (wFormat) {
  304. case sRLE::Direct:
  305. case sRLE::Paired:
  306. bFirst = m_ciEncoding[0];
  307. bSecond = m_ciEncoding[1];
  308. wIndex = m_wIndex;
  309. break;
  310. case sRLE::LengthIndexOffset:
  311. if (!CompactSize()) { // Encode it in the first two bytes
  312. bFirst = m_ciEncoding[0];
  313. bSecond = m_ciEncoding[1];
  314. }
  315. else
  316. wOffset = (WORD) m_dwOffset;
  317. bIndexOrHiOffset = (BYTE) m_wIndex;
  318. bLength = (BYTE)m_ciEncoding.Length();
  319. break;
  320. case sRLE::LengthOffset:
  321. if (!CompactSize()) { // Encode it in the first two bytes
  322. bFirst = m_ciEncoding[0];
  323. bSecond = m_ciEncoding[1];
  324. bIndexOrHiOffset = (BYTE) m_wIndex;
  325. bLength = (BYTE)m_ciEncoding.Length();
  326. break;
  327. }
  328. dwOffset = m_dwOffset;
  329. bLength = (BYTE)m_ciEncoding.Length();
  330. break;
  331. case sRLE::Offset:
  332. dwOffset = m_dwOffset;
  333. break;
  334. default:
  335. _ASSERTE(FALSE);
  336. // Should probably throw an exception...
  337. }
  338. cfTarget.Write(&dwOffset, sizeof dwOffset);
  339. }
  340. /******************************************************************************
  341. CGlyphHandle::WriteGTT
  342. This member function writes the GTT map table entry for this glyph in the
  343. requested format.
  344. ******************************************************************************/
  345. static BYTE abFlags[] = {sMapTableEntry::Replace, sMapTableEntry::Add,
  346. sMapTableEntry::Disable};
  347. void CGlyphHandle::WriteGTT(CFile& cfTarget, BOOL bPredefined) const {
  348. sMapTableEntry smte;
  349. smte.m_bCodePageIndex = (bPredefined && m_wPredefined == Removed) ?
  350. 0 : (BYTE) m_dwidCodePage;
  351. // GTTOffset set m_dwOffset if Composed is needed. Otherwise we can tell
  352. // the proper flags by looking at the length and whether it is DBCS or not
  353. if (m_dwOffset) {
  354. smte.m_uectt.wOffset = (WORD) m_dwOffset;
  355. smte.m_bfType = sMapTableEntry::Composed;
  356. }
  357. else {
  358. smte.m_bfType = pccpi->IsDBCS(m_dwCodePage) ?
  359. ((m_ciEncoding.Length() == 2) ?
  360. sMapTableEntry::Paired : sMapTableEntry::Direct ) |
  361. (pccpi->IsDBCS(m_dwCodePage, m_wCodePoint) ?
  362. sMapTableEntry::DoubleByte : sMapTableEntry::SingleByte) :
  363. (m_ciEncoding.Length() == 2) ?
  364. sMapTableEntry::Paired : sMapTableEntry::Direct;
  365. smte.m_uectt.abPaired[0] = m_ciEncoding[0];
  366. smte.m_uectt.abPaired[1] = m_ciEncoding[1];
  367. }
  368. if (bPredefined)
  369. smte.m_bfType |= abFlags[m_wPredefined];
  370. // Just write it out!
  371. cfTarget.Write(&smte, sizeof smte);
  372. }
  373. /******************************************************************************
  374. CGlyphHandle::WriteEncoding
  375. This method writes the encoding to to the file in the desired format. The
  376. formats are:
  377. GTT- write nothing if not composed. If composed, write the length, and then
  378. the encoding.
  379. RLESmall- just the encoding
  380. RLEBig- the index and the encoding.
  381. ******************************************************************************/
  382. void CGlyphHandle::WriteEncoding(CFile& cfTarget, WORD wfHow) const {
  383. if (!m_dwOffset)
  384. return; // Nothing to write
  385. if (wfHow == RLEBig)
  386. cfTarget.Write(&m_wIndex, sizeof m_wIndex);
  387. m_ciEncoding.WriteEncoding(cfTarget, wfHow == GTT);
  388. }
  389. /******************************************************************************
  390. CRunRecord class implementation
  391. ******************************************************************************/
  392. CRunRecord::CRunRecord(CGlyphHandle *pcgh, CRunRecord *pcrrPrevious) {
  393. m_wFirst = pcgh -> CodePoint();
  394. m_wcGlyphs = 1;
  395. m_dwOffset = 0;
  396. m_cpaGlyphs.Add(pcgh);
  397. // Maintain that old double chain!
  398. m_pcrrPrevious = pcrrPrevious;
  399. m_pcrrNext = m_pcrrPrevious -> m_pcrrNext;
  400. m_pcrrPrevious -> m_pcrrNext = this;
  401. if (m_pcrrNext)
  402. m_pcrrNext -> m_pcrrPrevious = this;
  403. }
  404. /******************************************************************************
  405. CRunRecord::CRunRecord(CRunRecord *pcrrPrevious, WORD wFirst)
  406. This private constructor is the second tail record initializer. It is called
  407. when a run is split due to a glyph deletion. In this case, we need to hook
  408. into the chain, then fill in the details from our predecessor. wFirst tells
  409. us where to begin extracting data from said predecessor.
  410. ******************************************************************************/
  411. CRunRecord::CRunRecord(CRunRecord* pcrrPrevious, WORD wFirst) {
  412. m_pcrrPrevious = pcrrPrevious;
  413. m_pcrrNext = pcrrPrevious -> m_pcrrNext;
  414. if (m_pcrrNext)
  415. m_pcrrNext -> m_pcrrPrevious = this;
  416. m_pcrrPrevious -> m_pcrrNext = this;
  417. m_wFirst = m_wcGlyphs = 0;
  418. m_dwOffset = 0;
  419. // That's the normal empty initialization. Now, er fill ourselves from
  420. // our predecessor
  421. for (; wFirst < pcrrPrevious -> Glyphs(); wFirst++)
  422. Add(&pcrrPrevious -> Glyph(wFirst));
  423. }
  424. /******************************************************************************
  425. CRunRecord::CRunRecord(CRunRecord *pcrrPrevious)
  426. This private constructor is the third and final tail record initializer. It
  427. makes an exact duplicate of the previous record, then links itself into the
  428. chain appropriately.
  429. This constructor is necessary when a new code point is inserted ahead of the
  430. earliest code point in the set of run records without extending the first
  431. run.
  432. ******************************************************************************/
  433. CRunRecord::CRunRecord(CRunRecord *pcrrPrevious) {
  434. m_wFirst = pcrrPrevious -> m_wFirst;
  435. m_wcGlyphs = pcrrPrevious -> m_wcGlyphs;
  436. m_pcrrNext = pcrrPrevious -> m_pcrrNext;
  437. m_pcrrPrevious = pcrrPrevious;
  438. m_pcrrPrevious -> m_pcrrNext = this;
  439. if (m_pcrrNext)
  440. m_pcrrNext -> m_pcrrPrevious = this;
  441. m_cpaGlyphs.Copy(pcrrPrevious -> m_cpaGlyphs);
  442. }
  443. // Initialize empty- this is used for the root record only
  444. CRunRecord::CRunRecord() {
  445. m_wFirst = m_wcGlyphs = 0;
  446. m_dwOffset = 0;
  447. m_pcrrNext = m_pcrrPrevious = NULL;
  448. }
  449. CRunRecord::~CRunRecord() {
  450. if (m_pcrrNext)
  451. delete m_pcrrNext;
  452. }
  453. unsigned CRunRecord::TotalGlyphs() const {
  454. return m_pcrrNext ?
  455. m_wcGlyphs + m_pcrrNext -> TotalGlyphs() : m_wcGlyphs;
  456. }
  457. BOOL CRunRecord::MustCompose() const {
  458. for (unsigned u = 0; u < m_wcGlyphs; u++)
  459. if (GlyphData(u).CompactSize())
  460. return TRUE; // No need to look further
  461. return m_pcrrNext ? m_pcrrNext -> MustCompose() : FALSE;
  462. }
  463. unsigned CRunRecord::ExtraNeeded(BOOL bCompact) {
  464. unsigned uNeeded = 0;
  465. for (unsigned u = 0; u < m_wcGlyphs; u++)
  466. uNeeded += bCompact ? Glyph(u).CompactSize() : Glyph(u).MaximumSize();
  467. return uNeeded + (m_pcrrNext ? m_pcrrNext -> ExtraNeeded() : 0);
  468. }
  469. /******************************************************************************
  470. CRunRecord::GetGlyph()
  471. This returns the nth handle in the run. We use recursion. This could get
  472. bad enough in terms of performance (ony used to fill glyph map page in
  473. editor) that we drop it, but I'll try it first.
  474. ******************************************************************************/
  475. CGlyphHandle* CRunRecord::GetGlyph(unsigned u) const {
  476. if (u < m_wcGlyphs)
  477. return (CGlyphHandle *) m_cpaGlyphs[u];
  478. return m_pcrrNext ? m_pcrrNext -> GetGlyph(u - m_wcGlyphs) : NULL;
  479. }
  480. /******************************************************************************
  481. CRunRecord::Add
  482. This member adds a glyph to the set of run records. This can mean adding an
  483. additional record at the beginning or end of the set, extending an existing
  484. record at either the beginning or end, and in those cases, orentiay merging
  485. two records together.
  486. ******************************************************************************/
  487. void CRunRecord::Add(CGlyphHandle *pcgh) {
  488. WCHAR wcNew = pcgh -> CodePoint();
  489. // If the glyph is already in the run, just update the info on it.
  490. if (m_wcGlyphs && wcNew >= m_wFirst && wcNew < m_wFirst + m_wcGlyphs){
  491. m_cpaGlyphs.SetAt(wcNew - m_wFirst, pcgh);
  492. return;
  493. }
  494. // If this is the first record, and the glyph falls ahead of our first
  495. // entry, we must clone ourselves, and become a one-glyph run. We cannot
  496. // insert a record in front of oursleves as we are embedded in the
  497. // glyph map structure directly.
  498. if (m_wcGlyphs && wcNew < m_wFirst - 1) {
  499. // This can only happen to the first record- otherwise the tail logic
  500. // below would prevent this occurence
  501. _ASSERTE(!m_pcrrPrevious);
  502. // Clone us, using the copy contructor
  503. CRunRecord *pcrr = new CRunRecord(this);
  504. m_wFirst = pcgh -> CodePoint();
  505. m_wcGlyphs = 1;
  506. m_cpaGlyphs.RemoveAll();
  507. m_cpaGlyphs.Add(pcgh);
  508. return;
  509. }
  510. if (m_wcGlyphs && wcNew != m_wFirst + m_wcGlyphs &&
  511. wcNew != m_wFirst - 1) {
  512. // This belongs in some other record- pass it down the line, or
  513. // append a new one.
  514. if (m_pcrrNext)
  515. // If this falls ahead of the next record, we must insert one now
  516. if (wcNew < m_pcrrNext -> m_wFirst - 1)
  517. m_pcrrNext = new CRunRecord(pcgh, this);
  518. else
  519. m_pcrrNext -> Add(pcgh);
  520. else
  521. m_pcrrNext = new CRunRecord(pcgh, this);
  522. }
  523. else {
  524. // We're adding either at the front or the back, so do it right!
  525. if (m_wFirst > wcNew) {
  526. m_cpaGlyphs.InsertAt(0, pcgh);
  527. m_wFirst = wcNew;
  528. }
  529. else
  530. m_cpaGlyphs.Add(pcgh);
  531. // This belonged here, so add it in- the root record begins with
  532. // 0 glyphs, so if this is the first, keep track of it.
  533. if (!m_wcGlyphs++)
  534. m_wFirst = wcNew;
  535. // If there is a following run, see if we need to merge it.
  536. if (m_pcrrNext &&
  537. m_pcrrNext -> m_wFirst == m_wFirst + m_wcGlyphs) {
  538. // Merge the records.
  539. m_cpaGlyphs.Append(m_pcrrNext -> m_cpaGlyphs);
  540. m_wcGlyphs += m_pcrrNext -> m_wcGlyphs;
  541. // Time to update the list. The class destructor removes the
  542. // tail records, so that pointer must be set to NULL before the
  543. // merged record is deleted.
  544. CRunRecord *pcrrDead = m_pcrrNext;
  545. m_pcrrNext = m_pcrrNext -> m_pcrrNext;
  546. if (m_pcrrNext)
  547. m_pcrrNext -> m_pcrrPrevious = this;
  548. pcrrDead -> m_pcrrNext = NULL; // Avoid destructor overkill
  549. pcrrDead -> m_wcGlyphs = 0; // Ditto
  550. delete pcrrDead;
  551. }
  552. }
  553. }
  554. /******************************************************************************
  555. CRunRecord::Delete
  556. This member deletes a given glyph from the set of runs. Deleting an entry is
  557. messy- it means splitting the record, unless we were so fortunate as to
  558. merely lop off one of the ends.
  559. ******************************************************************************/
  560. void CRunRecord::Delete(WORD wCodePoint) {
  561. // If this isn't the right record, recurse or return as appropriate
  562. if (wCodePoint < m_wFirst)
  563. return;
  564. if (wCodePoint >= m_wFirst + m_wcGlyphs) {
  565. if (m_pcrrNext)
  566. m_pcrrNext -> Delete(wCodePoint);
  567. return;
  568. }
  569. WORD wIndex = wCodePoint - m_wFirst;
  570. // Did we get lucky and hit the first or the last?
  571. if (!wIndex || wIndex == -1 + m_wcGlyphs) {
  572. // If there is only one entry in this run, kill it.
  573. if (m_wcGlyphs == 1) {
  574. if (m_pcrrPrevious) { // Not the first, then die!
  575. m_pcrrPrevious -> m_pcrrNext = m_pcrrNext;
  576. if (m_pcrrNext)
  577. m_pcrrNext -> m_pcrrPrevious = m_pcrrPrevious;
  578. m_pcrrNext = NULL; // We no longer have a follwing
  579. delete this;
  580. return; // It is finished
  581. }
  582. // We are the first. If there's someone after us, get their stuff
  583. // and make it ours- otherwise, zero everything.
  584. if (m_pcrrNext) {
  585. m_cpaGlyphs.Copy(m_pcrrNext -> m_cpaGlyphs);
  586. m_wFirst = m_pcrrNext -> m_wFirst;
  587. m_wcGlyphs = m_pcrrNext -> m_wcGlyphs;
  588. CRunRecord *pcrrVictim = m_pcrrNext;
  589. m_pcrrNext = m_pcrrNext -> m_pcrrNext;
  590. if (m_pcrrNext) // Raid 118880: BUG_BUG: m_pcrrNext become zero when deleted 1252 defalt with add code points
  591. m_pcrrNext -> m_pcrrPrevious = this;
  592. pcrrVictim -> m_pcrrNext = NULL;
  593. delete pcrrVictim;
  594. }
  595. else {
  596. m_cpaGlyphs.RemoveAll();
  597. m_wFirst = m_wcGlyphs = 0;
  598. }
  599. m_dwOffset = 0;
  600. return;
  601. }
  602. // OK, we can now kill the offending entry
  603. m_cpaGlyphs.RemoveAt(wIndex);
  604. m_wcGlyphs--;
  605. // Yes, the following line is trick code. It's good for the soul...
  606. m_wFirst += !wIndex;
  607. return; // The glyph, she be toast.
  608. }
  609. // Alas, this means we must split the record.
  610. // Since this means a new one must be made, let a new constructor do
  611. // most of the dirty work for us.
  612. m_pcrrNext = new CRunRecord(this, wIndex + 1);
  613. _ASSERTE(m_pcrrNext); // We lose that, we might as well die...
  614. // Delete everything after the offending member
  615. m_cpaGlyphs.RemoveAt(wIndex, m_wcGlyphs - wIndex);
  616. // Well, that about settles it, eh!
  617. m_wcGlyphs = wIndex;
  618. }
  619. /******************************************************************************
  620. CRunRecord::Empty
  621. This method will be called if the glyph map is being re-initialized. We set
  622. everything back to its initial state, and delete any tail records.
  623. ******************************************************************************/
  624. void CRunRecord::Empty() {
  625. if (m_pcrrNext)
  626. delete m_pcrrNext;
  627. m_pcrrNext = 0;
  628. m_wFirst = m_wcGlyphs = 0;
  629. m_cpaGlyphs.RemoveAll();
  630. }
  631. /******************************************************************************
  632. CRunRecord::NoteOffset
  633. This routine is given an offset which is to be managed in the run- the
  634. management needed differs depending upon the file image being produced, so
  635. we use a parameter to describe the tyoe being output.
  636. In any event, the offset is passed by reference, and updated by each run
  637. record in the set, in turn.
  638. ******************************************************************************/
  639. void CRunRecord::NoteOffset(DWORD& dwOffset, BOOL bRLE, BOOL bPaired) {
  640. if (bRLE) {
  641. m_dwOffset = dwOffset;
  642. dwOffset += m_wcGlyphs *
  643. ((CGlyphHandle *) m_cpaGlyphs[0]) -> RLESize();
  644. }
  645. else
  646. for (unsigned u = 0; u < Glyphs(); u++)
  647. Glyph(u).GTTOffset(dwOffset, bPaired);
  648. // Recurse if there's more...
  649. if (m_pcrrNext)
  650. m_pcrrNext -> NoteOffset(dwOffset, bRLE, bPaired);
  651. }
  652. // This routine passes a DWORD to each glyph handle denoting where it can
  653. // store its extra data. Each updates the offset, if necessary.
  654. // We then recursively call each descendant to do the same thing.
  655. void CRunRecord::NoteExtraOffset(DWORD &dwOffset, const BOOL bCompact) {
  656. for (unsigned u = 0; u < m_wcGlyphs; u++)
  657. Glyph(u).RLEOffset(dwOffset, bCompact);
  658. if (m_pcrrNext)
  659. m_pcrrNext -> NoteExtraOffset(dwOffset, bCompact);
  660. }
  661. // File output functions- These are all basically recursive. The callee does
  662. // its thing, then passes it on down the chain. Since this is the order RLE
  663. // and GTT are written in, everything is fine.
  664. void CRunRecord::WriteSelf(CFile& cfTarget, BOOL bRLE) const {
  665. cfTarget.Write(this, Size(bRLE));
  666. if (m_pcrrNext)
  667. m_pcrrNext -> WriteSelf(cfTarget, bRLE);
  668. }
  669. void CRunRecord::WriteHandles(CFile& cfTarget, WORD wFormat) const {
  670. for (unsigned u = 0; u < m_wcGlyphs; u++)
  671. GlyphData(u).WriteRLE(cfTarget, wFormat);
  672. if (m_pcrrNext)
  673. m_pcrrNext -> WriteHandles(cfTarget, wFormat);
  674. }
  675. // Member for writing the total set of GTT Map Table Entries
  676. void CRunRecord::WriteMapTable(CFile& cfTarget, BOOL bPredefined) const {
  677. for (unsigned u = 0; u < m_wcGlyphs; u++)
  678. GlyphData(u).WriteGTT(cfTarget, bPredefined);
  679. if (m_pcrrNext)
  680. m_pcrrNext -> WriteMapTable(cfTarget, bPredefined);
  681. }
  682. /******************************************************************************
  683. CRunRecord::WriteEncodings
  684. This calls each glyph in the run record in ascending order to have it write
  685. its encoding into the file in the given format. It then recursively calls
  686. the next run record.
  687. ******************************************************************************/
  688. void CRunRecord::WriteEncodings(CFile& cfTarget, WORD wfHow) const {
  689. for (unsigned u = 0; u < m_wcGlyphs; u++)
  690. GlyphData(u).WriteEncoding(cfTarget, wfHow);
  691. if (m_pcrrNext)
  692. m_pcrrNext -> WriteEncodings(cfTarget, wfHow);
  693. }
  694. /******************************************************************************
  695. CCodePageData class implementation
  696. ******************************************************************************/
  697. /******************************************************************************
  698. CCodePageData::Invocation
  699. This member function returns (in C-style string declaration form) the data to
  700. send to the printer to perform the requested select/deselect of this code
  701. page.
  702. ******************************************************************************/
  703. void CCodePageData::Invocation(CString& csReturn, BOOL bSelect) const {
  704. if (bSelect)
  705. m_ciSelect.GetInvocation(csReturn);
  706. else
  707. m_ciDeselect.GetInvocation(csReturn);
  708. }
  709. /******************************************************************************
  710. CCodePageData::SetInvocation(LPCTSTR lpstrInvoke, BOOL bSelect)
  711. This member function sets the select or deselect sring using a string which
  712. is decoded as a C-style string declaration.
  713. ******************************************************************************/
  714. void CCodePageData::SetInvocation(LPCTSTR lpstrInvoke, BOOL bSelect) {
  715. if (bSelect)
  716. m_ciSelect.SetInvocation(lpstrInvoke);
  717. else
  718. m_ciDeselect.SetInvocation(lpstrInvoke);
  719. }
  720. /******************************************************************************
  721. CCodePageData::SetInvocation(PBYTE pb, unsigned ucb, BOOL bSelect)
  722. This member function initializes one of the two CInvocation members via its
  723. Init function.
  724. ******************************************************************************/
  725. void CCodePageData::SetInvocation(PBYTE pb, unsigned ucb, BOOL bSelect) {
  726. if (bSelect)
  727. m_ciSelect.Init(pb, ucb);
  728. else
  729. m_ciDeselect.Init(pb, ucb);
  730. }
  731. /******************************************************************************
  732. CCodePageData::NoteOffsets
  733. This member function is passed an offset at which it will record its
  734. invocation strings. It simply funnels the call to each invocation member,
  735. which updates the value as appropriate.
  736. ******************************************************************************/
  737. void CCodePageData::NoteOffsets(DWORD& dwOffset) {
  738. m_ciSelect.NoteOffset(dwOffset);
  739. m_ciDeselect.NoteOffset(dwOffset);
  740. }
  741. // Write the id and invocation location information to the file
  742. void CCodePageData::WriteSelf(CFile& cfTarget) {
  743. cfTarget.Write(&m_dwid, sizeof m_dwid);
  744. m_ciSelect.WriteSelf(cfTarget);
  745. m_ciDeselect.WriteSelf(cfTarget);
  746. }
  747. // Write the invocation strings to a file.
  748. void CCodePageData::WriteInvocation(CFile& cfTarget) {
  749. m_ciSelect.WriteEncoding(cfTarget);
  750. m_ciDeselect.WriteEncoding(cfTarget);
  751. }
  752. /******************************************************************************
  753. CGlyphMap class implementation
  754. ******************************************************************************/
  755. IMPLEMENT_SERIAL(CGlyphMap, CProjectNode, 0)
  756. // The GTT header
  757. struct sGTTHeader {
  758. DWORD m_dwcbImage;
  759. enum {Version1Point0 = 0x10000};
  760. DWORD m_dwVersion;
  761. DWORD m_dwfControl; // Any flags defined?
  762. long m_lidPredefined;
  763. DWORD m_dwcGlyphs;
  764. DWORD m_dwcRuns;
  765. DWORD m_dwofRuns;
  766. DWORD m_dwcCodePages;
  767. DWORD m_dwofCodePages;
  768. DWORD m_dwofMapTable;
  769. DWORD m_dwReserved[2];
  770. sGTTHeader() {
  771. memset(this, 0, sizeof *this);
  772. m_dwVersion = Version1Point0;
  773. m_lidPredefined = CGlyphMap::NoPredefined;
  774. m_dwcbImage = sizeof *this;
  775. }
  776. };
  777. CSafeMapWordToOb CGlyphMap::m_csmw2oPredefined;
  778. /******************************************************************************
  779. CGlyphMap::Public
  780. This is a static member function which will return a pointer to one of the
  781. predefined GTT files, after loading it if necessary.
  782. ******************************************************************************/
  783. CGlyphMap* CGlyphMap::Public(WORD wID, WORD wCP/*= 0*/, DWORD dwDefCP/*= 0*/,
  784. WORD wFirst/*= 0*/, WORD wLast/*= 255*/)
  785. {
  786. //TRACE("*** First char = %d\t\tLast char = %d\n", wFirst, wLast) ;
  787. // If a GTT in this driver is needed, return NULL to force the
  788. // program to go get it.
  789. if (((short) wID) > 0)
  790. return NULL ;
  791. // If no GTT ID is set, use the code page that is passed in. If no code
  792. // page is passed in, use the project's default code page. If there is
  793. // no project, use 1252 as the default code page.
  794. if (wID == 0)
  795. if ((wID = wCP) == 0)
  796. if ((wID = (WORD) dwDefCP) == 0)
  797. wID = 1252 ;
  798. // Check to see if wID is set to one of the Far East codepages that are
  799. // built into the MDT. If that is the case, change it to the resource ID
  800. // for that code page.
  801. switch (wID) {
  802. case 932:
  803. wID = -17 ;
  804. break ;
  805. case 936:
  806. wID = -16 ;
  807. break ;
  808. case 949:
  809. wID = -18 ;
  810. break ;
  811. case 950:
  812. wID = -10 ;
  813. break ;
  814. } ;
  815. // If the ID is 1252, switch to the resource ID for CP 1252.
  816. if (wID == 1252)
  817. wID = -IDR_CP1252 ;
  818. // The easy part comes if it is already loaded
  819. CObject* pco ;
  820. if (m_csmw2oPredefined.Lookup(wID, pco))
  821. return (CGlyphMap*) pco ;
  822. //// DEAD_BUG - The program can't load huge GTTs so just return NULL.
  823. //
  824. //if ((short) wID >= -18 || (short) wID <= -10)
  825. // return NULL ;
  826. // Manage loading a predefined code page or building a GTT based on a code
  827. // page. Begin by declaring/initializing a class instance for it.
  828. CGlyphMap *pcgm = new CGlyphMap ;
  829. TCHAR acbuf[32] ;
  830. if (FindResource(AfxGetResourceHandle(),
  831. MAKEINTRESOURCE((((short) wID) < 0) ? -(short) wID : wID),
  832. MAKEINTRESOURCE(IDR_GLYPHMAP)))
  833. pcgm->m_csName.LoadString(IDS_DefaultPage + wID) ;
  834. else {
  835. strcpy(acbuf, _T("CP ")) ;
  836. _itoa(wID, &acbuf[3], 10) ;
  837. pcgm->m_csName = acbuf ;
  838. } ;
  839. pcgm->nSetRCID((int) wID) ;
  840. pcgm->m_wFirstChar = wFirst ;
  841. pcgm->m_wLastChar = wLast ;
  842. pcgm->m_bResBldGTT = true ;
  843. // Load/build the GTT. If this works, add it to the list of "predefined"
  844. // GTTs and return a pointer to it.
  845. if (pcgm->Load()) {
  846. m_csmw2oPredefined[wID] = pcgm ;
  847. return pcgm ;
  848. } ;
  849. // Clean up and return NULL if the load/build fails.
  850. delete pcgm ;
  851. return NULL ;
  852. }
  853. /******************************************************************************
  854. CGlyphMap::MergePredefined
  855. This merges in fresh glyph handles from the predefined GTT, then removes all
  856. glyphs destined for the gallows.
  857. ******************************************************************************/
  858. void CGlyphMap::MergePredefined() {
  859. if (m_lidPredefined == NoPredefined)
  860. return;
  861. CWaitCursor cwc; // This takes a long time, I'll bet!
  862. CGlyphMap *pcgm = Public((WORD) m_lidPredefined);
  863. if (!pcgm)
  864. AfxThrowNotSupportedException();
  865. // First, add any new code pages in the predefined GTT
  866. CMapWordToDWord cmw2dPageMap; // Map PDT code pages' indices to our own
  867. for (unsigned u = 0; u < pcgm -> CodePages(); u++) {
  868. for (unsigned u2 = 0; u2 < CodePages(); u2++)
  869. if (PageID(u2) == pcgm -> PageID(u))
  870. break;
  871. if (u2 == CodePages())
  872. AddCodePage(pcgm -> PageID(u));
  873. cmw2dPageMap[(WORD)u] = u2;
  874. }
  875. CPtrArray cpaTemplate;
  876. pcgm -> Collect(cpaTemplate);
  877. for (int i = 0; i < cpaTemplate.GetSize(); i++) {
  878. CGlyphHandle& cghTemplate = *(CGlyphHandle *) cpaTemplate[i];
  879. CObject* pco;
  880. if (!m_csmw2oEncodings.Lookup(cghTemplate.CodePoint(), pco)) {
  881. // Add this one, and map the code page info.
  882. CGlyphHandle* pcgh = new CGlyphHandle;
  883. if (!pcgh)
  884. AfxThrowMemoryException();
  885. *pcgh = cghTemplate;
  886. pcgh -> SetCodePage(cmw2dPageMap[(WORD)cghTemplate.CodePage()],
  887. pcgm -> PageID(cghTemplate.CodePage()));
  888. m_csmw2oEncodings[cghTemplate.CodePoint()] = pcgh;
  889. m_crr.Add(pcgh);
  890. }
  891. }
  892. // Now, all of the new pages have been added. We must remove all points
  893. // listed as "Remove".
  894. Collect(cpaTemplate); // Get all of the handles for ourselves
  895. for (i = (int)cpaTemplate.GetSize(); i--; ) {
  896. CGlyphHandle& cgh = *(CGlyphHandle *) cpaTemplate[i];
  897. if (cgh.Predefined() == CGlyphHandle::Removed)
  898. DeleteGlyph(cgh.CodePoint());
  899. }
  900. }
  901. /******************************************************************************
  902. CGlyphMap::UnmergePredefined
  903. This is the harder of the two predfined handlers, if that is conceivable.
  904. First (unless asked not to), glkyphs must be added to mark those missing from
  905. the predefined GTT.
  906. Then, the entire set is compared to the PDT, so they can be removed as
  907. equivalent, or flagged as added or modified.
  908. ******************************************************************************/
  909. void CGlyphMap::UnmergePredefined(BOOL bTrackRemovals) {
  910. if (m_lidPredefined == NoPredefined)
  911. return;
  912. CWaitCursor cwc; // This takes a long time, I'll bet!
  913. CGlyphMap *pcgm = Public((WORD) m_lidPredefined);
  914. if (!pcgm)
  915. AfxThrowNotSupportedException();
  916. CPtrArray cpaPDT;
  917. if (bTrackRemovals) {
  918. pcgm -> Collect(cpaPDT);
  919. for (int i = 0; i < cpaPDT.GetSize(); i++) {
  920. CGlyphHandle& cgh = *(CGlyphHandle*) cpaPDT[i];
  921. CObject* pco;
  922. if (m_csmw2oEncodings.Lookup(cgh.CodePoint(), pco))
  923. continue;
  924. // This point was removed from the predefined set, so add it to
  925. // ours, and mark it as such.
  926. CGlyphHandle *pcghCorpse = new CGlyphHandle();
  927. if (!pcghCorpse)
  928. AfxThrowMemoryException();
  929. *pcghCorpse = cgh;
  930. pcghCorpse -> SetPredefined(CGlyphHandle::Removed);
  931. m_csmw2oEncodings[cgh.CodePoint()] = pcghCorpse;
  932. m_crr.Add(pcghCorpse);
  933. }
  934. }
  935. // Mark all of the glyphs in our set, now. Also mark the code pages used
  936. Collect(cpaPDT);
  937. CMapWordToDWord cmw2dPages;
  938. for (int i = (int)cpaPDT.GetSize(); i--; ) {
  939. CGlyphHandle& cgh = *(CGlyphHandle*) cpaPDT[i];
  940. union {
  941. CObject *pco;
  942. CGlyphHandle *pcgh;
  943. };
  944. if (pcgm -> m_csmw2oEncodings.Lookup(cgh.CodePoint(), pco))
  945. if (*pcgh == cgh) {
  946. if (cgh.Predefined() == CGlyphHandle::Removed)
  947. continue; // Already accounted for
  948. if (m_bPaired != pcgm -> m_bPaired && cgh.PairedRelevant())
  949. cgh.SetPredefined(CGlyphHandle::Modified);
  950. else {
  951. DeleteGlyph(cgh.CodePoint()); // Unmodified
  952. continue;
  953. }
  954. }
  955. else
  956. cgh.SetPredefined(CGlyphHandle::Modified);
  957. else
  958. cgh.SetPredefined(CGlyphHandle::Added);
  959. cmw2dPages[(WORD)PageID(cgh.CodePage())]++; // Only track these pages
  960. }
  961. // Remove the unused code pages, unless they have selections
  962. for (unsigned u = CodePages(); u--; )
  963. if (!cmw2dPages[(WORD)PageID(u)])
  964. if (CodePage(u).NoInvocation())
  965. RemovePage(u, !u);
  966. }
  967. /******************************************************************************
  968. CGlyphMap::GenerateRuns
  969. This member will create the run records by iterating over the mapped glyph
  970. handles.
  971. ******************************************************************************/
  972. void CGlyphMap::GenerateRuns() {
  973. if (m_crr.TotalGlyphs() == Glyphs())
  974. return;
  975. for (POSITION pos = m_csmw2oEncodings.GetStartPosition(); pos;) {
  976. WORD wValue;
  977. union {
  978. CObject *pco;
  979. CGlyphHandle *pcgh;
  980. };
  981. m_csmw2oEncodings.GetNextAssoc(pos, wValue, pco);
  982. m_crr.Add(pcgh);
  983. }
  984. }
  985. /******************************************************************************
  986. CGlyphMap::Serialize
  987. This member function serializes the Glyph map, i.e., loads or stores it into
  988. a persistent object store. Only the project-level information is stored.
  989. The file will be loaded using the project-level data.
  990. Note: There was a second copy of the GTT's RC ID saved in the MDW file.
  991. Because it could get out of sync with the one in the CGlyphMap's
  992. CRCIDNode instance, the copy of the ID read/written by this routine
  993. is no longer used. A bogus value is written and the number read is
  994. discarded. This "ID" is still kept in the MDW file so that no new MDW
  995. version is needed.
  996. ******************************************************************************/
  997. void CGlyphMap::Serialize(CArchive& car)
  998. {
  999. WORD w = (WORD)0; // Used to read/write bogus RC ID in MDW file.
  1000. CProjectNode::Serialize(car) ;
  1001. if (car.IsLoading()) {
  1002. car >> w ;
  1003. }
  1004. else {
  1005. car << w ;
  1006. }
  1007. }
  1008. /******************************************************************************
  1009. CGlyphMap::CGlyphMap
  1010. The class constructor, in addition to setting some default values, builds an
  1011. array of IDs for the CProjectNode class from which it is derived to use in
  1012. building the context menu in the driver/project view tree.
  1013. It also allocates a single code page record for the current ANSI page, so we
  1014. always have a default page.
  1015. ******************************************************************************/
  1016. CGlyphMap::CGlyphMap() {
  1017. m_cfn.SetExtension(_T(".GTT"));
  1018. m_bPaired = FALSE;
  1019. m_lidPredefined = NoPredefined;
  1020. // Build the context menu control
  1021. m_cwaMenuID.Add(ID_OpenItem);
  1022. m_cwaMenuID.Add(ID_CopyItem);
  1023. m_cwaMenuID.Add(ID_RenameItem);
  1024. m_cwaMenuID.Add(ID_DeleteItem);
  1025. m_cwaMenuID.Add(0);
  1026. m_cwaMenuID.Add(ID_ExpandBranch);
  1027. m_cwaMenuID.Add(ID_CollapseBranch);
  1028. //m_cwaMenuID.Add(0);
  1029. //m_cwaMenuID.Add(ID_GenerateOne);
  1030. // Initialy, let the default code page be the current ANSI page, if this
  1031. // is not a DBCS locale. Otherwise, use 1252, as no DBCS CTT file can be
  1032. // generated with UniTool
  1033. for (WORD w = 0; w < 256; w++)
  1034. if (IsDBCSLeadByte((BYTE) w))
  1035. break;
  1036. m_csoaCodePage.Add(new CCodePageData(w < 256 ? 1252 : GetACP()));
  1037. // Allocate a CCodePageInformation class if needed.
  1038. if (pccpi == NULL)
  1039. pccpi = new CCodePageInformation ;
  1040. // Assume that the GTT's data should be read from a file.
  1041. m_bResBldGTT = false ;
  1042. m_ctSaveTimeStamp = (time_t) 0 ; // The GTT has not been saved
  1043. }
  1044. /******************************************************************************
  1045. CGlyphMap::CodePages(CDWordArray &cdaReturn)
  1046. This overload fills a DWordArray with the code page IDs.
  1047. ******************************************************************************/
  1048. void CGlyphMap::CodePages(CDWordArray &cdaReturn) const {
  1049. cdaReturn.RemoveAll();
  1050. for (unsigned u = 0; u < CodePages(); u++)
  1051. cdaReturn.Add(CodePage(u).Page());
  1052. }
  1053. /******************************************************************************
  1054. CGlyphMap::PageName
  1055. This member returns the name of a particular code page, by index.
  1056. ******************************************************************************/
  1057. CString CGlyphMap::PageName(unsigned u) const {
  1058. return pccpi->Name(CodePage(u).Page());
  1059. }
  1060. /******************************************************************************
  1061. CGlyphMap::Invocation
  1062. This member returns (in C-style encoding) a string which is used to either
  1063. select or deselect a given code page.
  1064. ******************************************************************************/
  1065. void CGlyphMap::Invocation(unsigned u, CString& csReturn,
  1066. BOOL bSelect) const {
  1067. CodePage(u).Invocation(csReturn, bSelect);
  1068. }
  1069. /******************************************************************************
  1070. CGlyphMap::UndefinedPoints
  1071. This member fills a map with all code points NOT in the current mapping, and
  1072. maps them to their related code pages. Thus only translatable points will be
  1073. passed back to the caller.
  1074. ******************************************************************************/
  1075. void CGlyphMap::UndefinedPoints(CMapWordToDWord& cmw2dCollector) const {
  1076. cmw2dCollector.RemoveAll();
  1077. CWaitCursor cwc;
  1078. for (unsigned u = 0; u < CodePages(); u++) {
  1079. CWordArray cwaPage;
  1080. // Collect the code points in the code page
  1081. pccpi->Collect(PageID(u), cwaPage);
  1082. union {
  1083. CObject *pco;
  1084. DWORD dw;
  1085. };
  1086. // Check the entries- if they haven't been mapped yet, and
  1087. // some earlier code page hasn't claimed them, add them.
  1088. for (int i = 0; i < cwaPage.GetSize(); i++)
  1089. if (!m_csmw2oEncodings.Lookup(cwaPage[i], pco) &&
  1090. !cmw2dCollector.Lookup(cwaPage[i], dw))
  1091. cmw2dCollector[cwaPage[i]] = u;
  1092. }
  1093. }
  1094. /******************************************************************************
  1095. CGlyphMap::Load(CByteArray& cbaMap)
  1096. This loads an image of a GTT into safe memory, whether it is predefined or
  1097. a file.
  1098. ******************************************************************************/
  1099. //void CGlyphMap::Load(CByteArray& cbaMap) const
  1100. void CGlyphMap::Load(CByteArray& cbaMap)
  1101. {
  1102. short xxx = (short) ((CProjectNode*) this)->nGetRCID() ; // The GTT's RC ID
  1103. short sid = (short) nGetRCID() ; // The GTT's RC ID
  1104. try {
  1105. // Try to load the GTT from a file when the GTT should not be loaded
  1106. // from a resource or built.
  1107. if (!m_bResBldGTT
  1108. && (sid > 0 || (sid < Wansung && sid != -IDR_CP1252))) {
  1109. CFile cfGTT(m_cfn.FullName(),
  1110. CFile::modeRead | CFile::shareDenyWrite);
  1111. cbaMap.SetSize(cfGTT.GetLength());
  1112. cfGTT.Read(cbaMap.GetData(), (unsigned)cbaMap.GetSize());
  1113. return;
  1114. } ;
  1115. // If the GTT is a resource, load it from there.
  1116. // raid 441362
  1117. if(MAKEINTRESOURCE((sid < 0) ? -sid : sid) == NULL)
  1118. return;
  1119. HRSRC hrsrc = FindResource(AfxGetResourceHandle(),
  1120. MAKEINTRESOURCE((sid < 0) ? -sid : sid),
  1121. MAKEINTRESOURCE(IDR_GLYPHMAP));
  1122. if (hrsrc) {
  1123. HGLOBAL hg = LoadResource(AfxGetResourceHandle(), hrsrc) ;
  1124. if (!hg)
  1125. return ;
  1126. LPVOID lpv = LockResource(hg) ;
  1127. if (!lpv)
  1128. return ;
  1129. cbaMap.SetSize(SizeofResource(AfxGetResourceHandle(), hrsrc)) ;
  1130. memcpy(cbaMap.GetData(), lpv, (size_t)cbaMap.GetSize()) ;
  1131. return ;
  1132. } ;
  1133. //AfxMessageBox("GTT building code reached.") ;
  1134. // If all else fails, try to generate a GTT based on the code page ID
  1135. // that should be in m_wID if this point is reached.
  1136. HANDLE hheap ;
  1137. UNI_GLYPHSETDATA *pGTT ;
  1138. if (!(hheap = HeapCreate(HEAP_NO_SERIALIZE, 10 * 1024, 256 * 1024))) {
  1139. AfxMessageBox(IDS_HeapInGLoad) ;
  1140. return ;
  1141. } ;
  1142. pGTT = PGetDefaultGlyphset(hheap, m_wFirstChar, m_wLastChar,
  1143. (DWORD) sid) ;
  1144. if (pGTT == NULL) {
  1145. HeapDestroy(hheap) ; //raid 116600 Prefix
  1146. AfxMessageBox(IDS_PGetFailedInGLoad) ;
  1147. return ;
  1148. } ;
  1149. cbaMap.SetSize(pGTT->dwSize) ;
  1150. memcpy(cbaMap.GetData(), pGTT, (size_t)cbaMap.GetSize()) ;
  1151. HeapDestroy(hheap) ;
  1152. }
  1153. catch (CException *pce) {
  1154. pce -> ReportError();
  1155. pce -> Delete();
  1156. CString csMessage;
  1157. csMessage.Format(IDS_LoadFailure, Name());
  1158. AfxMessageBox(csMessage);
  1159. }
  1160. }
  1161. /******************************************************************************
  1162. CGlyphmap::SetSourceName
  1163. This takes and stores the source file name so we can load and convert later.
  1164. It also renames (or rather, sets the original name) for the GlyphMap using
  1165. the base file name.
  1166. ******************************************************************************/
  1167. void CGlyphMap::SetSourceName(LPCTSTR lpstrNew) {
  1168. m_csSource = lpstrNew;
  1169. m_csName = m_csSource.Mid(m_csSource.ReverseFind(_T('\\')) + 1);
  1170. if (m_csName.Find(_T('.')) >= 0)
  1171. if (m_csName.Right(4).CompareNoCase(_T(".CTT"))) {
  1172. m_csName.SetAt(m_csName.Find(_T('.')), _T('_'));
  1173. CProjectNode::Rename(m_csName);
  1174. }
  1175. else
  1176. CProjectNode::Rename(m_csName.Left(m_csName.Find(_T('.'))));
  1177. else
  1178. CProjectNode::Rename(m_csName);
  1179. }
  1180. /******************************************************************************
  1181. CGlyphMap::SetFileName
  1182. This sets the new file name. It is done differently than in SetSourceName()
  1183. because the base file name must not be more than 8 characters long. (The
  1184. extra info is left in the node name by SetSourceName() because it is useful
  1185. there and it has no length limit.)
  1186. ******************************************************************************/
  1187. BOOL CGlyphMap::SetFileName(LPCTSTR lpstrNew)
  1188. {
  1189. CString csnew ; // CString version of input parameter
  1190. csnew = lpstrNew ;
  1191. // If the input filespec contains an extension, remove it and pass the
  1192. // resulting string to the file node's rename routine. Otherwise, just
  1193. // pass the original string to the rename routine.
  1194. //
  1195. // This check is complicated by the fact that one of the path components
  1196. // might have a dot in it too. We need to check for the last dot and make
  1197. // sure it comes before a path separator.
  1198. if (csnew.ReverseFind(_T('.')) > csnew.ReverseFind(_T('\\')))
  1199. return m_cfn.Rename(csnew.Left(csnew.ReverseFind(_T('.')))) ;
  1200. else
  1201. return m_cfn.Rename(csnew) ;
  1202. }
  1203. /******************************************************************************
  1204. CGlyphMap::AddPoints
  1205. This member adds one or more code points to the glyph map using the given
  1206. list of points and associated pages.
  1207. ******************************************************************************/
  1208. void CGlyphMap::AddPoints(CMapWordToDWord& cmw2dNew) {
  1209. WORD wKey;
  1210. DWORD dwixPage;
  1211. CWaitCursor cwc; // This could be slow!
  1212. for (POSITION pos = cmw2dNew.GetStartPosition(); pos; ) {
  1213. cmw2dNew.GetNextAssoc(pos, wKey, dwixPage);
  1214. // Get the MBCS encoding of the Unicode point as the initial
  1215. // glyph encoding.
  1216. CWordArray cwaIn;
  1217. CByteArray cbaOut;
  1218. cwaIn.Add(wKey);
  1219. pccpi->Convert(cbaOut, cwaIn, CodePage(dwixPage).Page());
  1220. // Create the glyph and add it to the map
  1221. CGlyphHandle *pcgh = new CGlyphHandle;
  1222. pcgh -> Init(cbaOut.GetData(), (unsigned) cbaOut.GetSize(), (WORD)Glyphs(),
  1223. wKey);
  1224. pcgh -> SetCodePage(dwixPage, CodePage(dwixPage).Page());
  1225. m_csmw2oEncodings[wKey] = pcgh;
  1226. m_crr.Add(pcgh);
  1227. }
  1228. Changed(); // Don't forget to tell the container!
  1229. }
  1230. /******************************************************************************
  1231. CGlyphMap::DeleteGlyph
  1232. This member function removes a glyph from the map. The most tricky part is
  1233. updating the run records, but that's not this class' responsibility, is it?
  1234. ******************************************************************************/
  1235. void CGlyphMap::DeleteGlyph(WORD wCodePoint) {
  1236. if (!m_csmw2oEncodings.RemoveKey(wCodePoint))
  1237. return; // This glyph is already toast!
  1238. m_crr.Delete(wCodePoint);
  1239. Changed();
  1240. }
  1241. /******************************************************************************
  1242. CGlyphMap::RemovePage
  1243. This member function removes a code page from the list of available pages.
  1244. Glyphs that used this page will be remapped to a second specified page.
  1245. ******************************************************************************/
  1246. BOOL CGlyphMap::RemovePage(unsigned uPage, unsigned uMapTo, bool bDelete /* bDelete = FALSE */) {
  1247. if (uPage >= CodePages() || uMapTo >= CodePages())
  1248. return FALSE;
  1249. // Pretty simple- walk the map- first replace any instances, then
  1250. // decrement any indices higher than uPage
  1251. WORD wKey;
  1252. union {
  1253. CObject* pco;
  1254. CGlyphHandle* pcgh;
  1255. };
  1256. for (POSITION pos = m_csmw2oEncodings.GetStartPosition(); pos; ) {
  1257. m_csmw2oEncodings.GetNextAssoc(pos, wKey, pco);
  1258. if (!bDelete){
  1259. if (pcgh -> CodePage() == uPage)
  1260. pcgh -> SetCodePage(uMapTo, CodePage(uMapTo).Page());
  1261. if (pcgh -> CodePage() > uPage)
  1262. pcgh -> SetCodePage(pcgh -> CodePage() - 1,
  1263. CodePage(pcgh -> CodePage()).Page());
  1264. }
  1265. else { // raid 118880
  1266. if (pcgh -> CodePage() == uPage)
  1267. DeleteGlyph(pcgh -> CodePoint() ) ; // delete m_csm2oEncodings, RunRecord
  1268. else if (pcgh -> CodePage() > uPage)
  1269. pcgh -> SetCodePage(pcgh -> CodePage() - 1,
  1270. CodePage(pcgh -> CodePage()).Page());
  1271. }
  1272. }
  1273. m_csoaCodePage.RemoveAt(uPage);
  1274. // Marke the GTT as dirty and then return success.
  1275. Changed();
  1276. return TRUE;
  1277. }
  1278. /******************************************************************************
  1279. CGlyphMap::ChangeCodePage
  1280. This member function changes the code page for one ore more glyphs to a
  1281. different page. At one time I thought remapping the code points would be
  1282. required, but currently, the Unicode stays intact. That seems a good feature
  1283. for demand-driven implementation.
  1284. ******************************************************************************/
  1285. // This one changes the code page for one or more glyphs.
  1286. // For now, we will simply keep the Unicode intact. Eventually, a query
  1287. // should be made about the intent, so we can remap through the existing
  1288. // page, if that is what is desired.
  1289. void CGlyphMap::ChangeCodePage(CPtrArray& cpaGlyphs, DWORD dwidNewPage) {
  1290. for (unsigned u = 0; u < CodePages(); u++)
  1291. if (dwidNewPage == CodePage(u).Page())
  1292. break;
  1293. _ASSERTE(u < CodePages());
  1294. if (u >= CodePages())
  1295. return;
  1296. for (int i = 0; i < cpaGlyphs.GetSize(); i++)
  1297. ((CGlyphHandle *) cpaGlyphs[i]) -> SetCodePage(u, dwidNewPage);
  1298. Changed();
  1299. }
  1300. /******************************************************************************
  1301. CGlyphMap::AddCodePage
  1302. This member function adds a new code page to the list of pages used in this
  1303. table.
  1304. ******************************************************************************/
  1305. void CGlyphMap::AddCodePage(DWORD dwidNewPage) {
  1306. m_csoaCodePage.Add(new CCodePageData(dwidNewPage));
  1307. Changed();
  1308. }
  1309. /******************************************************************************
  1310. CGlyphMap::SetPredefinedID
  1311. This changes the predefined table used by the map. If it really is a change,
  1312. we must remove all non-modified points from any existing map, and then flesh
  1313. out using the new one.
  1314. ******************************************************************************/
  1315. void CGlyphMap::UsePredefined(long lidNew) {
  1316. if (m_lidPredefined == lidNew)
  1317. return; // Didn't need to do this!
  1318. if (m_lidPredefined != NoPredefined)
  1319. UnmergePredefined(lidNew != NoPredefined);
  1320. m_lidPredefined = lidNew;
  1321. if (m_lidPredefined != NoPredefined)
  1322. MergePredefined();
  1323. Changed();
  1324. }
  1325. /******************************************************************************
  1326. CGlyphMap::SetInvocation
  1327. This member changes the invocation string for selecting or unselecting a
  1328. given code page.
  1329. ******************************************************************************/
  1330. void CGlyphMap::SetInvocation(unsigned u, LPCTSTR lpstrInvoke,
  1331. BOOL bSelect) {
  1332. CodePage(u).SetInvocation(lpstrInvoke, bSelect);
  1333. Changed();
  1334. }
  1335. /******************************************************************************
  1336. CGlyphMap::ChangeEncoding
  1337. This member is called when the user changes the encoding string used to
  1338. invoke a given code point. This could be done via the glyph, but then the
  1339. containing document won't know of the change, and thus the change could be
  1340. inadvertently lost...
  1341. ******************************************************************************/
  1342. void CGlyphMap::ChangeEncoding(WORD wCodePoint, LPCTSTR lpstrNewInvoke) {
  1343. union {
  1344. CObject *pco;
  1345. CGlyphHandle *pcgh;
  1346. };
  1347. if (!m_csmw2oEncodings.Lookup(wCodePoint, pco) || !lpstrNewInvoke||
  1348. !*lpstrNewInvoke)
  1349. return;
  1350. pcgh -> NewEncoding(lpstrNewInvoke);
  1351. Changed();
  1352. }
  1353. /******************************************************************************
  1354. CGlyphMap::ConvertCTT()
  1355. This member fuction initializes the glyphmap structure from a CTT file
  1356. ******************************************************************************/
  1357. int CGlyphMap::ConvertCTT() {
  1358. struct sCTT {
  1359. enum {Composed, Direct, Paired};
  1360. WORD m_wFormat;
  1361. BYTE m_bFirstChar, m_bLastChar;
  1362. union {
  1363. uencCTT m_uectt[1];
  1364. BYTE m_bDirect[1];
  1365. };
  1366. };
  1367. // If this map isn't empty, empty it now- at least of the glyph data
  1368. m_csmw2oEncodings.RemoveAll();
  1369. m_crr.Empty();
  1370. CByteArray cbaImage;
  1371. try {
  1372. CFile cfCTT(m_csSource, CFile::modeRead | CFile::shareDenyWrite);
  1373. cbaImage.SetSize(cfCTT.GetLength());
  1374. cfCTT.Read(cbaImage.GetData(), cfCTT.GetLength());
  1375. }
  1376. catch (CException *pce) {
  1377. pce -> ReportError();
  1378. pce -> Delete();
  1379. return IDS_FileReadError ;
  1380. }
  1381. #if 0
  1382. union {
  1383. PBYTE pbCTT;
  1384. sCTT* psctt;
  1385. };
  1386. pbCTT = cbaImage.GetData();
  1387. BYTE bFirst = min(0x20, psctt -> m_bFirstChar),
  1388. bLast = 0xFF; // Since we use a byte this is the max!
  1389. unsigned ucGlyphs = 1 + bLast - bFirst;
  1390. // Convert the code points to Unicode
  1391. CByteArray cbaCode;
  1392. CWordArray cwaCode;
  1393. for (unsigned u = 0; u < ucGlyphs; u++)
  1394. cbaCode.Add(u + bFirst);
  1395. // Convert the data to Unicode using the selected code page. This uses
  1396. // data stored from MultiByteToWideChar, so it is similar, except we can
  1397. // do this with code pages which might not be installed on the user's
  1398. // system.
  1399. if (ucGlyphs != pccpi->Convert(cbaCode, cwaCode, CodePage(0).Page())) {
  1400. CString csWork;
  1401. csWork.Format(IDS_NoUnicodePoint, u + bFirst, CodePage(0).Page());
  1402. AfxMessageBox(csWork);
  1403. return IDS_UnicodeConvFailed ;
  1404. }
  1405. // Since we add phony glyphs to the table (why, one wonders), we must mark
  1406. // them so we can manufacture equally phony encodings for them.
  1407. for (u = 0; u < ucGlyphs; u++) {
  1408. // Now, let's record the Encoding
  1409. CGlyphHandle *pcghNew = new CGlyphHandle;
  1410. unsigned uToUse = u + bFirst - psctt -> m_bFirstChar;
  1411. switch (psctt -> m_wFormat) {
  1412. case sCTT::Direct:
  1413. if (u + bFirst < psctt -> m_bFirstChar)
  1414. pcghNew -> Init((BYTE) u + bFirst, u,cwaCode[u]);
  1415. else
  1416. pcghNew -> Init(psctt -> m_bDirect[uToUse], u, cwaCode[u]);
  1417. break;
  1418. case sCTT::Paired:
  1419. if (u + bFirst < psctt -> m_bFirstChar)
  1420. pcghNew -> Init((BYTE) u + bFirst, u, cwaCode[u]);
  1421. else
  1422. if (psctt -> m_uectt[uToUse].abPaired[1])
  1423. pcghNew -> Init(psctt -> m_uectt[uToUse].abPaired, u,
  1424. cwaCode[u]);
  1425. else
  1426. pcghNew -> Init(psctt -> m_uectt[uToUse].abPaired[0],
  1427. u, cwaCode[u]);
  1428. break;
  1429. case sCTT::Composed:
  1430. if (u + bFirst < psctt -> m_bFirstChar) {
  1431. BYTE bMe = u + bFirst;
  1432. pcghNew -> Init(&bMe, 1, u, cwaCode[u]);
  1433. }
  1434. else
  1435. pcghNew -> Init(pbCTT + psctt -> m_uectt[uToUse].wOffset,
  1436. psctt -> m_uectt[uToUse + 1].wOffset -
  1437. psctt -> m_uectt[uToUse].wOffset, u, cwaCode[u]);
  1438. break;
  1439. default: // Don't accept anything else!
  1440. AfxMessageBox(IDS_InvalidCTTFormat);
  1441. return IDS_Invalid2CTTFormat ;
  1442. } // One map entry coded
  1443. // Code page index inits OK, but must know the page
  1444. pcghNew -> SetCodePage(0, DefaultCodePage());
  1445. m_csmw2oEncodings[cwaCode[u]] = pcghNew;
  1446. m_crr.Add(pcghNew);
  1447. } // Loop of generating entries
  1448. m_bPaired = sCTT::Paired == psctt -> m_wFormat;
  1449. #else
  1450. {
  1451. HANDLE hheap;
  1452. PBYTE pbCTT;
  1453. UNI_GLYPHSETDATA *pGTT;
  1454. pbCTT = cbaImage.GetData();
  1455. if( !(hheap = HeapCreate(HEAP_NO_SERIALIZE, 10 * 1024, 256 * 1024 )))
  1456. {
  1457. char acMessage[256];
  1458. wsprintf(acMessage, "HeapCreate() fails in ctt2gtt" );
  1459. MessageBox(NULL, acMessage, NULL, MB_OK);
  1460. return IDS_HeapCFailed ;
  1461. }
  1462. //if (!BConvertCTT2GTT(hheap, (PTRANSTAB)pbCTT, DefaultCodePage(), 0x20,
  1463. ASSERT(m_pcdOwner != NULL) ;
  1464. DWORD dw = ((CProjectRecord*) m_pcdOwner)->GetDefaultCodePageNum() ;
  1465. if (!BConvertCTT2GTT(hheap, (PTRANSTAB)pbCTT, dw, 0x20, 0xff, NULL,
  1466. NULL, &pGTT, 0)){
  1467. HeapDestroy(hheap); // raid 116619 prefix
  1468. return IDS_ConvCTTFailed ;
  1469. }
  1470. try {
  1471. CFile cfGTT;
  1472. if (!cfGTT.Open(m_cfn.FullName(), CFile::modeCreate | CFile::modeWrite |
  1473. CFile::shareExclusive))
  1474. return IDS_FileWriteError;
  1475. cfGTT.Write(pGTT, pGTT->dwSize);
  1476. }
  1477. catch (CException *pce) {
  1478. pce -> ReportError();
  1479. pce -> Delete();
  1480. HeapDestroy(hheap);
  1481. return IDS_FileWriteError ;
  1482. }
  1483. HeapDestroy(hheap);
  1484. }
  1485. Load();
  1486. #endif
  1487. return 0 ;
  1488. }
  1489. /******************************************************************************
  1490. CGlyphMap::Load()
  1491. This initializes the glyphmap from a GTT format file. Since this is the
  1492. primary means of loading, it requires no parameters.
  1493. ******************************************************************************/
  1494. BOOL CGlyphMap::Load(LPCTSTR lpstrName /*= NULL*/) {
  1495. // Note the correct name and path- the rename checks may fail, since the
  1496. // file is opened elsewhere (possibly with sharing conflicts), so disable
  1497. // them, for now. This code is a little sleazy- but the only time the
  1498. // file name isn't null is if the file's being opened.
  1499. if (FileTitle().IsEmpty() && lpstrName) {
  1500. m_cfn.EnableCreationCheck(FALSE);
  1501. SetFileName(lpstrName);
  1502. m_cfn.EnableCreationCheck();
  1503. }
  1504. if (Glyphs()) { // If we already have them, we're already loaded!
  1505. m_csoaCodePage.RemoveAll(); // Clean it all up, and reload.
  1506. m_csmw2oEncodings.RemoveAll();
  1507. m_crr.Empty();
  1508. }
  1509. CByteArray cbaGTT;
  1510. union {
  1511. PBYTE pbGTT;
  1512. sGTTHeader *psgtth;
  1513. };
  1514. Load(cbaGTT); // If this fails, it will post a reason why
  1515. if (!cbaGTT.GetSize())
  1516. return FALSE;
  1517. pbGTT = cbaGTT.GetData();
  1518. sMapTable* psmt = (sMapTable *) (pbGTT + psgtth -> m_dwofMapTable);
  1519. sMapTableEntry* psmte = (sMapTableEntry *)(psmt + 1);
  1520. // Before we go any further, let's do some validation
  1521. if (psgtth -> m_dwVersion != sGTTHeader::Version1Point0)
  1522. return FALSE;
  1523. m_bPaired = FALSE;
  1524. // First, let's snarf up the code page info
  1525. struct sInvocation {
  1526. DWORD m_dwSize, m_dwOffset;
  1527. };
  1528. struct sCodePageInfo {
  1529. DWORD m_dwPage;
  1530. sInvocation m_siSelect, m_siDeselect;
  1531. } *psci = (sCodePageInfo *)(pbGTT + psgtth -> m_dwofCodePages);
  1532. m_csoaCodePage.RemoveAll();
  1533. for (unsigned u = 0; u < psgtth -> m_dwcCodePages; u++, psci++) {
  1534. m_csoaCodePage.Add(new CCodePageData(psci -> m_dwPage));
  1535. if (!psci -> m_siSelect.m_dwSize != !psci -> m_siSelect.m_dwOffset ||
  1536. !psci -> m_siDeselect.m_dwSize !=
  1537. !psci -> m_siDeselect.m_dwOffset)
  1538. return FALSE; // The data is bogus!
  1539. CodePage(u).SetInvocation(((PBYTE) psci) + psci->m_siSelect.m_dwOffset,
  1540. psci -> m_siSelect.m_dwSize, TRUE);
  1541. CodePage(u).SetInvocation(((PBYTE) psci) + psci->m_siDeselect.m_dwOffset,
  1542. psci -> m_siDeselect.m_dwSize, FALSE);
  1543. //CodePage(u).SetInvocation(pbGTT + psci -> m_siSelect.m_dwOffset,
  1544. // psci -> m_siSelect.m_dwSize, TRUE);
  1545. //CodePage(u).SetInvocation(pbGTT + psci -> m_siDeselect.m_dwOffset,
  1546. // psci -> m_siDeselect.m_dwSize, FALSE);
  1547. }
  1548. // Next, we need to walk the glyph run tables to decipher and use the map
  1549. // table.
  1550. struct sGlyphRun {
  1551. WORD m_wFirst, m_wc;
  1552. } *psgr = (sGlyphRun *)(pbGTT + psgtth -> m_dwofRuns);
  1553. _ASSERTE(psgtth -> m_dwcGlyphs == psmt -> m_dwcEntries);
  1554. WORD wIndex = 0;
  1555. /*** Changes have been made so that the following code is unneeded.
  1556. The MDT can load predefined GTTs now. In addition, skipping
  1557. the complete loading of these GTTs causes some problems with
  1558. UFM width table loading. The cumulative count of entries in
  1559. the glyph run tables is used to determine the maximum size of
  1560. the UFMs width table. The data in the run tables is also used
  1561. to verify width table entries.
  1562. // Don't do the rest if a predefined GTT is being loaded. The code below
  1563. // can blow on large GTTs; eg, the DBCS ones. It may be better to find out
  1564. // why the code blows but this seems to work for now.
  1565. if ((short) m_wID >= CGlyphMap::Wansung
  1566. && (short) m_wID <= CGlyphMap::CodePage437)
  1567. return TRUE ;
  1568. */
  1569. for (unsigned uRun = 0; uRun < psgtth -> m_dwcRuns; uRun++, psgr++)
  1570. for (u = 0; u < psgr -> m_wc; u++, psmte++, wIndex++) {
  1571. CGlyphHandle* pcgh = new CGlyphHandle;
  1572. switch (psmte -> m_bfType & sMapTableEntry::Format) {
  1573. case sMapTableEntry::Direct:
  1574. pcgh -> Init((PBYTE) &psmte -> m_uectt, 1, wIndex,
  1575. psgr -> m_wFirst + u);
  1576. break;
  1577. case sMapTableEntry::Paired:
  1578. pcgh -> Init(psmte -> m_uectt.abPaired, wIndex,
  1579. psgr -> m_wFirst + u);
  1580. if (!(psmte -> m_bfType & sMapTableEntry::DBCS))
  1581. m_bPaired = TRUE;
  1582. break;
  1583. case sMapTableEntry::Composed:
  1584. pcgh -> Init(pbGTT + psgtth -> m_dwofMapTable +
  1585. psmte -> m_uectt.wOffset + sizeof wIndex,
  1586. *(PWORD) (pbGTT + psgtth -> m_dwofMapTable +
  1587. psmte -> m_uectt.wOffset), wIndex,
  1588. psgr -> m_wFirst + u);
  1589. break;
  1590. default: // Bad news- bad format
  1591. delete pcgh; // No orphans needed!
  1592. return FALSE;
  1593. }
  1594. // Don't forget the code page ID!
  1595. pcgh -> SetCodePage(psmte -> m_bCodePageIndex,
  1596. CodePage(psmte -> m_bCodePageIndex).Page());
  1597. // Mark this if it is to be disabled.
  1598. if (psmte -> m_bfType & sMapTableEntry::Disable)
  1599. pcgh -> SetPredefined(CGlyphHandle::Removed);
  1600. m_csmw2oEncodings[psgr -> m_wFirst + u] = pcgh;
  1601. m_crr.Add(pcgh);
  1602. }
  1603. // If we're predefined, Merge now.
  1604. m_lidPredefined = psgtth -> m_lidPredefined;
  1605. if (m_lidPredefined != NoPredefined)
  1606. MergePredefined();
  1607. return TRUE; // We actually did it!
  1608. }
  1609. /******************************************************************************
  1610. CGlyphMap::RLE
  1611. This generates an RLE-format file image of the glyph map.
  1612. ******************************************************************************/
  1613. BOOL CGlyphMap::RLE(CFile& cfTarget) {
  1614. sRLE srle;
  1615. srle.m_widRLE = 0x78FE;
  1616. srle.m_wcFirst = m_crr.First();
  1617. srle.m_wcLast = m_crr.Last();
  1618. srle.m_dwFlag = 0;
  1619. srle.m_dwcGlyphs = m_csmw2oEncodings.GetCount();
  1620. srle.m_dwcRuns = m_crr.RunCount();
  1621. srle.m_dwcbImage = 4 * sizeof srle.m_dwcbImage + srle.m_dwcRuns *
  1622. m_crr.Size();
  1623. srle.m_dwcbThis = srle.m_dwcbImage + 3 * sizeof srle.m_dwcbThis +
  1624. srle.m_dwcGlyphs * sizeof srle.m_dwcGlyphs;
  1625. // Determine the correct format, and thus the RLE size
  1626. if (!m_crr.MustCompose())
  1627. srle.m_wFormat = m_bPaired ? sRLE::Paired : sRLE::Direct;
  1628. else
  1629. if (srle.m_dwcGlyphs < 256 &&
  1630. srle.m_dwcbThis + m_crr.ExtraNeeded() <= 0xffff) {
  1631. srle.m_dwcbThis += m_crr.ExtraNeeded();
  1632. srle.m_wFormat = sRLE::LengthIndexOffset;
  1633. }
  1634. else {
  1635. srle.m_dwcbThis += m_crr.ExtraNeeded(FALSE);
  1636. srle.m_wFormat = sRLE::LengthOffset;
  1637. }
  1638. // We now need to feed the offset information down to the lower level
  1639. // classes, so that they are prepared to render their information to
  1640. // the target file.
  1641. // The first items encoded are the runs, which immediately follow the RLE
  1642. // header.
  1643. DWORD dwOffset = sizeof srle + srle.m_dwcRuns * m_crr.Size();
  1644. m_crr.NoteOffset(dwOffset, TRUE, m_bPaired);
  1645. // If this requires extra data, it will be appearing after the FD_GLYPHSET
  1646. if (srle.m_wFormat == sRLE::LengthOffset ||
  1647. srle.m_wFormat == sRLE::LengthIndexOffset)
  1648. m_crr.NoteExtraOffset(dwOffset,
  1649. srle.m_wFormat == sRLE::LengthIndexOffset);
  1650. _ASSERTE(dwOffset == srle.m_dwcbThis);
  1651. // We've got our data, we've got our file, and we've got a job to do.
  1652. // Hop to it!
  1653. try {
  1654. cfTarget.Write(&srle, sizeof srle);
  1655. m_crr.WriteSelf(cfTarget);
  1656. m_crr.WriteHandles(cfTarget, srle.m_wFormat);
  1657. m_crr.WriteEncodings(cfTarget, srle.m_wFormat == sRLE::LengthOffset ?
  1658. CGlyphHandle::RLEBig : CGlyphHandle::RLESmall);
  1659. }
  1660. catch (CException *pce) {
  1661. pce -> ReportError();
  1662. pce -> Delete();
  1663. return FALSE;
  1664. }
  1665. return TRUE;
  1666. }
  1667. /******************************************************************************
  1668. CGlyphMap::Glyph
  1669. I tried to do this in the header, file but that lets it be in-line, and I
  1670. don't want to export CRunRecord.
  1671. ******************************************************************************/
  1672. CGlyphHandle* CGlyphMap::Glyph(unsigned u) {
  1673. return m_crr.GetGlyph(u);
  1674. }
  1675. /******************************************************************************
  1676. CGlyphMap::CreateEditor
  1677. This member function overrides the CProjectNode function to create a new
  1678. CGlyphMapContainer document embedding this Glyph Map. It then uses the
  1679. appropriate document template to open a view on this document.
  1680. ******************************************************************************/
  1681. CMDIChildWnd *CGlyphMap::CreateEditor() {
  1682. CGlyphMapContainer* pcgmcMe= new CGlyphMapContainer(this, FileName());
  1683. // Make up a cool title
  1684. pcgmcMe -> SetTitle(m_pcbnWorkspace -> Name() + _TEXT(": ") + Name());
  1685. CMDIChildWnd *pcmcwNew = (CMDIChildWnd *) m_pcmdt ->
  1686. CreateNewFrame(pcgmcMe, NULL);
  1687. if (pcmcwNew) {
  1688. m_pcmdt -> InitialUpdateFrame(pcmcwNew, pcgmcMe, TRUE);
  1689. m_pcmdt -> AddDocument(pcgmcMe);
  1690. }
  1691. return pcmcwNew;
  1692. }
  1693. /******************************************************************************
  1694. CGlyphMap::Generate
  1695. This member function generates the GTT format image of the current data.
  1696. It returns a BOOL indicating success or failure.
  1697. ******************************************************************************/
  1698. BOOL CGlyphMap::Generate(CFile& cfGTT) {
  1699. sGTTHeader sgtth;
  1700. // First, take care of any predefined stuff, if we have to
  1701. if (m_lidPredefined != NoPredefined)
  1702. UnmergePredefined(TRUE);
  1703. sgtth.m_dwcGlyphs = Glyphs();
  1704. sgtth.m_dwcRuns = m_crr.RunCount();
  1705. sgtth.m_dwcCodePages = CodePages();
  1706. sgtth.m_lidPredefined = m_lidPredefined;
  1707. // The run table is the first item after the header, so add in its size
  1708. sgtth.m_dwofRuns = sgtth.m_dwcbImage; // Runs are first item
  1709. sgtth.m_dwcbImage += sgtth.m_dwcRuns * m_crr.Size(FALSE);
  1710. sgtth.m_dwofCodePages = sgtth.m_dwcbImage; // Code pages are next
  1711. // Code page selection strings immediately follow the Code page structures
  1712. // The code page information size must be padded to a DWORD multiple
  1713. sgtth.m_dwcbImage += sgtth.m_dwcCodePages * CodePage(0).Size();
  1714. DWORD dwPadding ; // # of padding bytes needed to DWORD align map table
  1715. DWORD dwSelOffset ; // Offset from each CODEPAGEINFO to sel/desel strings
  1716. DWORD dwSelBytes ; // Total # of bytes used by sel/desel strings
  1717. dwSelOffset = sgtth.m_dwcbImage - sgtth.m_dwofCodePages ;
  1718. for (unsigned u = 0 ; u < CodePages() ; u++) {
  1719. CodePage(u).NoteOffsets(dwSelOffset) ;
  1720. dwSelOffset -= CodePage(0).Size() ;
  1721. } ;
  1722. // Save the amount of padding, as we'll write it later. It is also needed
  1723. // as part of the computation for the mapping table offset.
  1724. dwPadding = dwSelOffset + sgtth.m_dwcbImage ;
  1725. dwPadding = (sizeof(DWORD) -
  1726. (dwPadding & (sizeof(DWORD) - 1))) & (sizeof(DWORD) - 1) ;
  1727. // Compute the number of bytes used for the sel/desel strings and pad. Then
  1728. // add this count to the image count of bytes so that it can be used to set
  1729. // the mapping table offset.
  1730. dwSelBytes = dwSelOffset + dwPadding ;
  1731. sgtth.m_dwcbImage += dwSelBytes;
  1732. sgtth.m_dwofMapTable = sgtth.m_dwcbImage;
  1733. TRACE("***CGlyphMap::Generate() - dwPadding = %d, dwSelBytes = %d, m_dwofMapTable = 0x%x\n", dwPadding, dwSelBytes, sgtth.m_dwofMapTable) ;
  1734. // Map Table size determination
  1735. sMapTable smt(Glyphs());
  1736. // Fortunately for us, the following not only preps the data, it also
  1737. // updates the image size for us
  1738. if (m_crr.MustCompose())
  1739. m_crr.NoteOffset(smt.m_dwcbImage, FALSE, m_bPaired);
  1740. // Final Size calculation
  1741. sgtth.m_dwcbImage += smt.m_dwcbImage;
  1742. // Now, we just write it out
  1743. try {
  1744. cfGTT.Write(&sgtth, sizeof sgtth); // Header
  1745. ASSERT(sgtth.m_dwofRuns == cfGTT.GetPosition()) ;
  1746. m_crr.WriteSelf(cfGTT, FALSE); // Glyph Runs
  1747. ASSERT(sgtth.m_dwofCodePages == cfGTT.GetPosition()) ;
  1748. for (unsigned u = 0; u < CodePages(); u++)
  1749. CodePage(u).WriteSelf(cfGTT); // Code page structures
  1750. for (u = 0; u < CodePages(); u++)
  1751. CodePage(u).WriteInvocation(cfGTT); // Code page invocations
  1752. // Pad with 0's to DWORD align the mapping table
  1753. dwSelBytes = 0 ;
  1754. cfGTT.Write((LPSTR) &dwSelBytes, dwPadding) ;
  1755. // Do the map table, and we are finished!
  1756. ASSERT(sgtth.m_dwofMapTable == cfGTT.GetPosition()) ;
  1757. cfGTT.Write(&smt, sizeof smt);
  1758. m_crr.WriteMapTable(cfGTT, m_lidPredefined != NoPredefined);
  1759. m_crr.WriteEncodings(cfGTT, CGlyphHandle::GTT);
  1760. }
  1761. catch (CException * pce) {
  1762. // Take care of any predefined stuff, if we have to
  1763. if (m_lidPredefined != NoPredefined)
  1764. MergePredefined();
  1765. // Feedback- something broke when it shouldn't have
  1766. pce -> ReportError();
  1767. pce -> Delete();
  1768. return FALSE;
  1769. }
  1770. // Take care of any predefined stuff, if we have to
  1771. if (m_lidPredefined != NoPredefined)
  1772. MergePredefined();
  1773. Changed(FALSE);
  1774. return TRUE;
  1775. }
  1776. /******************************************************************************
  1777. CGlyphMapContainer class - this encases the glyph table UI when it is either
  1778. embedded in the driver, or loaded directly from the GTT
  1779. ******************************************************************************/
  1780. /******************************************************************************
  1781. CGlyphMapContainer::CGlyphMapContainer()
  1782. This default constructor is used whenever dynamic creation is used, which is
  1783. most MFC usages of the document system. It starts with an empty glyph map.
  1784. ******************************************************************************/
  1785. IMPLEMENT_DYNCREATE(CGlyphMapContainer, CDocument)
  1786. CGlyphMapContainer::CGlyphMapContainer()
  1787. {
  1788. m_pcgm = new CGlyphMap;
  1789. m_pcgm -> NoteOwner(*this);
  1790. m_bSaveSuccessful = m_bEmbedded = FALSE;
  1791. }
  1792. /******************************************************************************
  1793. CGlyphMapContainer:CGlyphMapContainer(CGlyphMap *pvgm, CString csPath)
  1794. This constructor override is used when we create a CGlyphMapContainer
  1795. document from the driver/project level editor. In this case, a digested
  1796. map is passed, so no additional I/O us needed.
  1797. ******************************************************************************/
  1798. CGlyphMapContainer::CGlyphMapContainer(CGlyphMap *pcgm, CString csPath)
  1799. {
  1800. m_pcgm = pcgm;
  1801. SetPathName(csPath, FALSE);
  1802. m_bEmbedded = TRUE;
  1803. m_bSaveSuccessful = FALSE;
  1804. m_pcgm -> NoteOwner(*this); // This is the document being edited!
  1805. }
  1806. BOOL CGlyphMapContainer::OnNewDocument() {
  1807. return CDocument::OnNewDocument();
  1808. }
  1809. CGlyphMapContainer::~CGlyphMapContainer() {
  1810. if (!m_bEmbedded && m_pcgm)
  1811. delete m_pcgm;
  1812. }
  1813. BEGIN_MESSAGE_MAP(CGlyphMapContainer, CDocument)
  1814. //{{AFX_MSG_MAP(CGlyphMapContainer)
  1815. // NOTE - the ClassWizard will add and remove mapping macros here.
  1816. //}}AFX_MSG_MAP
  1817. END_MESSAGE_MAP()
  1818. /////////////////////////////////////////////////////////////////////////////
  1819. // CGlyphMapContainer diagnostics
  1820. #ifdef _DEBUG
  1821. void CGlyphMapContainer::AssertValid() const {
  1822. CDocument::AssertValid();
  1823. }
  1824. void CGlyphMapContainer::Dump(CDumpContext& dc) const {
  1825. CDocument::Dump(dc);
  1826. }
  1827. #endif //_DEBUG
  1828. /////////////////////////////////////////////////////////////////////////////
  1829. // CGlyphMapContainer serialization
  1830. void CGlyphMapContainer::Serialize(CArchive& ar) {
  1831. if (ar.IsStoring()) {
  1832. // TODO: add storing code here
  1833. }
  1834. else {
  1835. // TODO: add loading code here
  1836. }
  1837. }
  1838. /////////////////////////////////////////////////////////////////////////////
  1839. // CGlyphMapContainer commands
  1840. BOOL CGlyphMapContainer::OnSaveDocument(LPCTSTR lpszPathName) {
  1841. // We save via the glyph map's Generate function.
  1842. CFile cfGTT;
  1843. if (!cfGTT.Open(lpszPathName, CFile::modeCreate | CFile::modeWrite |
  1844. CFile::shareExclusive))
  1845. return FALSE;
  1846. m_bSaveSuccessful = m_pcgm -> Generate(cfGTT) ;
  1847. // Update the save timestamp. This is done here so that other user of the
  1848. // Generate() function don't update the timestamp.
  1849. m_pcgm->m_ctSaveTimeStamp = CTime::GetCurrentTime() ;
  1850. // when open mutiple workspace, last of the pos is the workspace conating current GTT or UFM
  1851. CDriverResources * pcpr =(CDriverResources *) m_pcgm->GetWorkspace() ;
  1852. if (m_pcgm->ChngedCodePt() && pcpr ) {// && m_pcgm->Glyphs() <= 1000 ) {
  1853. pcpr->SyncUFMWidth() ;
  1854. }
  1855. return m_bSaveSuccessful ;
  1856. }
  1857. /******************************************************************************
  1858. CGlyphMapContainer::OnOpenDocument
  1859. This overrides the typical MFC open document action, which is to open the
  1860. document by serialization. Instead, we use the CGlyphMap Load override for
  1861. the GTT format to initialize the GlyphMap.
  1862. ******************************************************************************/
  1863. BOOL CGlyphMapContainer::OnOpenDocument(LPCTSTR lpstrFile)
  1864. {
  1865. return m_pcgm->Load(lpstrFile) ;
  1866. }
  1867. /******************************************************************************
  1868. CGlyphMapContainer::SaveModified
  1869. The document is about to close. If the GTT was changed by the user but the
  1870. user does not want to save the changes, the user wants to close the GTT, and
  1871. the GTT was loaded from a workspace, then reload the GTT so that the changes
  1872. are removed from the in memory copy of the GTT. This keeps those "discarded"
  1873. changes from being displayed the next time the GTT is edited.
  1874. Return TRUE if it is ok for the doc to close. Otherwise, FALSE.
  1875. ******************************************************************************/
  1876. BOOL CGlyphMapContainer::SaveModified()
  1877. {
  1878. // Get a pointer to the associate view class instance and use it to make
  1879. // sure the code page select/deselect strings are copied into the GTT.
  1880. POSITION pos = GetFirstViewPosition() ;
  1881. ASSERT(pos != NULL) ;
  1882. CGlyphMapView* pcgmv = (CGlyphMapView*) GetNextView(pos) ;
  1883. pcgmv->SaveBothSelAndDeselStrings() ;
  1884. // Find out if the document was modified and if the user wants to save it.
  1885. m_bSaveSuccessful = FALSE ;
  1886. BOOL bmodified = IsModified() ;
  1887. BOOL bcloseok = CDocument::SaveModified() ;
  1888. // If the GTT was loaded from a workspace, the GTT was changed, the user
  1889. // does NOT want to save the changes, and he does want to close the doc,
  1890. // then reload the GTT.
  1891. if (m_bEmbedded && bmodified && bcloseok && !m_bSaveSuccessful)
  1892. m_pcgm->Load() ;
  1893. // Return flag indicating if it is ok to close the doc.
  1894. return bcloseok ;
  1895. }