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.
500 lines
14 KiB
500 lines
14 KiB
/******************************************************************************
|
|
|
|
Source File: Code Page Knowledge Base.CPP
|
|
|
|
This implements the code page knowledge base.
|
|
|
|
Copyright (c) 1997 by Microsoft Corporation. All Rights Reserved.
|
|
|
|
A Pretty Penny Enterprises Production.
|
|
|
|
Change History:
|
|
02-22-1997 [email protected] Created it
|
|
|
|
******************************************************************************/
|
|
|
|
#include "StdAfx.h"
|
|
//#include <AfxDllx.h>
|
|
#include "Resource.H"
|
|
#if defined(LONG_NAMES)
|
|
#include "Code Page Knowledge Base.H"
|
|
#else
|
|
#include "CodePage.H"
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/*** Commented out because this code is no longer in a DLL.
|
|
|
|
static AFX_EXTENSION_MODULE CodePageKnowledgeBaseDLL = { NULL, NULL };
|
|
static HINSTANCE hi;
|
|
|
|
extern "C" int APIENTRY
|
|
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) {
|
|
if (dwReason == DLL_PROCESS_ATTACH) {
|
|
hi = hInstance;
|
|
TRACE0("Code Page Knowledge Base.DLL Initializing!\n");
|
|
|
|
// Extension DLL one-time initialization
|
|
AfxInitExtensionModule(CodePageKnowledgeBaseDLL, hInstance);
|
|
|
|
// Insert this DLL into the resource chain
|
|
new CDynLinkLibrary(CodePageKnowledgeBaseDLL);
|
|
}
|
|
else if (dwReason == DLL_PROCESS_DETACH) {
|
|
TRACE0("Code Page Knowledge Base.DLL Terminating!\n");
|
|
}
|
|
return 1; // ok
|
|
}
|
|
*/
|
|
|
|
|
|
static CDWordArray cdaInstalled, cdaSupported, cdaMapped;
|
|
|
|
static BOOL CALLBACK EnumProc(LPTSTR lpstrName) {
|
|
cdaSupported.Add(atoi(lpstrName));
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::Load
|
|
|
|
This loads the selected code page into the cache, if it isn't already there.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CCodePageInformation::Load(DWORD dwidPage) {
|
|
|
|
if (dwidPage == m_dwidMapped)
|
|
return TRUE; // Already done!
|
|
|
|
if (dwidPage > 65535) // We map words for code pages in civilized lands
|
|
return FALSE;
|
|
|
|
HRSRC hrsrc = FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE((WORD) dwidPage),
|
|
MAKEINTRESOURCE(MAPPING_TABLE));
|
|
// raid 43537
|
|
if (!hrsrc)
|
|
return FALSE;
|
|
|
|
|
|
HGLOBAL hgMap = LoadResource(AfxGetResourceHandle(), hrsrc);
|
|
|
|
if (!hgMap)
|
|
return FALSE; // This should never happen!
|
|
|
|
LPVOID lpv = LockResource(hgMap);
|
|
|
|
if (!lpv)
|
|
return FALSE;
|
|
|
|
try {
|
|
m_cbaMap.RemoveAll();
|
|
m_cbaMap.SetSize(SizeofResource(AfxGetResourceHandle(), hrsrc));
|
|
memcpy(m_cbaMap.GetData(), lpv, (size_t)m_cbaMap.GetSize());
|
|
}
|
|
|
|
catch (CException * pce) {
|
|
m_dwidMapped = 0;
|
|
pce -> ReportError();
|
|
pce -> Delete();
|
|
return FALSE;
|
|
}
|
|
|
|
m_dwidMapped = dwidPage;
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::Map
|
|
|
|
This creates either the in or out of unicode translation table, as requested,
|
|
using the loaded map.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CCodePageInformation::Map(BOOL bUnicode) {
|
|
|
|
if (!m_dwidMapped)
|
|
return FALSE;
|
|
|
|
DWORD& dwid = bUnicode ? m_dwidOut : m_dwidIn;
|
|
|
|
if (m_dwidMapped == dwid)
|
|
return TRUE;
|
|
|
|
struct MB2WCMap {
|
|
WORD m_wMBCS;
|
|
WORD m_wWC;
|
|
} *psMap = (MB2WCMap *) m_cbaMap.GetData();
|
|
|
|
if (!psMap)
|
|
return 0;
|
|
|
|
DWORD dwcEntries = (DWORD)m_cbaMap.GetSize() / sizeof *psMap;
|
|
CWordArray& cwaMap = bUnicode ? m_cwaOut : m_cwaIn;
|
|
|
|
try {
|
|
|
|
cwaMap.RemoveAll();
|
|
cwaMap.InsertAt(0, 0xFFFF, 65536); // This is always an invalid value
|
|
|
|
while (dwcEntries--)
|
|
if (bUnicode)
|
|
cwaMap[psMap[dwcEntries].m_wWC] = psMap[dwcEntries].m_wMBCS;
|
|
else
|
|
cwaMap[psMap[dwcEntries].m_wMBCS] = psMap[dwcEntries].m_wWC;
|
|
}
|
|
|
|
catch (CException * pce) {
|
|
dwid = 0;
|
|
cwaMap.RemoveAll();
|
|
pce -> ReportError();
|
|
pce -> Delete();
|
|
return 0;
|
|
}
|
|
|
|
dwid = m_dwidMapped;
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation constructor
|
|
|
|
If the statistics haven't been initialized, do it now. Otherwise, this is
|
|
trivial.
|
|
|
|
******************************************************************************/
|
|
|
|
CCodePageInformation::CCodePageInformation() {
|
|
m_dwidMapped = m_dwidIn = m_dwidOut = 0;
|
|
// Initialize the statics if we need to.
|
|
|
|
if (cdaInstalled.GetSize())
|
|
return;
|
|
|
|
EnumSystemCodePages(&EnumProc, CP_INSTALLED);
|
|
cdaInstalled.Copy(cdaSupported);
|
|
cdaSupported.RemoveAll();
|
|
EnumSystemCodePages(&EnumProc, CP_SUPPORTED);
|
|
|
|
// Build a list of mappable code pages
|
|
|
|
for (DWORD dw = 400; dw < 32767; dw++)
|
|
if (HaveMap(dw))
|
|
cdaMapped.Add(dw);
|
|
}
|
|
|
|
const unsigned CCodePageInformation::SupportedCount() const {
|
|
return (unsigned) cdaSupported.GetSize();
|
|
}
|
|
|
|
const unsigned CCodePageInformation::InstalledCount() const {
|
|
return (unsigned) cdaInstalled.GetSize();
|
|
}
|
|
|
|
const unsigned CCodePageInformation::MappedCount() const {
|
|
return (unsigned) cdaMapped.GetSize();
|
|
}
|
|
|
|
const DWORD CCodePageInformation::Supported(unsigned u) const {
|
|
return cdaSupported[u];
|
|
}
|
|
|
|
const DWORD CCodePageInformation::Installed(unsigned u) const {
|
|
return cdaInstalled[u];
|
|
}
|
|
|
|
const DWORD CCodePageInformation::Mapped(unsigned u) const {
|
|
return cdaMapped[u];
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::Mapped(CDWordArray& cdaReturn)
|
|
|
|
Fills the given array with all of the mapped code page IDs.
|
|
|
|
******************************************************************************/
|
|
|
|
void CCodePageInformation::Mapped(CDWordArray& cdaReturn) const {
|
|
cdaReturn.Copy(cdaMapped);
|
|
}
|
|
|
|
CString CCodePageInformation::Name(DWORD dwidPage) const {
|
|
|
|
CString csTemp;
|
|
csTemp.LoadString(dwidPage);
|
|
csTemp.TrimLeft();
|
|
csTemp.TrimRight();
|
|
|
|
if (csTemp.IsEmpty())
|
|
csTemp.Format(_TEXT("Code Page %d"), dwidPage);
|
|
return csTemp;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::IsInstalled
|
|
|
|
Rturns true if the font is either installed in the OS or one of our
|
|
resources.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CCodePageInformation::IsInstalled(DWORD dwidPage) const {
|
|
for (unsigned u = 0; u < MappedCount(); u++)
|
|
if (Mapped(u) == dwidPage)
|
|
return TRUE;
|
|
for (u = 0; u < InstalledCount(); u++)
|
|
if (Installed(u) == dwidPage)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::GenerateMap
|
|
|
|
This private member generates a map representing the available one-to-one
|
|
transformations in an installed code page, and writes it to a file using
|
|
the code page id to form a unique name
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CCodePageInformation::GenerateMap(DWORD dwidMap) const {
|
|
|
|
// If we can't get Code Page info for it, vanish
|
|
|
|
CPINFO cpi;
|
|
|
|
if (!GetCPInfo(dwidMap, &cpi))
|
|
return FALSE;
|
|
|
|
CWordArray cwaMap;
|
|
|
|
for (unsigned u = 0; u < 65536; u++) {
|
|
unsigned uTo = 0;
|
|
BOOL bInvalid;
|
|
|
|
int icTo = WideCharToMultiByte(dwidMap, 0, (PWSTR) &u, 1, (PSTR) &uTo,
|
|
sizeof u, NULL, &bInvalid);
|
|
|
|
if (bInvalid)
|
|
continue; // Character wasn't any good...
|
|
|
|
_ASSERTE((unsigned) icTo <= cpi.MaxCharSize);
|
|
|
|
// OK, we mapped one- but, before we go on, make sure it also works
|
|
// in the other direction, since the U2M does some jiggering
|
|
|
|
unsigned u3 = 0;
|
|
|
|
MultiByteToWideChar(dwidMap, 0, (PSTR) &uTo, 2, (PWSTR) &u3, 2);
|
|
|
|
if (u3 != u)
|
|
continue; // Not a one-for one? Not interested...
|
|
|
|
cwaMap.Add((WORD)uTo);
|
|
cwaMap.Add((WORD)u);
|
|
}
|
|
|
|
// OK, we've got the down and dirty details- now, generate the file...
|
|
|
|
try {
|
|
CString csName;
|
|
csName.Format(_TEXT("WPS%u.CTT"), dwidMap);
|
|
|
|
CFile cfOut(csName,
|
|
CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive);
|
|
|
|
// Write the tranlated pairs
|
|
|
|
cfOut.Write(cwaMap.GetData(), (unsigned)(cwaMap.GetSize() * sizeof(WORD)));
|
|
}
|
|
|
|
catch(CException *pce) {
|
|
pce -> ReportError();
|
|
pce -> Delete();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::GenerateAllMaps
|
|
|
|
This member will generate an MBCS -> Unicode one-to-one mapping table for all
|
|
installed code pages in the user's system for which we do not now have maps.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CCodePageInformation::GenerateAllMaps() const {
|
|
|
|
BOOL bReturn = TRUE;
|
|
|
|
for (unsigned u = InstalledCount(); u--; )
|
|
if (!HaveMap(Installed(u)) && !GenerateMap(Installed(u)))
|
|
bReturn = FALSE;
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::HaveMap
|
|
|
|
Reports that the map is one of our resources (or isn't, as the case may be).
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CCodePageInformation::HaveMap(DWORD dwidMap) const {
|
|
return (dwidMap < 65536) ? !!FindResource(AfxGetResourceHandle(),
|
|
MAKEINTRESOURCE((WORD) dwidMap), MAKEINTRESOURCE(MAPPING_TABLE)) :
|
|
FALSE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::IsDBCS(DWORD dwidPage)
|
|
|
|
This is actually pretty simple- if the translation table is smaller than 1024
|
|
bytes (256 encodings), it isn't DBCS.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CCodePageInformation::IsDBCS(DWORD dwidPage) {
|
|
if (!Load(dwidPage))
|
|
return FALSE; // May be optimistic, but we'll find out...
|
|
|
|
return m_cbaMap.GetSize() > 1024;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::IsDBCS(DWORD dwidPage, WORD wCodePoint)
|
|
|
|
If the page isn't DBCS, we're done. Otherwise, make sure the Unicode->MBCS
|
|
map is loaded, and get the answer from there.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CCodePageInformation::IsDBCS(DWORD dwidPage, WORD wCodePoint) {
|
|
if (!IsDBCS(dwidPage))
|
|
return FALSE;
|
|
|
|
if (!Map(TRUE))
|
|
return FALSE; // Just say no, because the error's already been told
|
|
|
|
// 0xFFFF is invalid, hence SBCS (default always must be)
|
|
|
|
_ASSERTE(m_cwaOut[wCodePoint] != 0xFFFF);
|
|
|
|
return ((WORD) (1 + m_cwaOut[wCodePoint])) > 0x100;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::Convert
|
|
|
|
This is one of the workhorses- it loads the given code page, and maps the
|
|
given character strings one way or the other, depending upon which is empty.
|
|
|
|
******************************************************************************/
|
|
|
|
unsigned CCodePageInformation::Convert(CByteArray& cbaMBCS,
|
|
CWordArray& cwaWC,
|
|
DWORD dwidPage){
|
|
|
|
if (!cbaMBCS.GetSize() == !cwaWC.GetSize()) // Must be clear which way
|
|
return 0;
|
|
|
|
if (!Load(dwidPage) || !Map((int)cwaWC.GetSize()))
|
|
return 0;
|
|
|
|
CWordArray& cwaMap = cwaWC.GetSize() ? m_cwaOut : m_cwaIn;
|
|
try {
|
|
if (cbaMBCS.GetSize()) {
|
|
cwaWC.RemoveAll();
|
|
for (int i = 0; i < cbaMBCS.GetSize();) {
|
|
WORD wcThis = cbaMBCS[i];
|
|
|
|
if (cwaMap[wcThis] == 0xFFFF) { // No SBCS mapping
|
|
wcThis += cbaMBCS[i + 1] << 8;
|
|
if (cwaMap[wcThis] == 0xFFFF) { // No DBCS, either?
|
|
_ASSERTE(FALSE);
|
|
return 0; // We have failed to convert!
|
|
}
|
|
}
|
|
cwaWC.Add(cwaMap[wcThis]);
|
|
i += 1 + (wcThis > 0xFF);
|
|
}
|
|
}
|
|
else {
|
|
cbaMBCS.RemoveAll();
|
|
for (int i = 0; i < cwaWC.GetSize(); i++) {
|
|
if (cwaMap[cwaWC[i]] == 0xFFFF) {
|
|
_ASSERTE(0);
|
|
return 0;
|
|
}
|
|
cbaMBCS.Add((BYTE) cwaMap[cwaWC[i]]);
|
|
if (0xFF < cwaMap[cwaWC[i]])
|
|
cbaMBCS.Add((BYTE)(cwaMap[cwaWC[i]] >> 8));
|
|
}
|
|
}
|
|
}
|
|
|
|
catch (CException * pce) {
|
|
pce -> ReportError();
|
|
pce -> Delete();
|
|
return 0;
|
|
}
|
|
|
|
return (unsigned)cwaWC.GetSize(); // Correct conversion count either way!
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CCodePageInformation::Collect
|
|
|
|
This member fills a passed CWordArray with either the domain or range of the
|
|
mapping function. In either case, the array is in ascending order.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CCodePageInformation::Collect(DWORD dwidPage, CWordArray& cwaCollect,
|
|
BOOL bUnicode) {
|
|
|
|
if (!Load(dwidPage) || !Map(bUnicode))
|
|
return FALSE;
|
|
|
|
CWordArray& cwaMap = bUnicode ? m_cwaOut : m_cwaIn;
|
|
cwaCollect.RemoveAll();
|
|
|
|
// Code points < 0x20 always map, but aren't usable, so screen them out
|
|
|
|
try {
|
|
for (unsigned u = 0x20; u < (unsigned) cwaMap.GetSize(); u++)
|
|
if (~(int)(short)cwaMap[u]) // 0xFFFF means not mapped!
|
|
cwaCollect.Add((WORD)u);
|
|
}
|
|
|
|
catch (CException * pce) {
|
|
pce -> ReportError();
|
|
pce -> Delete();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|