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

/******************************************************************************
Source File: Glyph Translation.CPP
This implements the classes which encode glyph mapping information.
Copyright (c) 1997 by Microsoft Corporation. All rights reserved.
A Pretty Penny Enterprises Production
Change History:
02-13-97 [email protected]
******************************************************************************/
#include "StdAfx.H"
#include "Resource.H"
// Psuedo definition of DESIGNVECTOR.
#if (_WIN32_WINNT < 0x0500)
typedef unsigned long DESIGNVECTOR;
#endif
#include "GTT.H"
#include <CodePage.H>
#include <wingdi.h>
#include <winddi.h>
#include <prntfont.h>
#include <uni16res.h>
#define _FMNEWFM_H_
#include "ProjRec.h"
#include "ChildFrm.H"
#include "GTTView.H"
#include "minidev.h"
extern "C"
BOOL
BConvertCTT2GTT(
IN HANDLE hHeap,
IN PTRANSTAB pCTTData,
IN DWORD dwCodePage,
IN WCHAR wchFirst,
IN WCHAR wchLast,
IN PBYTE pCPSel,
IN PBYTE pCPUnSel,
IN OUT PUNI_GLYPHSETDATA *ppGlyphSetData,
IN DWORD dwGlySize);
extern "C"
PUNI_GLYPHSETDATA
PGetDefaultGlyphset(
IN HANDLE hHeap,
IN WORD wFirstChar,
IN WORD wLastChar,
IN DWORD dwCodePage) ;
struct sRLE {
enum {Direct = 10, Paired, LengthOffset, LengthIndexOffset, Offset};
WORD m_wFormat;
WORD m_widRLE; // Must have unique "magic" value 0x78FE
DWORD m_dwcbThis; // Total size of the memory image.
WCHAR m_wcFirst, m_wcLast;
// Handle mapping data follows
DWORD m_dwcbImage; // Size of the handle mapping data only
DWORD m_dwFlag;
DWORD m_dwcGlyphs, m_dwcRuns;
};
union uencCTT {
WORD wOffset;
BYTE m_bDirect; // This member is used in GTT only!
BYTE abPaired[2];
};
struct sMapTableEntry {
enum {Composed = 1, Direct = 2, Paired = 4, Format = 7, SingleByte,
DoubleByte = 0x10, DBCS = 0x18, Replace = 0x20, Add = 0x40,
Disable = 0x80, PredefinedMask = 0xE0};
BYTE m_bCodePageIndex, m_bfType;
uencCTT m_uectt;
};
// Since I don't build the map table in memory, there is no need to declare
// the fact that the array of entries follows it
struct sMapTable {
DWORD m_dwcbImage, m_dwcEntries;
sMapTable(unsigned ucEntries) {
m_dwcbImage = sizeof *this + ucEntries * sizeof (sMapTableEntry);
m_dwcEntries = ucEntries; }
};
// Use a static for Code Page information- gets the max benefit from caching
static CCodePageInformation* pccpi = NULL ; // Use a static CCodePageInformation to derive more benefit from caching
/******************************************************************************
CInvocation class implementation
******************************************************************************/
IMPLEMENT_SERIAL(CInvocation, CObject, 0)
void CInvocation::Encode(BYTE c, CString& cs) const {
if (isprint(c))
if (c != _TEXT('\\'))
cs = c;
else
cs = _TEXT("\\\\");
else
cs.Format(_TEXT("\\x%2.2x"), c);
}
/******************************************************************************
CInvocation::Init
This copies a series of bytes into the invocation. Since the data structures
used to represent these lend themselves most readily to this, this is the
normal method used in reading info from a file.
******************************************************************************/
void CInvocation::Init(PBYTE pb, unsigned ucb) {
m_cbaEncoding.RemoveAll();
while (ucb--)
m_cbaEncoding.Add(*pb++);
}
void CInvocation::GetInvocation(CString& cs) const {
CString csWork;
cs.Empty();
for (int i = 0; i < m_cbaEncoding.GetSize(); i++) {
Encode(m_cbaEncoding[i], csWork);
cs += csWork;
}
}
// This member converts a C-Style encoding of an invocation into
// byte form and stores it.
void CInvocation::SetInvocation(LPCTSTR lpstrNew) {
CString csWork(lpstrNew);
m_cbaEncoding.RemoveAll();
while (!csWork.IsEmpty()) {
CString csClean = csWork.SpanExcluding("\\");
if (!csClean.IsEmpty()) {
for (int i = 0; i < csClean.GetLength(); i++)
m_cbaEncoding.Add((BYTE) csClean[i]);
csWork = csWork.Mid(csClean.GetLength());
continue;
}
// A backslash has been found. If the string ends with a backslash, we
// can't let the function assert in the switch statement so just return
// and ignore the terminating backslash. Yes, I know the string is
// invalid if it ends this way but, according to MS, this isn't a field
// they want validated.
if (csWork.GetLength() <= 1)
return ;
// OK, we have something to decode
switch (csWork[1]) {
case _TEXT('r'):
m_cbaEncoding.Add(13);
csWork = csWork.Mid(2);
continue;
case _TEXT('n'):
m_cbaEncoding.Add(10);
csWork = csWork.Mid(2);
continue;
case _TEXT('b'):
m_cbaEncoding.Add('\b');
csWork = csWork.Mid(2);
continue;
case _TEXT('\t'):
m_cbaEncoding.Add(9);
csWork = csWork.Mid(2);
continue;
case _TEXT('x'):
case _TEXT('X'):
{
CString csNumber = csWork.Mid(2,2).SpanIncluding(
_TEXT("1234567890abcdefABCDEF"));
csWork = csWork.Mid(2 + csNumber.GetLength());
unsigned u;
#if defined(UNICODE) || defined(_UNICODE)
#define _tsscanf swscanf
#else
#define _tsscanf sscanf
#endif
_tsscanf(csNumber, _TEXT("%x"), &u);
m_cbaEncoding.Add((BYTE)u);
continue;
}
// TODO: octal encodings are pretty common
default:
m_cbaEncoding.Add(
(BYTE) csWork[(int)(csWork.GetLength() != 1)]);
csWork = csWork.Mid(2);
continue;
}
}
// We've done it!
}
// This member function records the offset for its image (if any) and updates
// the given offset to reflect this
void CInvocation::NoteOffset(DWORD& dwOffset) {
m_dwOffset = Length() ? dwOffset : 0;
dwOffset += Length();
}
// I/O routines, both native and document form
void CInvocation::WriteSelf(CFile& cfTarget) const {
DWORD dwWork = Length();
cfTarget.Write(&dwWork, sizeof dwWork);
cfTarget.Write(&m_dwOffset, sizeof m_dwOffset);
}
void CInvocation::WriteEncoding(CFile& cfTarget, BOOL bWriteLength) const {
if (bWriteLength) {
WORD w = (WORD)Length();
cfTarget.Write(&w, sizeof w);
}
cfTarget.Write(m_cbaEncoding.GetData(), Length());
}
void CInvocation::Serialize(CArchive& car) {
CObject::Serialize(car);
m_cbaEncoding.Serialize(car);
}
/******************************************************************************
CGlyphHandle class implementation
******************************************************************************/
CGlyphHandle::CGlyphHandle()
{
m_wPredefined = m_wIndex = 0;
m_dwCodePage = m_dwidCodePage = m_dwOffset = 0;
// Allocate a CCodePageInformation class if needed.
if (pccpi == NULL)
pccpi = new CCodePageInformation ;
}
unsigned CGlyphHandle::CompactSize() const {
return (m_ciEncoding.Length() < 3) ? 0 : m_ciEncoding.Length();
}
/******************************************************************************
CGlyphHandle::operator ==
Returns true if the encoding, code point, and code page IDs (but maybe not
the indices) are the same.
******************************************************************************/
BOOL CGlyphHandle::operator ==(CGlyphHandle& cghRef) {
if (cghRef.m_wCodePoint != m_wCodePoint ||
cghRef.m_dwCodePage != m_dwCodePage ||
m_ciEncoding.Length() != cghRef.m_ciEncoding.Length())
return FALSE;
for (int i = 0; i < (int) m_ciEncoding.Length(); i++)
if (m_ciEncoding[i] != cghRef.m_ciEncoding[i])
return FALSE;
return TRUE;
}
/******************************************************************************
CGlyphHandle::Init
This function has three overloads, for intializing from direc, paired, or
composed data.
******************************************************************************/
void CGlyphHandle::Init(BYTE b, WORD wIndex, WORD wCode) {
m_wIndex = wIndex;
m_wCodePoint = wCode;
m_ciEncoding.Init(&b, 1);
}
void CGlyphHandle::Init(BYTE ab[2], WORD wIndex, WORD wCode) {
m_wIndex = wIndex;
m_wCodePoint = wCode;
m_ciEncoding.Init(ab, 2);
}
void CGlyphHandle::Init(PBYTE pb, unsigned ucb, WORD wIndex, WORD wCode) {
m_wIndex = wIndex;
m_wCodePoint = wCode;
m_ciEncoding.Init(pb, ucb);
}
/******************************************************************************
CGlyphHandle::operator =
This is a copy (assignment) operator for the class.
******************************************************************************/
CGlyphHandle& CGlyphHandle::operator =(CGlyphHandle& cghTemplate) {
m_dwCodePage = cghTemplate.m_dwCodePage;
m_dwidCodePage = cghTemplate.m_dwidCodePage;
m_wCodePoint = cghTemplate.m_wCodePoint;
m_ciEncoding = cghTemplate.m_ciEncoding;
return *this;
}
// This member records the current offset for the data in RLE format, and
// then updates it to account for the length of any data that will go into
// the extra storage at the end of the file/
void CGlyphHandle::RLEOffset(DWORD& dwOffset, const BOOL bCompact) {
if (m_ciEncoding.Length() < 3)
return; // Don't need it, and don't use it!
m_dwOffset = dwOffset;
dwOffset += bCompact ? CompactSize() : MaximumSize();
}
/******************************************************************************
CGlyphHandle::GTTOffset
This member records the current offset for where our data will go, then adds
the length of the encoding string to it and updates the offset. It will only
be updated if the encoding must be composed data. The encoding length
includes a WORD length in the GTT world. Data of 1 byte, or of 2 if DBCS or
a Paired font, does not add any length.
******************************************************************************/
void CGlyphHandle::GTTOffset(DWORD& dwOffset, BOOL bPaired) {
if (m_ciEncoding.Length() >
(unsigned) 1 + (bPaired || pccpi->IsDBCS(m_dwCodePage))) {
m_dwOffset = dwOffset;
dwOffset += m_ciEncoding.Length() + sizeof m_wIndex;
}
else
m_dwOffset = 0;
}
// These members write our vital stuff to a given file.
void CGlyphHandle::WriteRLE(CFile& cfTarget, WORD wFormat) const {
// This is the RLE-specific glyph handle encoding
union {
DWORD dwOffset;
struct {
union {
struct {
BYTE bFirst, bSecond;
};
WORD wOffset;
};
union {
struct {
BYTE bIndexOrHiOffset, bLength;
};
WORD wIndex;
};
};
};
switch (wFormat) {
case sRLE::Direct:
case sRLE::Paired:
bFirst = m_ciEncoding[0];
bSecond = m_ciEncoding[1];
wIndex = m_wIndex;
break;
case sRLE::LengthIndexOffset:
if (!CompactSize()) { // Encode it in the first two bytes
bFirst = m_ciEncoding[0];
bSecond = m_ciEncoding[1];
}
else
wOffset = (WORD) m_dwOffset;
bIndexOrHiOffset = (BYTE) m_wIndex;
bLength = (BYTE)m_ciEncoding.Length();
break;
case sRLE::LengthOffset:
if (!CompactSize()) { // Encode it in the first two bytes
bFirst = m_ciEncoding[0];
bSecond = m_ciEncoding[1];
bIndexOrHiOffset = (BYTE) m_wIndex;
bLength = (BYTE)m_ciEncoding.Length();
break;
}
dwOffset = m_dwOffset;
bLength = (BYTE)m_ciEncoding.Length();
break;
case sRLE::Offset:
dwOffset = m_dwOffset;
break;
default:
_ASSERTE(FALSE);
// Should probably throw an exception...
}
cfTarget.Write(&dwOffset, sizeof dwOffset);
}
/******************************************************************************
CGlyphHandle::WriteGTT
This member function writes the GTT map table entry for this glyph in the
requested format.
******************************************************************************/
static BYTE abFlags[] = {sMapTableEntry::Replace, sMapTableEntry::Add,
sMapTableEntry::Disable};
void CGlyphHandle::WriteGTT(CFile& cfTarget, BOOL bPredefined) const {
sMapTableEntry smte;
smte.m_bCodePageIndex = (bPredefined && m_wPredefined == Removed) ?
0 : (BYTE) m_dwidCodePage;
// GTTOffset set m_dwOffset if Composed is needed. Otherwise we can tell
// the proper flags by looking at the length and whether it is DBCS or not
if (m_dwOffset) {
smte.m_uectt.wOffset = (WORD) m_dwOffset;
smte.m_bfType = sMapTableEntry::Composed;
}
else {
smte.m_bfType = pccpi->IsDBCS(m_dwCodePage) ?
((m_ciEncoding.Length() == 2) ?
sMapTableEntry::Paired : sMapTableEntry::Direct ) |
(pccpi->IsDBCS(m_dwCodePage, m_wCodePoint) ?
sMapTableEntry::DoubleByte : sMapTableEntry::SingleByte) :
(m_ciEncoding.Length() == 2) ?
sMapTableEntry::Paired : sMapTableEntry::Direct;
smte.m_uectt.abPaired[0] = m_ciEncoding[0];
smte.m_uectt.abPaired[1] = m_ciEncoding[1];
}
if (bPredefined)
smte.m_bfType |= abFlags[m_wPredefined];
// Just write it out!
cfTarget.Write(&smte, sizeof smte);
}
/******************************************************************************
CGlyphHandle::WriteEncoding
This method writes the encoding to to the file in the desired format. The
formats are:
GTT- write nothing if not composed. If composed, write the length, and then
the encoding.
RLESmall- just the encoding
RLEBig- the index and the encoding.
******************************************************************************/
void CGlyphHandle::WriteEncoding(CFile& cfTarget, WORD wfHow) const {
if (!m_dwOffset)
return; // Nothing to write
if (wfHow == RLEBig)
cfTarget.Write(&m_wIndex, sizeof m_wIndex);
m_ciEncoding.WriteEncoding(cfTarget, wfHow == GTT);
}
/******************************************************************************
CRunRecord class implementation
******************************************************************************/
CRunRecord::CRunRecord(CGlyphHandle *pcgh, CRunRecord *pcrrPrevious) {
m_wFirst = pcgh -> CodePoint();
m_wcGlyphs = 1;
m_dwOffset = 0;
m_cpaGlyphs.Add(pcgh);
// Maintain that old double chain!
m_pcrrPrevious = pcrrPrevious;
m_pcrrNext = m_pcrrPrevious -> m_pcrrNext;
m_pcrrPrevious -> m_pcrrNext = this;
if (m_pcrrNext)
m_pcrrNext -> m_pcrrPrevious = this;
}
/******************************************************************************
CRunRecord::CRunRecord(CRunRecord *pcrrPrevious, WORD wFirst)
This private constructor is the second tail record initializer. It is called
when a run is split due to a glyph deletion. In this case, we need to hook
into the chain, then fill in the details from our predecessor. wFirst tells
us where to begin extracting data from said predecessor.
******************************************************************************/
CRunRecord::CRunRecord(CRunRecord* pcrrPrevious, WORD wFirst) {
m_pcrrPrevious = pcrrPrevious;
m_pcrrNext = pcrrPrevious -> m_pcrrNext;
if (m_pcrrNext)
m_pcrrNext -> m_pcrrPrevious = this;
m_pcrrPrevious -> m_pcrrNext = this;
m_wFirst = m_wcGlyphs = 0;
m_dwOffset = 0;
// That's the normal empty initialization. Now, er fill ourselves from
// our predecessor
for (; wFirst < pcrrPrevious -> Glyphs(); wFirst++)
Add(&pcrrPrevious -> Glyph(wFirst));
}
/******************************************************************************
CRunRecord::CRunRecord(CRunRecord *pcrrPrevious)
This private constructor is the third and final tail record initializer. It
makes an exact duplicate of the previous record, then links itself into the
chain appropriately.
This constructor is necessary when a new code point is inserted ahead of the
earliest code point in the set of run records without extending the first
run.
******************************************************************************/
CRunRecord::CRunRecord(CRunRecord *pcrrPrevious) {
m_wFirst = pcrrPrevious -> m_wFirst;
m_wcGlyphs = pcrrPrevious -> m_wcGlyphs;
m_pcrrNext = pcrrPrevious -> m_pcrrNext;
m_pcrrPrevious = pcrrPrevious;
m_pcrrPrevious -> m_pcrrNext = this;
if (m_pcrrNext)
m_pcrrNext -> m_pcrrPrevious = this;
m_cpaGlyphs.Copy(pcrrPrevious -> m_cpaGlyphs);
}
// Initialize empty- this is used for the root record only
CRunRecord::CRunRecord() {
m_wFirst = m_wcGlyphs = 0;
m_dwOffset = 0;
m_pcrrNext = m_pcrrPrevious = NULL;
}
CRunRecord::~CRunRecord() {
if (m_pcrrNext)
delete m_pcrrNext;
}
unsigned CRunRecord::TotalGlyphs() const {
return m_pcrrNext ?
m_wcGlyphs + m_pcrrNext -> TotalGlyphs() : m_wcGlyphs;
}
BOOL CRunRecord::MustCompose() const {
for (unsigned u = 0; u < m_wcGlyphs; u++)
if (GlyphData(u).CompactSize())
return TRUE; // No need to look further
return m_pcrrNext ? m_pcrrNext -> MustCompose() : FALSE;
}
unsigned CRunRecord::ExtraNeeded(BOOL bCompact) {
unsigned uNeeded = 0;
for (unsigned u = 0; u < m_wcGlyphs; u++)
uNeeded += bCompact ? Glyph(u).CompactSize() : Glyph(u).MaximumSize();
return uNeeded + (m_pcrrNext ? m_pcrrNext -> ExtraNeeded() : 0);
}
/******************************************************************************
CRunRecord::GetGlyph()
This returns the nth handle in the run. We use recursion. This could get
bad enough in terms of performance (ony used to fill glyph map page in
editor) that we drop it, but I'll try it first.
******************************************************************************/
CGlyphHandle* CRunRecord::GetGlyph(unsigned u) const {
if (u < m_wcGlyphs)
return (CGlyphHandle *) m_cpaGlyphs[u];
return m_pcrrNext ? m_pcrrNext -> GetGlyph(u - m_wcGlyphs) : NULL;
}
/******************************************************************************
CRunRecord::Add
This member adds a glyph to the set of run records. This can mean adding an
additional record at the beginning or end of the set, extending an existing
record at either the beginning or end, and in those cases, orentiay merging
two records together.
******************************************************************************/
void CRunRecord::Add(CGlyphHandle *pcgh) {
WCHAR wcNew = pcgh -> CodePoint();
// If the glyph is already in the run, just update the info on it.
if (m_wcGlyphs && wcNew >= m_wFirst && wcNew < m_wFirst + m_wcGlyphs){
m_cpaGlyphs.SetAt(wcNew - m_wFirst, pcgh);
return;
}
// If this is the first record, and the glyph falls ahead of our first
// entry, we must clone ourselves, and become a one-glyph run. We cannot
// insert a record in front of oursleves as we are embedded in the
// glyph map structure directly.
if (m_wcGlyphs && wcNew < m_wFirst - 1) {
// This can only happen to the first record- otherwise the tail logic
// below would prevent this occurence
_ASSERTE(!m_pcrrPrevious);
// Clone us, using the copy contructor
CRunRecord *pcrr = new CRunRecord(this);
m_wFirst = pcgh -> CodePoint();
m_wcGlyphs = 1;
m_cpaGlyphs.RemoveAll();
m_cpaGlyphs.Add(pcgh);
return;
}
if (m_wcGlyphs && wcNew != m_wFirst + m_wcGlyphs &&
wcNew != m_wFirst - 1) {
// This belongs in some other record- pass it down the line, or
// append a new one.
if (m_pcrrNext)
// If this falls ahead of the next record, we must insert one now
if (wcNew < m_pcrrNext -> m_wFirst - 1)
m_pcrrNext = new CRunRecord(pcgh, this);
else
m_pcrrNext -> Add(pcgh);
else
m_pcrrNext = new CRunRecord(pcgh, this);
}
else {
// We're adding either at the front or the back, so do it right!
if (m_wFirst > wcNew) {
m_cpaGlyphs.InsertAt(0, pcgh);
m_wFirst = wcNew;
}
else
m_cpaGlyphs.Add(pcgh);
// This belonged here, so add it in- the root record begins with
// 0 glyphs, so if this is the first, keep track of it.
if (!m_wcGlyphs++)
m_wFirst = wcNew;
// If there is a following run, see if we need to merge it.
if (m_pcrrNext &&
m_pcrrNext -> m_wFirst == m_wFirst + m_wcGlyphs) {
// Merge the records.
m_cpaGlyphs.Append(m_pcrrNext -> m_cpaGlyphs);
m_wcGlyphs += m_pcrrNext -> m_wcGlyphs;
// Time to update the list. The class destructor removes the
// tail records, so that pointer must be set to NULL before the
// merged record is deleted.
CRunRecord *pcrrDead = m_pcrrNext;
m_pcrrNext = m_pcrrNext -> m_pcrrNext;
if (m_pcrrNext)
m_pcrrNext -> m_pcrrPrevious = this;
pcrrDead -> m_pcrrNext = NULL; // Avoid destructor overkill
pcrrDead -> m_wcGlyphs = 0; // Ditto
delete pcrrDead;
}
}
}
/******************************************************************************
CRunRecord::Delete
This member deletes a given glyph from the set of runs. Deleting an entry is
messy- it means splitting the record, unless we were so fortunate as to
merely lop off one of the ends.
******************************************************************************/
void CRunRecord::Delete(WORD wCodePoint) {
// If this isn't the right record, recurse or return as appropriate
if (wCodePoint < m_wFirst)
return;
if (wCodePoint >= m_wFirst + m_wcGlyphs) {
if (m_pcrrNext)
m_pcrrNext -> Delete(wCodePoint);
return;
}
WORD wIndex = wCodePoint - m_wFirst;
// Did we get lucky and hit the first or the last?
if (!wIndex || wIndex == -1 + m_wcGlyphs) {
// If there is only one entry in this run, kill it.
if (m_wcGlyphs == 1) {
if (m_pcrrPrevious) { // Not the first, then die!
m_pcrrPrevious -> m_pcrrNext = m_pcrrNext;
if (m_pcrrNext)
m_pcrrNext -> m_pcrrPrevious = m_pcrrPrevious;
m_pcrrNext = NULL; // We no longer have a follwing
delete this;
return; // It is finished
}
// We are the first. If there's someone after us, get their stuff
// and make it ours- otherwise, zero everything.
if (m_pcrrNext) {
m_cpaGlyphs.Copy(m_pcrrNext -> m_cpaGlyphs);
m_wFirst = m_pcrrNext -> m_wFirst;
m_wcGlyphs = m_pcrrNext -> m_wcGlyphs;
CRunRecord *pcrrVictim = m_pcrrNext;
m_pcrrNext = m_pcrrNext -> m_pcrrNext;
if (m_pcrrNext) // Raid 118880: BUG_BUG: m_pcrrNext become zero when deleted 1252 defalt with add code points
m_pcrrNext -> m_pcrrPrevious = this;
pcrrVictim -> m_pcrrNext = NULL;
delete pcrrVictim;
}
else {
m_cpaGlyphs.RemoveAll();
m_wFirst = m_wcGlyphs = 0;
}
m_dwOffset = 0;
return;
}
// OK, we can now kill the offending entry
m_cpaGlyphs.RemoveAt(wIndex);
m_wcGlyphs--;
// Yes, the following line is trick code. It's good for the soul...
m_wFirst += !wIndex;
return; // The glyph, she be toast.
}
// Alas, this means we must split the record.
// Since this means a new one must be made, let a new constructor do
// most of the dirty work for us.
m_pcrrNext = new CRunRecord(this, wIndex + 1);
_ASSERTE(m_pcrrNext); // We lose that, we might as well die...
// Delete everything after the offending member
m_cpaGlyphs.RemoveAt(wIndex, m_wcGlyphs - wIndex);
// Well, that about settles it, eh!
m_wcGlyphs = wIndex;
}
/******************************************************************************
CRunRecord::Empty
This method will be called if the glyph map is being re-initialized. We set
everything back to its initial state, and delete any tail records.
******************************************************************************/
void CRunRecord::Empty() {
if (m_pcrrNext)
delete m_pcrrNext;
m_pcrrNext = 0;
m_wFirst = m_wcGlyphs = 0;
m_cpaGlyphs.RemoveAll();
}
/******************************************************************************
CRunRecord::NoteOffset
This routine is given an offset which is to be managed in the run- the
management needed differs depending upon the file image being produced, so
we use a parameter to describe the tyoe being output.
In any event, the offset is passed by reference, and updated by each run
record in the set, in turn.
******************************************************************************/
void CRunRecord::NoteOffset(DWORD& dwOffset, BOOL bRLE, BOOL bPaired) {
if (bRLE) {
m_dwOffset = dwOffset;
dwOffset += m_wcGlyphs *
((CGlyphHandle *) m_cpaGlyphs[0]) -> RLESize();
}
else
for (unsigned u = 0; u < Glyphs(); u++)
Glyph(u).GTTOffset(dwOffset, bPaired);
// Recurse if there's more...
if (m_pcrrNext)
m_pcrrNext -> NoteOffset(dwOffset, bRLE, bPaired);
}
// This routine passes a DWORD to each glyph handle denoting where it can
// store its extra data. Each updates the offset, if necessary.
// We then recursively call each descendant to do the same thing.
void CRunRecord::NoteExtraOffset(DWORD &dwOffset, const BOOL bCompact) {
for (unsigned u = 0; u < m_wcGlyphs; u++)
Glyph(u).RLEOffset(dwOffset, bCompact);
if (m_pcrrNext)
m_pcrrNext -> NoteExtraOffset(dwOffset, bCompact);
}
// File output functions- These are all basically recursive. The callee does
// its thing, then passes it on down the chain. Since this is the order RLE
// and GTT are written in, everything is fine.
void CRunRecord::WriteSelf(CFile& cfTarget, BOOL bRLE) const {
cfTarget.Write(this, Size(bRLE));
if (m_pcrrNext)
m_pcrrNext -> WriteSelf(cfTarget, bRLE);
}
void CRunRecord::WriteHandles(CFile& cfTarget, WORD wFormat) const {
for (unsigned u = 0; u < m_wcGlyphs; u++)
GlyphData(u).WriteRLE(cfTarget, wFormat);
if (m_pcrrNext)
m_pcrrNext -> WriteHandles(cfTarget, wFormat);
}
// Member for writing the total set of GTT Map Table Entries
void CRunRecord::WriteMapTable(CFile& cfTarget, BOOL bPredefined) const {
for (unsigned u = 0; u < m_wcGlyphs; u++)
GlyphData(u).WriteGTT(cfTarget, bPredefined);
if (m_pcrrNext)
m_pcrrNext -> WriteMapTable(cfTarget, bPredefined);
}
/******************************************************************************
CRunRecord::WriteEncodings
This calls each glyph in the run record in ascending order to have it write
its encoding into the file in the given format. It then recursively calls
the next run record.
******************************************************************************/
void CRunRecord::WriteEncodings(CFile& cfTarget, WORD wfHow) const {
for (unsigned u = 0; u < m_wcGlyphs; u++)
GlyphData(u).WriteEncoding(cfTarget, wfHow);
if (m_pcrrNext)
m_pcrrNext -> WriteEncodings(cfTarget, wfHow);
}
/******************************************************************************
CCodePageData class implementation
******************************************************************************/
/******************************************************************************
CCodePageData::Invocation
This member function returns (in C-style string declaration form) the data to
send to the printer to perform the requested select/deselect of this code
page.
******************************************************************************/
void CCodePageData::Invocation(CString& csReturn, BOOL bSelect) const {
if (bSelect)
m_ciSelect.GetInvocation(csReturn);
else
m_ciDeselect.GetInvocation(csReturn);
}
/******************************************************************************
CCodePageData::SetInvocation(LPCTSTR lpstrInvoke, BOOL bSelect)
This member function sets the select or deselect sring using a string which
is decoded as a C-style string declaration.
******************************************************************************/
void CCodePageData::SetInvocation(LPCTSTR lpstrInvoke, BOOL bSelect) {
if (bSelect)
m_ciSelect.SetInvocation(lpstrInvoke);
else
m_ciDeselect.SetInvocation(lpstrInvoke);
}
/******************************************************************************
CCodePageData::SetInvocation(PBYTE pb, unsigned ucb, BOOL bSelect)
This member function initializes one of the two CInvocation members via its
Init function.
******************************************************************************/
void CCodePageData::SetInvocation(PBYTE pb, unsigned ucb, BOOL bSelect) {
if (bSelect)
m_ciSelect.Init(pb, ucb);
else
m_ciDeselect.Init(pb, ucb);
}
/******************************************************************************
CCodePageData::NoteOffsets
This member function is passed an offset at which it will record its
invocation strings. It simply funnels the call to each invocation member,
which updates the value as appropriate.
******************************************************************************/
void CCodePageData::NoteOffsets(DWORD& dwOffset) {
m_ciSelect.NoteOffset(dwOffset);
m_ciDeselect.NoteOffset(dwOffset);
}
// Write the id and invocation location information to the file
void CCodePageData::WriteSelf(CFile& cfTarget) {
cfTarget.Write(&m_dwid, sizeof m_dwid);
m_ciSelect.WriteSelf(cfTarget);
m_ciDeselect.WriteSelf(cfTarget);
}
// Write the invocation strings to a file.
void CCodePageData::WriteInvocation(CFile& cfTarget) {
m_ciSelect.WriteEncoding(cfTarget);
m_ciDeselect.WriteEncoding(cfTarget);
}
/******************************************************************************
CGlyphMap class implementation
******************************************************************************/
IMPLEMENT_SERIAL(CGlyphMap, CProjectNode, 0)
// The GTT header
struct sGTTHeader {
DWORD m_dwcbImage;
enum {Version1Point0 = 0x10000};
DWORD m_dwVersion;
DWORD m_dwfControl; // Any flags defined?
long m_lidPredefined;
DWORD m_dwcGlyphs;
DWORD m_dwcRuns;
DWORD m_dwofRuns;
DWORD m_dwcCodePages;
DWORD m_dwofCodePages;
DWORD m_dwofMapTable;
DWORD m_dwReserved[2];
sGTTHeader() {
memset(this, 0, sizeof *this);
m_dwVersion = Version1Point0;
m_lidPredefined = CGlyphMap::NoPredefined;
m_dwcbImage = sizeof *this;
}
};
CSafeMapWordToOb CGlyphMap::m_csmw2oPredefined;
/******************************************************************************
CGlyphMap::Public
This is a static member function which will return a pointer to one of the
predefined GTT files, after loading it if necessary.
******************************************************************************/
CGlyphMap* CGlyphMap::Public(WORD wID, WORD wCP/*= 0*/, DWORD dwDefCP/*= 0*/,
WORD wFirst/*= 0*/, WORD wLast/*= 255*/)
{
//TRACE("*** First char = %d\t\tLast char = %d\n", wFirst, wLast) ;
// If a GTT in this driver is needed, return NULL to force the
// program to go get it.
if (((short) wID) > 0)
return NULL ;
// If no GTT ID is set, use the code page that is passed in. If no code
// page is passed in, use the project's default code page. If there is
// no project, use 1252 as the default code page.
if (wID == 0)
if ((wID = wCP) == 0)
if ((wID = (WORD) dwDefCP) == 0)
wID = 1252 ;
// Check to see if wID is set to one of the Far East codepages that are
// built into the MDT. If that is the case, change it to the resource ID
// for that code page.
switch (wID) {
case 932:
wID = -17 ;
break ;
case 936:
wID = -16 ;
break ;
case 949:
wID = -18 ;
break ;
case 950:
wID = -10 ;
break ;
} ;
// If the ID is 1252, switch to the resource ID for CP 1252.
if (wID == 1252)
wID = -IDR_CP1252 ;
// The easy part comes if it is already loaded
CObject* pco ;
if (m_csmw2oPredefined.Lookup(wID, pco))
return (CGlyphMap*) pco ;
//// DEAD_BUG - The program can't load huge GTTs so just return NULL.
//
//if ((short) wID >= -18 || (short) wID <= -10)
// return NULL ;
// Manage loading a predefined code page or building a GTT based on a code
// page. Begin by declaring/initializing a class instance for it.
CGlyphMap *pcgm = new CGlyphMap ;
TCHAR acbuf[32] ;
if (FindResource(AfxGetResourceHandle(),
MAKEINTRESOURCE((((short) wID) < 0) ? -(short) wID : wID),
MAKEINTRESOURCE(IDR_GLYPHMAP)))
pcgm->m_csName.LoadString(IDS_DefaultPage + wID) ;
else {
strcpy(acbuf, _T("CP ")) ;
_itoa(wID, &acbuf[3], 10) ;
pcgm->m_csName = acbuf ;
} ;
pcgm->nSetRCID((int) wID) ;
pcgm->m_wFirstChar = wFirst ;
pcgm->m_wLastChar = wLast ;
pcgm->m_bResBldGTT = true ;
// Load/build the GTT. If this works, add it to the list of "predefined"
// GTTs and return a pointer to it.
if (pcgm->Load()) {
m_csmw2oPredefined[wID] = pcgm ;
return pcgm ;
} ;
// Clean up and return NULL if the load/build fails.
delete pcgm ;
return NULL ;
}
/******************************************************************************
CGlyphMap::MergePredefined
This merges in fresh glyph handles from the predefined GTT, then removes all
glyphs destined for the gallows.
******************************************************************************/
void CGlyphMap::MergePredefined() {
if (m_lidPredefined == NoPredefined)
return;
CWaitCursor cwc; // This takes a long time, I'll bet!
CGlyphMap *pcgm = Public((WORD) m_lidPredefined);
if (!pcgm)
AfxThrowNotSupportedException();
// First, add any new code pages in the predefined GTT
CMapWordToDWord cmw2dPageMap; // Map PDT code pages' indices to our own
for (unsigned u = 0; u < pcgm -> CodePages(); u++) {
for (unsigned u2 = 0; u2 < CodePages(); u2++)
if (PageID(u2) == pcgm -> PageID(u))
break;
if (u2 == CodePages())
AddCodePage(pcgm -> PageID(u));
cmw2dPageMap[(WORD)u] = u2;
}
CPtrArray cpaTemplate;
pcgm -> Collect(cpaTemplate);
for (int i = 0; i < cpaTemplate.GetSize(); i++) {
CGlyphHandle& cghTemplate = *(CGlyphHandle *) cpaTemplate[i];
CObject* pco;
if (!m_csmw2oEncodings.Lookup(cghTemplate.CodePoint(), pco)) {
// Add this one, and map the code page info.
CGlyphHandle* pcgh = new CGlyphHandle;
if (!pcgh)
AfxThrowMemoryException();
*pcgh = cghTemplate;
pcgh -> SetCodePage(cmw2dPageMap[(WORD)cghTemplate.CodePage()],
pcgm -> PageID(cghTemplate.CodePage()));
m_csmw2oEncodings[cghTemplate.CodePoint()] = pcgh;
m_crr.Add(pcgh);
}
}
// Now, all of the new pages have been added. We must remove all points
// listed as "Remove".
Collect(cpaTemplate); // Get all of the handles for ourselves
for (i = (int)cpaTemplate.GetSize(); i--; ) {
CGlyphHandle& cgh = *(CGlyphHandle *) cpaTemplate[i];
if (cgh.Predefined() == CGlyphHandle::Removed)
DeleteGlyph(cgh.CodePoint());
}
}
/******************************************************************************
CGlyphMap::UnmergePredefined
This is the harder of the two predfined handlers, if that is conceivable.
First (unless asked not to), glkyphs must be added to mark those missing from
the predefined GTT.
Then, the entire set is compared to the PDT, so they can be removed as
equivalent, or flagged as added or modified.
******************************************************************************/
void CGlyphMap::UnmergePredefined(BOOL bTrackRemovals) {
if (m_lidPredefined == NoPredefined)
return;
CWaitCursor cwc; // This takes a long time, I'll bet!
CGlyphMap *pcgm = Public((WORD) m_lidPredefined);
if (!pcgm)
AfxThrowNotSupportedException();
CPtrArray cpaPDT;
if (bTrackRemovals) {
pcgm -> Collect(cpaPDT);
for (int i = 0; i < cpaPDT.GetSize(); i++) {
CGlyphHandle& cgh = *(CGlyphHandle*) cpaPDT[i];
CObject* pco;
if (m_csmw2oEncodings.Lookup(cgh.CodePoint(), pco))
continue;
// This point was removed from the predefined set, so add it to
// ours, and mark it as such.
CGlyphHandle *pcghCorpse = new CGlyphHandle();
if (!pcghCorpse)
AfxThrowMemoryException();
*pcghCorpse = cgh;
pcghCorpse -> SetPredefined(CGlyphHandle::Removed);
m_csmw2oEncodings[cgh.CodePoint()] = pcghCorpse;
m_crr.Add(pcghCorpse);
}
}
// Mark all of the glyphs in our set, now. Also mark the code pages used
Collect(cpaPDT);
CMapWordToDWord cmw2dPages;
for (int i = (int)cpaPDT.GetSize(); i--; ) {
CGlyphHandle& cgh = *(CGlyphHandle*) cpaPDT[i];
union {
CObject *pco;
CGlyphHandle *pcgh;
};
if (pcgm -> m_csmw2oEncodings.Lookup(cgh.CodePoint(), pco))
if (*pcgh == cgh) {
if (cgh.Predefined() == CGlyphHandle::Removed)
continue; // Already accounted for
if (m_bPaired != pcgm -> m_bPaired && cgh.PairedRelevant())
cgh.SetPredefined(CGlyphHandle::Modified);
else {
DeleteGlyph(cgh.CodePoint()); // Unmodified
continue;
}
}
else
cgh.SetPredefined(CGlyphHandle::Modified);
else
cgh.SetPredefined(CGlyphHandle::Added);
cmw2dPages[(WORD)PageID(cgh.CodePage())]++; // Only track these pages
}
// Remove the unused code pages, unless they have selections
for (unsigned u = CodePages(); u--; )
if (!cmw2dPages[(WORD)PageID(u)])
if (CodePage(u).NoInvocation())
RemovePage(u, !u);
}
/******************************************************************************
CGlyphMap::GenerateRuns
This member will create the run records by iterating over the mapped glyph
handles.
******************************************************************************/
void CGlyphMap::GenerateRuns() {
if (m_crr.TotalGlyphs() == Glyphs())
return;
for (POSITION pos = m_csmw2oEncodings.GetStartPosition(); pos;) {
WORD wValue;
union {
CObject *pco;
CGlyphHandle *pcgh;
};
m_csmw2oEncodings.GetNextAssoc(pos, wValue, pco);
m_crr.Add(pcgh);
}
}
/******************************************************************************
CGlyphMap::Serialize
This member function serializes the Glyph map, i.e., loads or stores it into
a persistent object store. Only the project-level information is stored.
The file will be loaded using the project-level data.
Note: There was a second copy of the GTT's RC ID saved in the MDW file.
Because it could get out of sync with the one in the CGlyphMap's
CRCIDNode instance, the copy of the ID read/written by this routine
is no longer used. A bogus value is written and the number read is
discarded. This "ID" is still kept in the MDW file so that no new MDW
version is needed.
******************************************************************************/
void CGlyphMap::Serialize(CArchive& car)
{
WORD w = (WORD)0; // Used to read/write bogus RC ID in MDW file.
CProjectNode::Serialize(car) ;
if (car.IsLoading()) {
car >> w ;
}
else {
car << w ;
}
}
/******************************************************************************
CGlyphMap::CGlyphMap
The class constructor, in addition to setting some default values, builds an
array of IDs for the CProjectNode class from which it is derived to use in
building the context menu in the driver/project view tree.
It also allocates a single code page record for the current ANSI page, so we
always have a default page.
******************************************************************************/
CGlyphMap::CGlyphMap() {
m_cfn.SetExtension(_T(".GTT"));
m_bPaired = FALSE;
m_lidPredefined = NoPredefined;
// Build the context menu control
m_cwaMenuID.Add(ID_OpenItem);
m_cwaMenuID.Add(ID_CopyItem);
m_cwaMenuID.Add(ID_RenameItem);
m_cwaMenuID.Add(ID_DeleteItem);
m_cwaMenuID.Add(0);
m_cwaMenuID.Add(ID_ExpandBranch);
m_cwaMenuID.Add(ID_CollapseBranch);
//m_cwaMenuID.Add(0);
//m_cwaMenuID.Add(ID_GenerateOne);
// Initialy, let the default code page be the current ANSI page, if this
// is not a DBCS locale. Otherwise, use 1252, as no DBCS CTT file can be
// generated with UniTool
for (WORD w = 0; w < 256; w++)
if (IsDBCSLeadByte((BYTE) w))
break;
m_csoaCodePage.Add(new CCodePageData(w < 256 ? 1252 : GetACP()));
// Allocate a CCodePageInformation class if needed.
if (pccpi == NULL)
pccpi = new CCodePageInformation ;
// Assume that the GTT's data should be read from a file.
m_bResBldGTT = false ;
m_ctSaveTimeStamp = (time_t) 0 ; // The GTT has not been saved
}
/******************************************************************************
CGlyphMap::CodePages(CDWordArray &cdaReturn)
This overload fills a DWordArray with the code page IDs.
******************************************************************************/
void CGlyphMap::CodePages(CDWordArray &cdaReturn) const {
cdaReturn.RemoveAll();
for (unsigned u = 0; u < CodePages(); u++)
cdaReturn.Add(CodePage(u).Page());
}
/******************************************************************************
CGlyphMap::PageName
This member returns the name of a particular code page, by index.
******************************************************************************/
CString CGlyphMap::PageName(unsigned u) const {
return pccpi->Name(CodePage(u).Page());
}
/******************************************************************************
CGlyphMap::Invocation
This member returns (in C-style encoding) a string which is used to either
select or deselect a given code page.
******************************************************************************/
void CGlyphMap::Invocation(unsigned u, CString& csReturn,
BOOL bSelect) const {
CodePage(u).Invocation(csReturn, bSelect);
}
/******************************************************************************
CGlyphMap::UndefinedPoints
This member fills a map with all code points NOT in the current mapping, and
maps them to their related code pages. Thus only translatable points will be
passed back to the caller.
******************************************************************************/
void CGlyphMap::UndefinedPoints(CMapWordToDWord& cmw2dCollector) const {
cmw2dCollector.RemoveAll();
CWaitCursor cwc;
for (unsigned u = 0; u < CodePages(); u++) {
CWordArray cwaPage;
// Collect the code points in the code page
pccpi->Collect(PageID(u), cwaPage);
union {
CObject *pco;
DWORD dw;
};
// Check the entries- if they haven't been mapped yet, and
// some earlier code page hasn't claimed them, add them.
for (int i = 0; i < cwaPage.GetSize(); i++)
if (!m_csmw2oEncodings.Lookup(cwaPage[i], pco) &&
!cmw2dCollector.Lookup(cwaPage[i], dw))
cmw2dCollector[cwaPage[i]] = u;
}
}
/******************************************************************************
CGlyphMap::Load(CByteArray& cbaMap)
This loads an image of a GTT into safe memory, whether it is predefined or
a file.
******************************************************************************/
//void CGlyphMap::Load(CByteArray& cbaMap) const
void CGlyphMap::Load(CByteArray& cbaMap)
{
short xxx = (short) ((CProjectNode*) this)->nGetRCID() ; // The GTT's RC ID
short sid = (short) nGetRCID() ; // The GTT's RC ID
try {
// Try to load the GTT from a file when the GTT should not be loaded
// from a resource or built.
if (!m_bResBldGTT
&& (sid > 0 || (sid < Wansung && sid != -IDR_CP1252))) {
CFile cfGTT(m_cfn.FullName(),
CFile::modeRead | CFile::shareDenyWrite);
cbaMap.SetSize(cfGTT.GetLength());
cfGTT.Read(cbaMap.GetData(), (unsigned)cbaMap.GetSize());
return;
} ;
// If the GTT is a resource, load it from there.
// raid 441362
if(MAKEINTRESOURCE((sid < 0) ? -sid : sid) == NULL)
return;
HRSRC hrsrc = FindResource(AfxGetResourceHandle(),
MAKEINTRESOURCE((sid < 0) ? -sid : sid),
MAKEINTRESOURCE(IDR_GLYPHMAP));
if (hrsrc) {
HGLOBAL hg = LoadResource(AfxGetResourceHandle(), hrsrc) ;
if (!hg)
return ;
LPVOID lpv = LockResource(hg) ;
if (!lpv)
return ;
cbaMap.SetSize(SizeofResource(AfxGetResourceHandle(), hrsrc)) ;
memcpy(cbaMap.GetData(), lpv, (size_t)cbaMap.GetSize()) ;
return ;
} ;
//AfxMessageBox("GTT building code reached.") ;
// If all else fails, try to generate a GTT based on the code page ID
// that should be in m_wID if this point is reached.
HANDLE hheap ;
UNI_GLYPHSETDATA *pGTT ;
if (!(hheap = HeapCreate(HEAP_NO_SERIALIZE, 10 * 1024, 256 * 1024))) {
AfxMessageBox(IDS_HeapInGLoad) ;
return ;
} ;
pGTT = PGetDefaultGlyphset(hheap, m_wFirstChar, m_wLastChar,
(DWORD) sid) ;
if (pGTT == NULL) {
HeapDestroy(hheap) ; //raid 116600 Prefix
AfxMessageBox(IDS_PGetFailedInGLoad) ;
return ;
} ;
cbaMap.SetSize(pGTT->dwSize) ;
memcpy(cbaMap.GetData(), pGTT, (size_t)cbaMap.GetSize()) ;
HeapDestroy(hheap) ;
}
catch (CException *pce) {
pce -> ReportError();
pce -> Delete();
CString csMessage;
csMessage.Format(IDS_LoadFailure, Name());
AfxMessageBox(csMessage);
}
}
/******************************************************************************
CGlyphmap::SetSourceName
This takes and stores the source file name so we can load and convert later.
It also renames (or rather, sets the original name) for the GlyphMap using
the base file name.
******************************************************************************/
void CGlyphMap::SetSourceName(LPCTSTR lpstrNew) {
m_csSource = lpstrNew;
m_csName = m_csSource.Mid(m_csSource.ReverseFind(_T('\\')) + 1);
if (m_csName.Find(_T('.')) >= 0)
if (m_csName.Right(4).CompareNoCase(_T(".CTT"))) {
m_csName.SetAt(m_csName.Find(_T('.')), _T('_'));
CProjectNode::Rename(m_csName);
}
else
CProjectNode::Rename(m_csName.Left(m_csName.Find(_T('.'))));
else
CProjectNode::Rename(m_csName);
}
/******************************************************************************
CGlyphMap::SetFileName
This sets the new file name. It is done differently than in SetSourceName()
because the base file name must not be more than 8 characters long. (The
extra info is left in the node name by SetSourceName() because it is useful
there and it has no length limit.)
******************************************************************************/
BOOL CGlyphMap::SetFileName(LPCTSTR lpstrNew)
{
CString csnew ; // CString version of input parameter
csnew = lpstrNew ;
// If the input filespec contains an extension, remove it and pass the
// resulting string to the file node's rename routine. Otherwise, just
// pass the original string to the rename routine.
//
// This check is complicated by the fact that one of the path components
// might have a dot in it too. We need to check for the last dot and make
// sure it comes before a path separator.
if (csnew.ReverseFind(_T('.')) > csnew.ReverseFind(_T('\\')))
return m_cfn.Rename(csnew.Left(csnew.ReverseFind(_T('.')))) ;
else
return m_cfn.Rename(csnew) ;
}
/******************************************************************************
CGlyphMap::AddPoints
This member adds one or more code points to the glyph map using the given
list of points and associated pages.
******************************************************************************/
void CGlyphMap::AddPoints(CMapWordToDWord& cmw2dNew) {
WORD wKey;
DWORD dwixPage;
CWaitCursor cwc; // This could be slow!
for (POSITION pos = cmw2dNew.GetStartPosition(); pos; ) {
cmw2dNew.GetNextAssoc(pos, wKey, dwixPage);
// Get the MBCS encoding of the Unicode point as the initial
// glyph encoding.
CWordArray cwaIn;
CByteArray cbaOut;
cwaIn.Add(wKey);
pccpi->Convert(cbaOut, cwaIn, CodePage(dwixPage).Page());
// Create the glyph and add it to the map
CGlyphHandle *pcgh = new CGlyphHandle;
pcgh -> Init(cbaOut.GetData(), (unsigned) cbaOut.GetSize(), (WORD)Glyphs(),
wKey);
pcgh -> SetCodePage(dwixPage, CodePage(dwixPage).Page());
m_csmw2oEncodings[wKey] = pcgh;
m_crr.Add(pcgh);
}
Changed(); // Don't forget to tell the container!
}
/******************************************************************************
CGlyphMap::DeleteGlyph
This member function removes a glyph from the map. The most tricky part is
updating the run records, but that's not this class' responsibility, is it?
******************************************************************************/
void CGlyphMap::DeleteGlyph(WORD wCodePoint) {
if (!m_csmw2oEncodings.RemoveKey(wCodePoint))
return; // This glyph is already toast!
m_crr.Delete(wCodePoint);
Changed();
}
/******************************************************************************
CGlyphMap::RemovePage
This member function removes a code page from the list of available pages.
Glyphs that used this page will be remapped to a second specified page.
******************************************************************************/
BOOL CGlyphMap::RemovePage(unsigned uPage, unsigned uMapTo, bool bDelete /* bDelete = FALSE */) {
if (uPage >= CodePages() || uMapTo >= CodePages())
return FALSE;
// Pretty simple- walk the map- first replace any instances, then
// decrement any indices higher than uPage
WORD wKey;
union {
CObject* pco;
CGlyphHandle* pcgh;
};
for (POSITION pos = m_csmw2oEncodings.GetStartPosition(); pos; ) {
m_csmw2oEncodings.GetNextAssoc(pos, wKey, pco);
if (!bDelete){
if (pcgh -> CodePage() == uPage)
pcgh -> SetCodePage(uMapTo, CodePage(uMapTo).Page());
if (pcgh -> CodePage() > uPage)
pcgh -> SetCodePage(pcgh -> CodePage() - 1,
CodePage(pcgh -> CodePage()).Page());
}
else { // raid 118880
if (pcgh -> CodePage() == uPage)
DeleteGlyph(pcgh -> CodePoint() ) ; // delete m_csm2oEncodings, RunRecord
else if (pcgh -> CodePage() > uPage)
pcgh -> SetCodePage(pcgh -> CodePage() - 1,
CodePage(pcgh -> CodePage()).Page());
}
}
m_csoaCodePage.RemoveAt(uPage);
// Marke the GTT as dirty and then return success.
Changed();
return TRUE;
}
/******************************************************************************
CGlyphMap::ChangeCodePage
This member function changes the code page for one ore more glyphs to a
different page. At one time I thought remapping the code points would be
required, but currently, the Unicode stays intact. That seems a good feature
for demand-driven implementation.
******************************************************************************/
// This one changes the code page for one or more glyphs.
// For now, we will simply keep the Unicode intact. Eventually, a query
// should be made about the intent, so we can remap through the existing
// page, if that is what is desired.
void CGlyphMap::ChangeCodePage(CPtrArray& cpaGlyphs, DWORD dwidNewPage) {
for (unsigned u = 0; u < CodePages(); u++)
if (dwidNewPage == CodePage(u).Page())
break;
_ASSERTE(u < CodePages());
if (u >= CodePages())
return;
for (int i = 0; i < cpaGlyphs.GetSize(); i++)
((CGlyphHandle *) cpaGlyphs[i]) -> SetCodePage(u, dwidNewPage);
Changed();
}
/******************************************************************************
CGlyphMap::AddCodePage
This member function adds a new code page to the list of pages used in this
table.
******************************************************************************/
void CGlyphMap::AddCodePage(DWORD dwidNewPage) {
m_csoaCodePage.Add(new CCodePageData(dwidNewPage));
Changed();
}
/******************************************************************************
CGlyphMap::SetPredefinedID
This changes the predefined table used by the map. If it really is a change,
we must remove all non-modified points from any existing map, and then flesh
out using the new one.
******************************************************************************/
void CGlyphMap::UsePredefined(long lidNew) {
if (m_lidPredefined == lidNew)
return; // Didn't need to do this!
if (m_lidPredefined != NoPredefined)
UnmergePredefined(lidNew != NoPredefined);
m_lidPredefined = lidNew;
if (m_lidPredefined != NoPredefined)
MergePredefined();
Changed();
}
/******************************************************************************
CGlyphMap::SetInvocation
This member changes the invocation string for selecting or unselecting a
given code page.
******************************************************************************/
void CGlyphMap::SetInvocation(unsigned u, LPCTSTR lpstrInvoke,
BOOL bSelect) {
CodePage(u).SetInvocation(lpstrInvoke, bSelect);
Changed();
}
/******************************************************************************
CGlyphMap::ChangeEncoding
This member is called when the user changes the encoding string used to
invoke a given code point. This could be done via the glyph, but then the
containing document won't know of the change, and thus the change could be
inadvertently lost...
******************************************************************************/
void CGlyphMap::ChangeEncoding(WORD wCodePoint, LPCTSTR lpstrNewInvoke) {
union {
CObject *pco;
CGlyphHandle *pcgh;
};
if (!m_csmw2oEncodings.Lookup(wCodePoint, pco) || !lpstrNewInvoke||
!*lpstrNewInvoke)
return;
pcgh -> NewEncoding(lpstrNewInvoke);
Changed();
}
/******************************************************************************
CGlyphMap::ConvertCTT()
This member fuction initializes the glyphmap structure from a CTT file
******************************************************************************/
int CGlyphMap::ConvertCTT() {
struct sCTT {
enum {Composed, Direct, Paired};
WORD m_wFormat;
BYTE m_bFirstChar, m_bLastChar;
union {
uencCTT m_uectt[1];
BYTE m_bDirect[1];
};
};
// If this map isn't empty, empty it now- at least of the glyph data
m_csmw2oEncodings.RemoveAll();
m_crr.Empty();
CByteArray cbaImage;
try {
CFile cfCTT(m_csSource, CFile::modeRead | CFile::shareDenyWrite);
cbaImage.SetSize(cfCTT.GetLength());
cfCTT.Read(cbaImage.GetData(), cfCTT.GetLength());
}
catch (CException *pce) {
pce -> ReportError();
pce -> Delete();
return IDS_FileReadError ;
}
#if 0
union {
PBYTE pbCTT;
sCTT* psctt;
};
pbCTT = cbaImage.GetData();
BYTE bFirst = min(0x20, psctt -> m_bFirstChar),
bLast = 0xFF; // Since we use a byte this is the max!
unsigned ucGlyphs = 1 + bLast - bFirst;
// Convert the code points to Unicode
CByteArray cbaCode;
CWordArray cwaCode;
for (unsigned u = 0; u < ucGlyphs; u++)
cbaCode.Add(u + bFirst);
// Convert the data to Unicode using the selected code page. This uses
// data stored from MultiByteToWideChar, so it is similar, except we can
// do this with code pages which might not be installed on the user's
// system.
if (ucGlyphs != pccpi->Convert(cbaCode, cwaCode, CodePage(0).Page())) {
CString csWork;
csWork.Format(IDS_NoUnicodePoint, u + bFirst, CodePage(0).Page());
AfxMessageBox(csWork);
return IDS_UnicodeConvFailed ;
}
// Since we add phony glyphs to the table (why, one wonders), we must mark
// them so we can manufacture equally phony encodings for them.
for (u = 0; u < ucGlyphs; u++) {
// Now, let's record the Encoding
CGlyphHandle *pcghNew = new CGlyphHandle;
unsigned uToUse = u + bFirst - psctt -> m_bFirstChar;
switch (psctt -> m_wFormat) {
case sCTT::Direct:
if (u + bFirst < psctt -> m_bFirstChar)
pcghNew -> Init((BYTE) u + bFirst, u,cwaCode[u]);
else
pcghNew -> Init(psctt -> m_bDirect[uToUse], u, cwaCode[u]);
break;
case sCTT::Paired:
if (u + bFirst < psctt -> m_bFirstChar)
pcghNew -> Init((BYTE) u + bFirst, u, cwaCode[u]);
else
if (psctt -> m_uectt[uToUse].abPaired[1])
pcghNew -> Init(psctt -> m_uectt[uToUse].abPaired, u,
cwaCode[u]);
else
pcghNew -> Init(psctt -> m_uectt[uToUse].abPaired[0],
u, cwaCode[u]);
break;
case sCTT::Composed:
if (u + bFirst < psctt -> m_bFirstChar) {
BYTE bMe = u + bFirst;
pcghNew -> Init(&bMe, 1, u, cwaCode[u]);
}
else
pcghNew -> Init(pbCTT + psctt -> m_uectt[uToUse].wOffset,
psctt -> m_uectt[uToUse + 1].wOffset -
psctt -> m_uectt[uToUse].wOffset, u, cwaCode[u]);
break;
default: // Don't accept anything else!
AfxMessageBox(IDS_InvalidCTTFormat);
return IDS_Invalid2CTTFormat ;
} // One map entry coded
// Code page index inits OK, but must know the page
pcghNew -> SetCodePage(0, DefaultCodePage());
m_csmw2oEncodings[cwaCode[u]] = pcghNew;
m_crr.Add(pcghNew);
} // Loop of generating entries
m_bPaired = sCTT::Paired == psctt -> m_wFormat;
#else
{
HANDLE hheap;
PBYTE pbCTT;
UNI_GLYPHSETDATA *pGTT;
pbCTT = cbaImage.GetData();
if( !(hheap = HeapCreate(HEAP_NO_SERIALIZE, 10 * 1024, 256 * 1024 )))
{
char acMessage[256];
wsprintf(acMessage, "HeapCreate() fails in ctt2gtt" );
MessageBox(NULL, acMessage, NULL, MB_OK);
return IDS_HeapCFailed ;
}
//if (!BConvertCTT2GTT(hheap, (PTRANSTAB)pbCTT, DefaultCodePage(), 0x20,
ASSERT(m_pcdOwner != NULL) ;
DWORD dw = ((CProjectRecord*) m_pcdOwner)->GetDefaultCodePageNum() ;
if (!BConvertCTT2GTT(hheap, (PTRANSTAB)pbCTT, dw, 0x20, 0xff, NULL,
NULL, &pGTT, 0)){
HeapDestroy(hheap); // raid 116619 prefix
return IDS_ConvCTTFailed ;
}
try {
CFile cfGTT;
if (!cfGTT.Open(m_cfn.FullName(), CFile::modeCreate | CFile::modeWrite |
CFile::shareExclusive))
return IDS_FileWriteError;
cfGTT.Write(pGTT, pGTT->dwSize);
}
catch (CException *pce) {
pce -> ReportError();
pce -> Delete();
HeapDestroy(hheap);
return IDS_FileWriteError ;
}
HeapDestroy(hheap);
}
Load();
#endif
return 0 ;
}
/******************************************************************************
CGlyphMap::Load()
This initializes the glyphmap from a GTT format file. Since this is the
primary means of loading, it requires no parameters.
******************************************************************************/
BOOL CGlyphMap::Load(LPCTSTR lpstrName /*= NULL*/) {
// Note the correct name and path- the rename checks may fail, since the
// file is opened elsewhere (possibly with sharing conflicts), so disable
// them, for now. This code is a little sleazy- but the only time the
// file name isn't null is if the file's being opened.
if (FileTitle().IsEmpty() && lpstrName) {
m_cfn.EnableCreationCheck(FALSE);
SetFileName(lpstrName);
m_cfn.EnableCreationCheck();
}
if (Glyphs()) { // If we already have them, we're already loaded!
m_csoaCodePage.RemoveAll(); // Clean it all up, and reload.
m_csmw2oEncodings.RemoveAll();
m_crr.Empty();
}
CByteArray cbaGTT;
union {
PBYTE pbGTT;
sGTTHeader *psgtth;
};
Load(cbaGTT); // If this fails, it will post a reason why
if (!cbaGTT.GetSize())
return FALSE;
pbGTT = cbaGTT.GetData();
sMapTable* psmt = (sMapTable *) (pbGTT + psgtth -> m_dwofMapTable);
sMapTableEntry* psmte = (sMapTableEntry *)(psmt + 1);
// Before we go any further, let's do some validation
if (psgtth -> m_dwVersion != sGTTHeader::Version1Point0)
return FALSE;
m_bPaired = FALSE;
// First, let's snarf up the code page info
struct sInvocation {
DWORD m_dwSize, m_dwOffset;
};
struct sCodePageInfo {
DWORD m_dwPage;
sInvocation m_siSelect, m_siDeselect;
} *psci = (sCodePageInfo *)(pbGTT + psgtth -> m_dwofCodePages);
m_csoaCodePage.RemoveAll();
for (unsigned u = 0; u < psgtth -> m_dwcCodePages; u++, psci++) {
m_csoaCodePage.Add(new CCodePageData(psci -> m_dwPage));
if (!psci -> m_siSelect.m_dwSize != !psci -> m_siSelect.m_dwOffset ||
!psci -> m_siDeselect.m_dwSize !=
!psci -> m_siDeselect.m_dwOffset)
return FALSE; // The data is bogus!
CodePage(u).SetInvocation(((PBYTE) psci) + psci->m_siSelect.m_dwOffset,
psci -> m_siSelect.m_dwSize, TRUE);
CodePage(u).SetInvocation(((PBYTE) psci) + psci->m_siDeselect.m_dwOffset,
psci -> m_siDeselect.m_dwSize, FALSE);
//CodePage(u).SetInvocation(pbGTT + psci -> m_siSelect.m_dwOffset,
// psci -> m_siSelect.m_dwSize, TRUE);
//CodePage(u).SetInvocation(pbGTT + psci -> m_siDeselect.m_dwOffset,
// psci -> m_siDeselect.m_dwSize, FALSE);
}
// Next, we need to walk the glyph run tables to decipher and use the map
// table.
struct sGlyphRun {
WORD m_wFirst, m_wc;
} *psgr = (sGlyphRun *)(pbGTT + psgtth -> m_dwofRuns);
_ASSERTE(psgtth -> m_dwcGlyphs == psmt -> m_dwcEntries);
WORD wIndex = 0;
/*** Changes have been made so that the following code is unneeded.
The MDT can load predefined GTTs now. In addition, skipping
the complete loading of these GTTs causes some problems with
UFM width table loading. The cumulative count of entries in
the glyph run tables is used to determine the maximum size of
the UFMs width table. The data in the run tables is also used
to verify width table entries.
// Don't do the rest if a predefined GTT is being loaded. The code below
// can blow on large GTTs; eg, the DBCS ones. It may be better to find out
// why the code blows but this seems to work for now.
if ((short) m_wID >= CGlyphMap::Wansung
&& (short) m_wID <= CGlyphMap::CodePage437)
return TRUE ;
*/
for (unsigned uRun = 0; uRun < psgtth -> m_dwcRuns; uRun++, psgr++)
for (u = 0; u < psgr -> m_wc; u++, psmte++, wIndex++) {
CGlyphHandle* pcgh = new CGlyphHandle;
switch (psmte -> m_bfType & sMapTableEntry::Format) {
case sMapTableEntry::Direct:
pcgh -> Init((PBYTE) &psmte -> m_uectt, 1, wIndex,
psgr -> m_wFirst + u);
break;
case sMapTableEntry::Paired:
pcgh -> Init(psmte -> m_uectt.abPaired, wIndex,
psgr -> m_wFirst + u);
if (!(psmte -> m_bfType & sMapTableEntry::DBCS))
m_bPaired = TRUE;
break;
case sMapTableEntry::Composed:
pcgh -> Init(pbGTT + psgtth -> m_dwofMapTable +
psmte -> m_uectt.wOffset + sizeof wIndex,
*(PWORD) (pbGTT + psgtth -> m_dwofMapTable +
psmte -> m_uectt.wOffset), wIndex,
psgr -> m_wFirst + u);
break;
default: // Bad news- bad format
delete pcgh; // No orphans needed!
return FALSE;
}
// Don't forget the code page ID!
pcgh -> SetCodePage(psmte -> m_bCodePageIndex,
CodePage(psmte -> m_bCodePageIndex).Page());
// Mark this if it is to be disabled.
if (psmte -> m_bfType & sMapTableEntry::Disable)
pcgh -> SetPredefined(CGlyphHandle::Removed);
m_csmw2oEncodings[psgr -> m_wFirst + u] = pcgh;
m_crr.Add(pcgh);
}
// If we're predefined, Merge now.
m_lidPredefined = psgtth -> m_lidPredefined;
if (m_lidPredefined != NoPredefined)
MergePredefined();
return TRUE; // We actually did it!
}
/******************************************************************************
CGlyphMap::RLE
This generates an RLE-format file image of the glyph map.
******************************************************************************/
BOOL CGlyphMap::RLE(CFile& cfTarget) {
sRLE srle;
srle.m_widRLE = 0x78FE;
srle.m_wcFirst = m_crr.First();
srle.m_wcLast = m_crr.Last();
srle.m_dwFlag = 0;
srle.m_dwcGlyphs = m_csmw2oEncodings.GetCount();
srle.m_dwcRuns = m_crr.RunCount();
srle.m_dwcbImage = 4 * sizeof srle.m_dwcbImage + srle.m_dwcRuns *
m_crr.Size();
srle.m_dwcbThis = srle.m_dwcbImage + 3 * sizeof srle.m_dwcbThis +
srle.m_dwcGlyphs * sizeof srle.m_dwcGlyphs;
// Determine the correct format, and thus the RLE size
if (!m_crr.MustCompose())
srle.m_wFormat = m_bPaired ? sRLE::Paired : sRLE::Direct;
else
if (srle.m_dwcGlyphs < 256 &&
srle.m_dwcbThis + m_crr.ExtraNeeded() <= 0xffff) {
srle.m_dwcbThis += m_crr.ExtraNeeded();
srle.m_wFormat = sRLE::LengthIndexOffset;
}
else {
srle.m_dwcbThis += m_crr.ExtraNeeded(FALSE);
srle.m_wFormat = sRLE::LengthOffset;
}
// We now need to feed the offset information down to the lower level
// classes, so that they are prepared to render their information to
// the target file.
// The first items encoded are the runs, which immediately follow the RLE
// header.
DWORD dwOffset = sizeof srle + srle.m_dwcRuns * m_crr.Size();
m_crr.NoteOffset(dwOffset, TRUE, m_bPaired);
// If this requires extra data, it will be appearing after the FD_GLYPHSET
if (srle.m_wFormat == sRLE::LengthOffset ||
srle.m_wFormat == sRLE::LengthIndexOffset)
m_crr.NoteExtraOffset(dwOffset,
srle.m_wFormat == sRLE::LengthIndexOffset);
_ASSERTE(dwOffset == srle.m_dwcbThis);
// We've got our data, we've got our file, and we've got a job to do.
// Hop to it!
try {
cfTarget.Write(&srle, sizeof srle);
m_crr.WriteSelf(cfTarget);
m_crr.WriteHandles(cfTarget, srle.m_wFormat);
m_crr.WriteEncodings(cfTarget, srle.m_wFormat == sRLE::LengthOffset ?
CGlyphHandle::RLEBig : CGlyphHandle::RLESmall);
}
catch (CException *pce) {
pce -> ReportError();
pce -> Delete();
return FALSE;
}
return TRUE;
}
/******************************************************************************
CGlyphMap::Glyph
I tried to do this in the header, file but that lets it be in-line, and I
don't want to export CRunRecord.
******************************************************************************/
CGlyphHandle* CGlyphMap::Glyph(unsigned u) {
return m_crr.GetGlyph(u);
}
/******************************************************************************
CGlyphMap::CreateEditor
This member function overrides the CProjectNode function to create a new
CGlyphMapContainer document embedding this Glyph Map. It then uses the
appropriate document template to open a view on this document.
******************************************************************************/
CMDIChildWnd *CGlyphMap::CreateEditor() {
CGlyphMapContainer* pcgmcMe= new CGlyphMapContainer(this, FileName());
// Make up a cool title
pcgmcMe -> SetTitle(m_pcbnWorkspace -> Name() + _TEXT(": ") + Name());
CMDIChildWnd *pcmcwNew = (CMDIChildWnd *) m_pcmdt ->
CreateNewFrame(pcgmcMe, NULL);
if (pcmcwNew) {
m_pcmdt -> InitialUpdateFrame(pcmcwNew, pcgmcMe, TRUE);
m_pcmdt -> AddDocument(pcgmcMe);
}
return pcmcwNew;
}
/******************************************************************************
CGlyphMap::Generate
This member function generates the GTT format image of the current data.
It returns a BOOL indicating success or failure.
******************************************************************************/
BOOL CGlyphMap::Generate(CFile& cfGTT) {
sGTTHeader sgtth;
// First, take care of any predefined stuff, if we have to
if (m_lidPredefined != NoPredefined)
UnmergePredefined(TRUE);
sgtth.m_dwcGlyphs = Glyphs();
sgtth.m_dwcRuns = m_crr.RunCount();
sgtth.m_dwcCodePages = CodePages();
sgtth.m_lidPredefined = m_lidPredefined;
// The run table is the first item after the header, so add in its size
sgtth.m_dwofRuns = sgtth.m_dwcbImage; // Runs are first item
sgtth.m_dwcbImage += sgtth.m_dwcRuns * m_crr.Size(FALSE);
sgtth.m_dwofCodePages = sgtth.m_dwcbImage; // Code pages are next
// Code page selection strings immediately follow the Code page structures
// The code page information size must be padded to a DWORD multiple
sgtth.m_dwcbImage += sgtth.m_dwcCodePages * CodePage(0).Size();
DWORD dwPadding ; // # of padding bytes needed to DWORD align map table
DWORD dwSelOffset ; // Offset from each CODEPAGEINFO to sel/desel strings
DWORD dwSelBytes ; // Total # of bytes used by sel/desel strings
dwSelOffset = sgtth.m_dwcbImage - sgtth.m_dwofCodePages ;
for (unsigned u = 0 ; u < CodePages() ; u++) {
CodePage(u).NoteOffsets(dwSelOffset) ;
dwSelOffset -= CodePage(0).Size() ;
} ;
// Save the amount of padding, as we'll write it later. It is also needed
// as part of the computation for the mapping table offset.
dwPadding = dwSelOffset + sgtth.m_dwcbImage ;
dwPadding = (sizeof(DWORD) -
(dwPadding & (sizeof(DWORD) - 1))) & (sizeof(DWORD) - 1) ;
// Compute the number of bytes used for the sel/desel strings and pad. Then
// add this count to the image count of bytes so that it can be used to set
// the mapping table offset.
dwSelBytes = dwSelOffset + dwPadding ;
sgtth.m_dwcbImage += dwSelBytes;
sgtth.m_dwofMapTable = sgtth.m_dwcbImage;
TRACE("***CGlyphMap::Generate() - dwPadding = %d, dwSelBytes = %d, m_dwofMapTable = 0x%x\n", dwPadding, dwSelBytes, sgtth.m_dwofMapTable) ;
// Map Table size determination
sMapTable smt(Glyphs());
// Fortunately for us, the following not only preps the data, it also
// updates the image size for us
if (m_crr.MustCompose())
m_crr.NoteOffset(smt.m_dwcbImage, FALSE, m_bPaired);
// Final Size calculation
sgtth.m_dwcbImage += smt.m_dwcbImage;
// Now, we just write it out
try {
cfGTT.Write(&sgtth, sizeof sgtth); // Header
ASSERT(sgtth.m_dwofRuns == cfGTT.GetPosition()) ;
m_crr.WriteSelf(cfGTT, FALSE); // Glyph Runs
ASSERT(sgtth.m_dwofCodePages == cfGTT.GetPosition()) ;
for (unsigned u = 0; u < CodePages(); u++)
CodePage(u).WriteSelf(cfGTT); // Code page structures
for (u = 0; u < CodePages(); u++)
CodePage(u).WriteInvocation(cfGTT); // Code page invocations
// Pad with 0's to DWORD align the mapping table
dwSelBytes = 0 ;
cfGTT.Write((LPSTR) &dwSelBytes, dwPadding) ;
// Do the map table, and we are finished!
ASSERT(sgtth.m_dwofMapTable == cfGTT.GetPosition()) ;
cfGTT.Write(&smt, sizeof smt);
m_crr.WriteMapTable(cfGTT, m_lidPredefined != NoPredefined);
m_crr.WriteEncodings(cfGTT, CGlyphHandle::GTT);
}
catch (CException * pce) {
// Take care of any predefined stuff, if we have to
if (m_lidPredefined != NoPredefined)
MergePredefined();
// Feedback- something broke when it shouldn't have
pce -> ReportError();
pce -> Delete();
return FALSE;
}
// Take care of any predefined stuff, if we have to
if (m_lidPredefined != NoPredefined)
MergePredefined();
Changed(FALSE);
return TRUE;
}
/******************************************************************************
CGlyphMapContainer class - this encases the glyph table UI when it is either
embedded in the driver, or loaded directly from the GTT
******************************************************************************/
/******************************************************************************
CGlyphMapContainer::CGlyphMapContainer()
This default constructor is used whenever dynamic creation is used, which is
most MFC usages of the document system. It starts with an empty glyph map.
******************************************************************************/
IMPLEMENT_DYNCREATE(CGlyphMapContainer, CDocument)
CGlyphMapContainer::CGlyphMapContainer()
{
m_pcgm = new CGlyphMap;
m_pcgm -> NoteOwner(*this);
m_bSaveSuccessful = m_bEmbedded = FALSE;
}
/******************************************************************************
CGlyphMapContainer:CGlyphMapContainer(CGlyphMap *pvgm, CString csPath)
This constructor override is used when we create a CGlyphMapContainer
document from the driver/project level editor. In this case, a digested
map is passed, so no additional I/O us needed.
******************************************************************************/
CGlyphMapContainer::CGlyphMapContainer(CGlyphMap *pcgm, CString csPath)
{
m_pcgm = pcgm;
SetPathName(csPath, FALSE);
m_bEmbedded = TRUE;
m_bSaveSuccessful = FALSE;
m_pcgm -> NoteOwner(*this); // This is the document being edited!
}
BOOL CGlyphMapContainer::OnNewDocument() {
return CDocument::OnNewDocument();
}
CGlyphMapContainer::~CGlyphMapContainer() {
if (!m_bEmbedded && m_pcgm)
delete m_pcgm;
}
BEGIN_MESSAGE_MAP(CGlyphMapContainer, CDocument)
//{{AFX_MSG_MAP(CGlyphMapContainer)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CGlyphMapContainer diagnostics
#ifdef _DEBUG
void CGlyphMapContainer::AssertValid() const {
CDocument::AssertValid();
}
void CGlyphMapContainer::Dump(CDumpContext& dc) const {
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CGlyphMapContainer serialization
void CGlyphMapContainer::Serialize(CArchive& ar) {
if (ar.IsStoring()) {
// TODO: add storing code here
}
else {
// TODO: add loading code here
}
}
/////////////////////////////////////////////////////////////////////////////
// CGlyphMapContainer commands
BOOL CGlyphMapContainer::OnSaveDocument(LPCTSTR lpszPathName) {
// We save via the glyph map's Generate function.
CFile cfGTT;
if (!cfGTT.Open(lpszPathName, CFile::modeCreate | CFile::modeWrite |
CFile::shareExclusive))
return FALSE;
m_bSaveSuccessful = m_pcgm -> Generate(cfGTT) ;
// Update the save timestamp. This is done here so that other user of the
// Generate() function don't update the timestamp.
m_pcgm->m_ctSaveTimeStamp = CTime::GetCurrentTime() ;
// when open mutiple workspace, last of the pos is the workspace conating current GTT or UFM
CDriverResources * pcpr =(CDriverResources *) m_pcgm->GetWorkspace() ;
if (m_pcgm->ChngedCodePt() && pcpr ) {// && m_pcgm->Glyphs() <= 1000 ) {
pcpr->SyncUFMWidth() ;
}
return m_bSaveSuccessful ;
}
/******************************************************************************
CGlyphMapContainer::OnOpenDocument
This overrides the typical MFC open document action, which is to open the
document by serialization. Instead, we use the CGlyphMap Load override for
the GTT format to initialize the GlyphMap.
******************************************************************************/
BOOL CGlyphMapContainer::OnOpenDocument(LPCTSTR lpstrFile)
{
return m_pcgm->Load(lpstrFile) ;
}
/******************************************************************************
CGlyphMapContainer::SaveModified
The document is about to close. If the GTT was changed by the user but the
user does not want to save the changes, the user wants to close the GTT, and
the GTT was loaded from a workspace, then reload the GTT so that the changes
are removed from the in memory copy of the GTT. This keeps those "discarded"
changes from being displayed the next time the GTT is edited.
Return TRUE if it is ok for the doc to close. Otherwise, FALSE.
******************************************************************************/
BOOL CGlyphMapContainer::SaveModified()
{
// Get a pointer to the associate view class instance and use it to make
// sure the code page select/deselect strings are copied into the GTT.
POSITION pos = GetFirstViewPosition() ;
ASSERT(pos != NULL) ;
CGlyphMapView* pcgmv = (CGlyphMapView*) GetNextView(pos) ;
pcgmv->SaveBothSelAndDeselStrings() ;
// Find out if the document was modified and if the user wants to save it.
m_bSaveSuccessful = FALSE ;
BOOL bmodified = IsModified() ;
BOOL bcloseok = CDocument::SaveModified() ;
// If the GTT was loaded from a workspace, the GTT was changed, the user
// does NOT want to save the changes, and he does want to close the doc,
// then reload the GTT.
if (m_bEmbedded && bmodified && bcloseok && !m_bSaveSuccessful)
m_pcgm->Load() ;
// Return flag indicating if it is ok to close the doc.
return bcloseok ;
}