mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
502 lines
13 KiB
C++
502 lines
13 KiB
C++
#include "stdafx.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "MemoryUtils.h"
|
|
#include "File.h"
|
|
#include "StringExt.h"
|
|
#include "GlobalParams.h"
|
|
#include "PSLexer.h"
|
|
#include "CMap.h"
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
struct CMapVectorEntry
|
|
{
|
|
BOOL bIsVector;
|
|
CID nCID;
|
|
CMapVectorEntry *pVector;
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
static int GetCharFromFile(void *pFile)
|
|
{
|
|
return fgetc((FILE *)pFile);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
CMap *CMap::Parse(CMapCache *pCache, StringExt *seCollection, StringExt *seCMapName, GlobalParams *pGlobalParams, wchar_t *wsFilePath)
|
|
{
|
|
FILE *pFile = NULL;
|
|
char sToken1[256], sToken2[256], sToken3[256];
|
|
int nLen1, nLen2, nLen3;
|
|
|
|
if ( NULL != wsFilePath )
|
|
{
|
|
if ( !(pFile = _wfopen( wsFilePath, _T("r") )) )
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
if ( pGlobalParams && !( pFile = pGlobalParams->FindCMapFile( seCollection, seCMapName ) ) )
|
|
{
|
|
// Ïðîâåðÿåì íà Identity CMap.
|
|
if ( !seCMapName->Compare("Identity") || !seCMapName->Compare("Identity-H") )
|
|
{
|
|
return new CMap( pGlobalParams, seCollection->Copy(), seCMapName->Copy(), 0 );
|
|
}
|
|
if ( !seCMapName->Compare("Identity-V") )
|
|
{
|
|
return new CMap( pGlobalParams, seCollection->Copy(), seCMapName->Copy(), 1 );
|
|
}
|
|
|
|
// TO DO: Error "Couldn't find CMap file for collection"
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
CMap *pCMap = new CMap( pGlobalParams, seCollection->Copy(), seCMapName->Copy());
|
|
|
|
PSLexer *Lexer = new PSLexer(&GetCharFromFile, pFile);
|
|
Lexer->GetToken( sToken1, sizeof(sToken1), &nLen1);
|
|
|
|
while ( Lexer->GetToken( sToken2, sizeof(sToken2), &nLen2) )
|
|
{
|
|
if ( !strcmp( sToken2, "usecmap") )
|
|
{
|
|
if ( sToken1[0] == '/' )
|
|
{
|
|
pCMap->UseCMap( pCache, sToken1 + 1);
|
|
}
|
|
Lexer->GetToken( sToken1, sizeof(sToken1), &nLen1);
|
|
}
|
|
else if ( !strcmp( sToken1, "/WMode") )
|
|
{
|
|
pCMap->m_nWMode = atoi(sToken2);
|
|
Lexer->GetToken( sToken1, sizeof(sToken1), &nLen1);
|
|
}
|
|
else if ( !strcmp( sToken2, "begincodespacerange") )
|
|
{
|
|
while ( Lexer->GetToken( sToken1, sizeof(sToken1), &nLen1) )
|
|
{
|
|
if ( !strcmp(sToken1, "endcodespacerange") )
|
|
{
|
|
break;
|
|
}
|
|
if ( !Lexer->GetToken( sToken2, sizeof(sToken2), &nLen2) || !strcmp( sToken2, "endcodespacerange") )
|
|
{
|
|
// TO DO: Error "Illegal entry in codespacerange block in CMap"
|
|
break;
|
|
}
|
|
if ( sToken1[0] == '<' && sToken2[0] == '<' && nLen1 == nLen2 && nLen1 >= 4 && (nLen1 & 1) == 0)
|
|
{
|
|
unsigned int unStart = 0, unEnd = 0;
|
|
sToken1[nLen1 - 1] = sToken2[nLen1 - 1] = '\0';
|
|
sscanf( sToken1 + 1, "%x", &unStart);
|
|
sscanf( sToken2 + 1, "%x", &unEnd);
|
|
nLen1 = (nLen1 - 2) / 2;
|
|
pCMap->AddCodeSpace( pCMap->m_pVector, unStart, unEnd, nLen1);
|
|
}
|
|
}
|
|
Lexer->GetToken( sToken1, sizeof(sToken1), &nLen1);
|
|
}
|
|
else if ( !strcmp( sToken2, "begincidchar") )
|
|
{
|
|
while ( Lexer->GetToken( sToken1, sizeof(sToken1), &nLen1) )
|
|
{
|
|
if ( !strcmp( sToken1, "endcidchar") )
|
|
{
|
|
break;
|
|
}
|
|
if ( !Lexer->GetToken( sToken2, sizeof(sToken2), &nLen2) || !strcmp( sToken2, "endcidchar") )
|
|
{
|
|
// TO DO: Error "Illegal entry in cidchar block in CMap"
|
|
break;
|
|
}
|
|
if ( !( sToken1[0] == '<' && sToken1[nLen1 - 1] == '>' && nLen1 >= 4 && (nLen1 & 1) == 0) )
|
|
{
|
|
// TO DO: Error "Illegal entry in cidchar block in CMap"
|
|
continue;
|
|
}
|
|
sToken1[nLen1 - 1] = '\0';
|
|
unsigned int unCode = 0;
|
|
if ( sscanf( sToken1 + 1, "%x", &unCode) != 1 )
|
|
{
|
|
// TO DO: Error "Illegal entry in cidchar block in CMap"
|
|
continue;
|
|
}
|
|
nLen1 = (nLen1 - 2) / 2;
|
|
pCMap->AddCIDs( unCode, unCode, nLen1, (CID)atoi(sToken2));
|
|
}
|
|
Lexer->GetToken( sToken1, sizeof(sToken1), &nLen1);
|
|
}
|
|
else if ( !strcmp( sToken2, "begincidrange") )
|
|
{
|
|
while ( Lexer->GetToken( sToken1, sizeof(sToken1), &nLen1) )
|
|
{
|
|
if ( !strcmp( sToken1, "endcidrange") )
|
|
{
|
|
break;
|
|
}
|
|
if ( !Lexer->GetToken( sToken2, sizeof(sToken2), &nLen2) || !strcmp( sToken2, "endcidrange") || !Lexer->GetToken( sToken3, sizeof(sToken3), &nLen3) || !strcmp( sToken3, "endcidrange") )
|
|
{
|
|
// TO DO: Error "Illegal entry in cidrange block in CMap"
|
|
break;
|
|
}
|
|
if ( sToken1[0] == '<' && sToken2[0] == '<' && nLen1 == nLen2 && nLen1 >= 4 && (nLen1 & 1) == 0 )
|
|
{
|
|
unsigned int unStart = 0, unEnd = 0;
|
|
sToken1[nLen1 - 1] = sToken2[nLen1 - 1] = '\0';
|
|
sscanf( sToken1 + 1, "%x", &unStart);
|
|
sscanf( sToken2 + 1, "%x", &unEnd);
|
|
nLen1 = (nLen1 - 2) / 2;
|
|
pCMap->AddCIDs( unStart, unEnd, nLen1, (CID)atoi(sToken3));
|
|
}
|
|
}
|
|
Lexer->GetToken( sToken1, sizeof(sToken1), &nLen1);
|
|
}
|
|
else
|
|
{
|
|
strcpy( sToken1, sToken2);
|
|
}
|
|
}
|
|
delete Lexer;
|
|
|
|
fclose(pFile);
|
|
|
|
return pCMap;
|
|
}
|
|
|
|
CMap::CMap(GlobalParams *pGlobalParams, StringExt *seCollection, StringExt *seCMapName)
|
|
{
|
|
m_pGlobalParams = pGlobalParams;
|
|
|
|
m_seCollection = seCollection;
|
|
m_seCMapName = seCMapName;
|
|
m_nWMode = 0;
|
|
m_pVector = (CMapVectorEntry *)MemUtilsMallocArray( 256, sizeof(CMapVectorEntry) );
|
|
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
m_pVector[nIndex].bIsVector = FALSE;
|
|
m_pVector[nIndex].nCID = 0;
|
|
}
|
|
m_nRef = 1;
|
|
|
|
InitializeCriticalSection( &m_oCS );
|
|
}
|
|
|
|
CMap::CMap(GlobalParams *pGlobalParams, StringExt *seCollection, StringExt *seCMapName, int nWMode)
|
|
{
|
|
m_pGlobalParams = pGlobalParams;
|
|
|
|
m_seCollection = seCollection;
|
|
m_seCMapName = seCMapName;
|
|
m_nWMode = nWMode;
|
|
m_pVector = NULL;
|
|
m_nRef = 1;
|
|
|
|
InitializeCriticalSection( &m_oCS );
|
|
}
|
|
|
|
void CMap::UseCMap(CMapCache *pCache, char *sUseName)
|
|
{
|
|
StringExt *pUseNameStr = new StringExt(sUseName);
|
|
if ( !pUseNameStr )
|
|
return;
|
|
CMap *pSubCMap = pCache->GetCMap( m_seCollection, pUseNameStr, m_pGlobalParams );
|
|
delete pUseNameStr;
|
|
if ( !pSubCMap )
|
|
return;
|
|
CopyVector( m_pVector, pSubCMap->m_pVector);
|
|
pSubCMap->Release();
|
|
}
|
|
|
|
void CMap::CopyVector(CMapVectorEntry *pDest, CMapVectorEntry *pSrc)
|
|
{
|
|
for ( int nSrcIndex = 0; nSrcIndex < 256; ++nSrcIndex )
|
|
{
|
|
if ( pSrc[nSrcIndex].bIsVector )
|
|
{
|
|
if ( !pDest[nSrcIndex].bIsVector )
|
|
{
|
|
pDest[nSrcIndex].bIsVector = TRUE;
|
|
pDest[nSrcIndex].pVector = (CMapVectorEntry *)MemUtilsMallocArray(256, sizeof(CMapVectorEntry));
|
|
for ( int pDstIndex = 0; pDstIndex < 256; ++pDstIndex )
|
|
{
|
|
pDest[nSrcIndex].pVector[pDstIndex].bIsVector = FALSE;
|
|
pDest[nSrcIndex].pVector[pDstIndex].nCID = 0;
|
|
}
|
|
}
|
|
CopyVector( pDest[nSrcIndex].pVector, pSrc[nSrcIndex].pVector);
|
|
}
|
|
else
|
|
{
|
|
if ( pDest[nSrcIndex].bIsVector )
|
|
{
|
|
// TO DO: Error "Collision in usecmap"
|
|
}
|
|
else
|
|
{
|
|
pDest[nSrcIndex].nCID = pSrc[nSrcIndex].nCID;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMap::AddCodeSpace(CMapVectorEntry *pVector, unsigned int unStart, unsigned int unEnd, unsigned int unBytesCount)
|
|
{
|
|
if ( unBytesCount > 1 )
|
|
{
|
|
int nStartByte = (unStart >> (8 * (unBytesCount - 1))) & 0xff;
|
|
int nEndByte = (unEnd >> (8 * (unBytesCount - 1))) & 0xff;
|
|
unsigned int unStart2 = unStart & ((1 << (8 * (unBytesCount - 1))) - 1);
|
|
unsigned int unEnd2 = unEnd & ((1 << (8 * (unBytesCount - 1))) - 1);
|
|
for ( int nI = nStartByte; nI <= nEndByte; ++nI )
|
|
{
|
|
if ( !pVector[nI].bIsVector )
|
|
{
|
|
pVector[nI].bIsVector = TRUE;
|
|
pVector[nI].pVector = (CMapVectorEntry *)MemUtilsMallocArray(256, sizeof(CMapVectorEntry));
|
|
for ( int nJ = 0; nJ < 256; ++nJ )
|
|
{
|
|
pVector[nI].pVector[nJ].bIsVector = FALSE;
|
|
pVector[nI].pVector[nJ].nCID = 0;
|
|
}
|
|
}
|
|
AddCodeSpace( pVector[nI].pVector, unStart2, unEnd2, unBytesCount - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMap::AddCIDs(unsigned int unStart, unsigned int unEnd, unsigned int unBytesCount, CID nFirstCID)
|
|
{
|
|
CMapVectorEntry *pVector = m_pVector;
|
|
for ( unsigned int nIndex = unBytesCount - 1; nIndex >= 1; --nIndex )
|
|
{
|
|
int nByte = (unStart >> (8 * nIndex)) & 0xff;
|
|
if ( !pVector[nByte].bIsVector )
|
|
{
|
|
// TO DO: Error "Invalid CID in CMap"
|
|
return;
|
|
}
|
|
pVector = pVector[nByte].pVector;
|
|
}
|
|
CID nCID = nFirstCID;
|
|
for ( int nByte = (int)(unStart & 0xff); nByte <= (int)(unEnd & 0xff); ++nByte )
|
|
{
|
|
if ( pVector[nByte].bIsVector )
|
|
{
|
|
// TO DO: Error "Invalid CID in CMap"
|
|
}
|
|
else
|
|
{
|
|
pVector[nByte].nCID = nCID;
|
|
}
|
|
++nCID;
|
|
}
|
|
}
|
|
|
|
CMap::~CMap()
|
|
{
|
|
if ( m_seCollection )
|
|
delete m_seCollection;
|
|
|
|
if ( m_seCMapName )
|
|
delete m_seCMapName;
|
|
if ( m_pVector )
|
|
{
|
|
FreeCMapVector(m_pVector);
|
|
}
|
|
|
|
DeleteCriticalSection( &m_oCS );
|
|
}
|
|
|
|
void CMap::FreeCMapVector(CMapVectorEntry *pVector)
|
|
{
|
|
for ( int nIndex = 0; nIndex < 256; ++nIndex )
|
|
{
|
|
if ( pVector[nIndex].bIsVector )
|
|
{
|
|
FreeCMapVector( pVector[nIndex].pVector);
|
|
}
|
|
}
|
|
MemUtilsFree(pVector);
|
|
}
|
|
|
|
void CMap::AddRef()
|
|
{
|
|
CTemporaryCS *pCS = new CTemporaryCS( &m_oCS );
|
|
++m_nRef;
|
|
|
|
RELEASEOBJECT( pCS );
|
|
}
|
|
|
|
void CMap::Release()
|
|
{
|
|
CTemporaryCS *pCS = new CTemporaryCS( &m_oCS );
|
|
|
|
BOOL bDelete = (--m_nRef == 0);
|
|
|
|
RELEASEOBJECT( pCS );
|
|
|
|
if ( bDelete )
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
BOOL CMap::Match(StringExt *seCollection, StringExt *seCMapName)
|
|
{
|
|
return !m_seCollection->Compare(seCollection) && !m_seCMapName->Compare(seCMapName);
|
|
}
|
|
|
|
CID CMap::GetCID(char *sChar, int nLen, int *pnUsed)
|
|
{
|
|
CMapVectorEntry *pVector;
|
|
|
|
if ( !( pVector = m_pVector ) )
|
|
{
|
|
// Identity CMap
|
|
*pnUsed = 2;
|
|
if ( nLen < 2 )
|
|
{
|
|
return 0;
|
|
}
|
|
return ((sChar[0] & 0xff) << 8) + (sChar[1] & 0xff);
|
|
}
|
|
int nUsedCount = 0;
|
|
while (1)
|
|
{
|
|
if ( nUsedCount >= nLen )
|
|
{
|
|
*pnUsed = nUsedCount;
|
|
return 0;
|
|
}
|
|
int nIndex = sChar[nUsedCount++] & 0xff;
|
|
if ( !pVector[nIndex].bIsVector )
|
|
{
|
|
*pnUsed = nUsedCount;
|
|
return pVector[nIndex].nCID;
|
|
}
|
|
pVector = pVector[nIndex].pVector;
|
|
}
|
|
}
|
|
|
|
void CMap::ToXml(CString sFilePath)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
XmlUtils::CXmlWriter oWriter;
|
|
|
|
oWriter.WriteNodeBegin( _T("PDF-CMap"), TRUE );
|
|
oWriter.WriteAttribute( _T("collection"), A2W( m_seCollection->GetBuffer() ) );
|
|
oWriter.WriteAttribute( _T("name"), A2W( m_seCMapName->GetBuffer() ) );
|
|
oWriter.WriteNodeEnd( _T("PDF-CMap"), TRUE, FALSE );
|
|
|
|
if ( !m_seCMapName->Compare("Identity") || !m_seCMapName->Compare("Identity-H") || !m_seCMapName->Compare("Identity-V") )
|
|
WriteVectorToXml( &oWriter, m_pVector );
|
|
|
|
oWriter.WriteNodeEnd( _T("PDF-CMap"), FALSE, TRUE );
|
|
|
|
oWriter.SaveToFile( sFilePath );
|
|
}
|
|
|
|
void CMap::WriteVectorToXml(XmlUtils::CXmlWriter *pWriter, CMapVectorEntry *pVector)
|
|
{
|
|
if ( NULL == pVector )
|
|
return;
|
|
|
|
for ( int nIndex = 0; nIndex < 256; nIndex++ )
|
|
{
|
|
if ( 0 != pVector[nIndex].nCID || FALSE != pVector[nIndex].bIsVector )
|
|
{
|
|
if ( pVector[nIndex].bIsVector )
|
|
{
|
|
pWriter->WriteNodeBegin( _T("Vector"), TRUE );
|
|
pWriter->WriteAttribute( _T("index"), nIndex );
|
|
pWriter->WriteAttribute( _T("isvector"), 1 );
|
|
pWriter->WriteAttribute( _T("cid"), (int)pVector[nIndex].nCID );
|
|
pWriter->WriteNodeEnd( _T("Vector"), TRUE, FALSE );
|
|
|
|
WriteVectorToXml( pWriter, pVector[nIndex].pVector );
|
|
|
|
pWriter->WriteNodeEnd( _T("Vector"), FALSE, TRUE );
|
|
}
|
|
else
|
|
{
|
|
pWriter->WriteNodeBegin( _T("Vector"), TRUE );
|
|
pWriter->WriteAttribute( _T("index"), nIndex );
|
|
pWriter->WriteAttribute( _T("isvector"), 0 );
|
|
pWriter->WriteAttribute( _T("cid"), (int)pVector[nIndex].nCID );
|
|
pWriter->WriteNodeEnd( _T("Vector"), TRUE, TRUE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
CMapCache::CMapCache()
|
|
{
|
|
for ( int nIndex = 0; nIndex < CMapCacheSize; ++nIndex )
|
|
{
|
|
m_ppCache[nIndex] = NULL;
|
|
}
|
|
}
|
|
|
|
CMapCache::~CMapCache()
|
|
{
|
|
for ( int nIndex = 0; nIndex < CMapCacheSize; ++nIndex )
|
|
{
|
|
if ( m_ppCache[nIndex] )
|
|
{
|
|
m_ppCache[nIndex]->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
CMap *CMapCache::GetCMap(StringExt *seCollection, StringExt *seCMapName, GlobalParams* pGlobalParams, wchar_t *wsFilePath)
|
|
{
|
|
CMap *pCMap = NULL;
|
|
|
|
if ( m_ppCache[0] && m_ppCache[0]->Match( seCollection, seCMapName) )
|
|
{
|
|
m_ppCache[0]->AddRef();
|
|
return m_ppCache[0];
|
|
}
|
|
|
|
for ( int nIndex = 1; nIndex < CMapCacheSize; ++nIndex )
|
|
{
|
|
if ( m_ppCache[nIndex] && m_ppCache[nIndex]->Match( seCollection, seCMapName) )
|
|
{
|
|
pCMap = m_ppCache[nIndex];
|
|
for ( int nJ = nIndex; nJ >= 1; --nJ )
|
|
{
|
|
m_ppCache[nJ] = m_ppCache[nJ - 1];
|
|
}
|
|
m_ppCache[0] = pCMap;
|
|
pCMap->AddRef();
|
|
return pCMap;
|
|
}
|
|
}
|
|
if ( ( pCMap = CMap::Parse(this, seCollection, seCMapName, pGlobalParams, wsFilePath) ) )
|
|
{
|
|
if ( m_ppCache[CMapCacheSize - 1] )
|
|
{
|
|
m_ppCache[CMapCacheSize - 1]->Release();
|
|
}
|
|
for ( int nJ = CMapCacheSize - 1; nJ >= 1; --nJ )
|
|
{
|
|
m_ppCache[nJ] = m_ppCache[nJ - 1];
|
|
}
|
|
m_ppCache[0] = pCMap;
|
|
pCMap->AddRef();
|
|
return pCMap;
|
|
}
|
|
return NULL;
|
|
}
|