summaryrefslogtreecommitdiff
path: root/Build/source/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
committerKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
commitad547a6b5986815fda458221149728d9d9ab1d87 (patch)
tree16296910eb3eca724371474ea9aea3994dc69614 /Build/source/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc
parent947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff)
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc')
-rw-r--r--Build/source/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc787
1 files changed, 787 insertions, 0 deletions
diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc
new file mode 100644
index 00000000000..5eec7a9fc6c
--- /dev/null
+++ b/Build/source/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc
@@ -0,0 +1,787 @@
+//========================================================================
+//
+// CharCodeToUnicode.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "gmem.h"
+#include "gmempp.h"
+#include "gfile.h"
+#include "GString.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "PSTokenizer.h"
+#include "CharCodeToUnicode.h"
+
+//------------------------------------------------------------------------
+
+#define maxUnicodeString 8
+
+struct CharCodeToUnicodeString {
+ CharCode c;
+ Unicode u[maxUnicodeString];
+ int len;
+};
+
+//------------------------------------------------------------------------
+
+struct GStringIndex {
+ GString *s;
+ int i;
+};
+
+static int getCharFromGString(void *data) {
+ GStringIndex *idx = (GStringIndex *)data;
+ if (idx->i >= idx->s->getLength()) {
+ return EOF;
+ }
+ return idx->s->getChar(idx->i++) & 0xff;
+}
+
+static int getCharFromFile(void *data) {
+ return fgetc((FILE *)data);
+}
+
+//------------------------------------------------------------------------
+
+static int hexCharVals[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2x
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 3x
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5x
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 8x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 9x
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ax
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Bx
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Cx
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Dx
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ex
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // Fx
+};
+
+// Parse a <len>-byte hex string <s> into *<val>. Returns false on
+// error.
+static GBool parseHex(char *s, int len, Guint *val) {
+ int i, x;
+
+ *val = 0;
+ for (i = 0; i < len; ++i) {
+ x = hexCharVals[s[i] & 0xff];
+ if (x < 0) {
+ return gFalse;
+ }
+ *val = (*val << 4) + x;
+ }
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+
+CharCodeToUnicode *CharCodeToUnicode::makeIdentityMapping() {
+ return new CharCodeToUnicode();
+}
+
+CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName,
+ GString *collection) {
+ FILE *f;
+ Unicode *mapA;
+ CharCode size, mapLenA;
+ char buf[64];
+ Unicode u;
+ CharCodeToUnicode *ctu;
+
+ if (!(f = openFile(fileName->getCString(), "r"))) {
+ error(errSyntaxError, -1, "Couldn't open cidToUnicode file '{0:t}'",
+ fileName);
+ return NULL;
+ }
+
+ size = 32768;
+ mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
+ mapLenA = 0;
+
+ while (getLine(buf, sizeof(buf), f)) {
+ if (mapLenA == size) {
+ size *= 2;
+ mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
+ }
+ if (sscanf(buf, "%x", &u) == 1) {
+ mapA[mapLenA] = u;
+ } else {
+ error(errSyntaxWarning, -1,
+ "Bad line ({0:d}) in cidToUnicode file '{1:t}'",
+ (int)(mapLenA + 1), fileName);
+ mapA[mapLenA] = 0;
+ }
+ ++mapLenA;
+ }
+ fclose(f);
+
+ ctu = new CharCodeToUnicode(collection->copy(), mapA, mapLenA, gTrue,
+ NULL, 0, 0);
+ gfree(mapA);
+ return ctu;
+}
+
+CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(
+ GString *fileName) {
+ FILE *f;
+ Unicode *mapA;
+ CharCodeToUnicodeString *sMapA;
+ CharCode size, oldSize, len, sMapSizeA, sMapLenA;
+ char buf[256];
+ char *tok;
+ Unicode u0;
+ Unicode uBuf[maxUnicodeString];
+ CharCodeToUnicode *ctu;
+ int line, n, i;
+
+ if (!(f = openFile(fileName->getCString(), "r"))) {
+ error(errSyntaxError, -1, "Couldn't open unicodeToUnicode file '{0:t}'",
+ fileName);
+ return NULL;
+ }
+
+ size = 4096;
+ mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
+ memset(mapA, 0, size * sizeof(Unicode));
+ len = 0;
+ sMapA = NULL;
+ sMapSizeA = sMapLenA = 0;
+
+ line = 0;
+ while (getLine(buf, sizeof(buf), f)) {
+ ++line;
+ if (!(tok = strtok(buf, " \t\r\n")) ||
+ !parseHex(tok, (int)strlen(tok), &u0)) {
+ error(errSyntaxWarning, -1,
+ "Bad line ({0:d}) in unicodeToUnicode file '{1:t}'",
+ line, fileName);
+ continue;
+ }
+ n = 0;
+ while (n < maxUnicodeString) {
+ if (!(tok = strtok(NULL, " \t\r\n"))) {
+ break;
+ }
+ if (!parseHex(tok, (int)strlen(tok), &uBuf[n])) {
+ error(errSyntaxWarning, -1,
+ "Bad line ({0:d}) in unicodeToUnicode file '{1:t}'",
+ line, fileName);
+ break;
+ }
+ ++n;
+ }
+ if (n < 1) {
+ error(errSyntaxWarning, -1,
+ "Bad line ({0:d}) in unicodeToUnicode file '{1:t}'",
+ line, fileName);
+ continue;
+ }
+ if (u0 >= size) {
+ oldSize = size;
+ while (u0 >= size) {
+ size *= 2;
+ }
+ mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
+ memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode));
+ }
+ if (n == 1) {
+ mapA[u0] = uBuf[0];
+ } else {
+ mapA[u0] = 0;
+ if (sMapLenA == sMapSizeA) {
+ sMapSizeA += 16;
+ sMapA = (CharCodeToUnicodeString *)
+ greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString));
+ }
+ sMapA[sMapLenA].c = u0;
+ for (i = 0; i < n; ++i) {
+ sMapA[sMapLenA].u[i] = uBuf[i];
+ }
+ sMapA[sMapLenA].len = n;
+ ++sMapLenA;
+ }
+ if (u0 >= len) {
+ len = u0 + 1;
+ }
+ }
+ fclose(f);
+
+ ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue,
+ sMapA, sMapLenA, sMapSizeA);
+ gfree(mapA);
+ return ctu;
+}
+
+CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) {
+ return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0);
+}
+
+CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) {
+ CharCodeToUnicode *ctu;
+ GStringIndex idx;
+
+ ctu = new CharCodeToUnicode(NULL);
+ idx.s = buf;
+ idx.i = 0;
+ if (!ctu->parseCMap1(&getCharFromGString, &idx, nBits)) {
+ delete ctu;
+ return NULL;
+ }
+ return ctu;
+}
+
+void CharCodeToUnicode::mergeCMap(GString *buf, int nBits) {
+ GStringIndex idx;
+
+ idx.s = buf;
+ idx.i = 0;
+ parseCMap1(&getCharFromGString, &idx, nBits);
+}
+
+GBool CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
+ int nBits) {
+ PSTokenizer *pst;
+ char tok1[256], tok2[256], tok3[256];
+ int n1, n2, n3;
+ CharCode i;
+ CharCode maxCode, code1, code2;
+ GString *name;
+ FILE *f;
+ GBool ok;
+
+ ok = gFalse;
+ maxCode = (nBits == 8) ? 0xff : (nBits == 16) ? 0xffff : 0xffffffff;
+ pst = new PSTokenizer(getCharFunc, data);
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ while (pst->getToken(tok2, sizeof(tok2), &n2)) {
+ if (!strcmp(tok2, "usecmap")) {
+ if (tok1[0] == '/') {
+ name = new GString(tok1 + 1);
+ if ((f = globalParams->findToUnicodeFile(name))) {
+ if (parseCMap1(&getCharFromFile, f, nBits)) {
+ ok = gTrue;
+ }
+ fclose(f);
+ } else {
+ error(errSyntaxError, -1,
+ "Couldn't find ToUnicode CMap file for '{1:t}'",
+ name);
+ }
+ delete name;
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "beginbfchar")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endbfchar")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endbfchar")) {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in bfchar block in ToUnicode CMap");
+ break;
+ }
+ if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ tok2[0] == '<' && tok2[n2 - 1] == '>')) {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in bfchar block in ToUnicode CMap");
+ continue;
+ }
+ tok1[n1 - 1] = tok2[n2 - 1] = '\0';
+ if (!parseHex(tok1 + 1, n1 - 2, &code1)) {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in bfchar block in ToUnicode CMap");
+ continue;
+ }
+ if (code1 > maxCode) {
+ error(errSyntaxWarning, -1,
+ "Invalid entry in bfchar block in ToUnicode CMap");
+ }
+ addMapping(code1, tok2 + 1, n2 - 2, 0);
+ ok = gTrue;
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "beginbfrange")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endbfrange")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endbfrange") ||
+ !pst->getToken(tok3, sizeof(tok3), &n3) ||
+ !strcmp(tok3, "endbfrange")) {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in bfrange block in ToUnicode CMap");
+ break;
+ }
+ if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ tok2[0] == '<' && tok2[n2 - 1] == '>')) {
+ error(errSyntaxWarning,
+ -1, "Illegal entry in bfrange block in ToUnicode CMap");
+ continue;
+ }
+ tok1[n1 - 1] = tok2[n2 - 1] = '\0';
+ if (!parseHex(tok1 + 1, n1 - 2, &code1) ||
+ !parseHex(tok2 + 1, n2 - 2, &code2)) {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in bfrange block in ToUnicode CMap");
+ continue;
+ }
+ if (code1 > maxCode || code2 > maxCode) {
+ error(errSyntaxWarning, -1,
+ "Invalid entry in bfrange block in ToUnicode CMap");
+ if (code2 > maxCode) {
+ code2 = maxCode;
+ }
+ }
+ if (!strcmp(tok3, "[")) {
+ i = 0;
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "]")) {
+ break;
+ }
+ if (tok1[0] == '<' && tok1[n1 - 1] == '>') {
+ if (code1 + i <= code2) {
+ tok1[n1 - 1] = '\0';
+ addMapping(code1 + i, tok1 + 1, n1 - 2, 0);
+ ok = gTrue;
+ }
+ } else {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in bfrange block in ToUnicode CMap");
+ }
+ ++i;
+ }
+ } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') {
+ tok3[n3 - 1] = '\0';
+ for (i = 0; code1 <= code2; ++code1, ++i) {
+ addMapping(code1, tok3 + 1, n3 - 2, i);
+ ok = gTrue;
+ }
+ } else {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in bfrange block in ToUnicode CMap");
+ }
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "begincidchar")) {
+ // the begincidchar operator is not allowed in ToUnicode CMaps,
+ // but some buggy PDF generators incorrectly use
+ // code-to-CID-type CMaps here
+ error(errSyntaxWarning, -1,
+ "Invalid 'begincidchar' operator in ToUnicode CMap");
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endcidchar")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endcidchar")) {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in cidchar block in ToUnicode CMap");
+ break;
+ }
+ if (!(tok1[0] == '<' && tok1[n1 - 1] == '>')) {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in cidchar block in ToUnicode CMap");
+ continue;
+ }
+ tok1[n1 - 1] = '\0';
+ if (!parseHex(tok1 + 1, n1 - 2, &code1)) {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in cidchar block in ToUnicode CMap");
+ continue;
+ }
+ if (code1 > maxCode) {
+ error(errSyntaxWarning, -1,
+ "Invalid entry in cidchar block in ToUnicode CMap");
+ }
+ addMappingInt(code1, atoi(tok2));
+ ok = gTrue;
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "begincidrange")) {
+ // the begincidrange operator is not allowed in ToUnicode CMaps,
+ // but some buggy PDF generators incorrectly use
+ // code-to-CID-type CMaps here
+ error(errSyntaxWarning, -1,
+ "Invalid 'begincidrange' operator in ToUnicode CMap");
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endcidrange")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endcidrange") ||
+ !pst->getToken(tok3, sizeof(tok3), &n3) ||
+ !strcmp(tok3, "endcidrange")) {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in cidrange block in ToUnicode CMap");
+ break;
+ }
+ if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ tok2[0] == '<' && tok2[n2 - 1] == '>')) {
+ error(errSyntaxWarning,
+ -1, "Illegal entry in cidrange block in ToUnicode CMap");
+ continue;
+ }
+ tok1[n1 - 1] = tok2[n2 - 1] = '\0';
+ if (!parseHex(tok1 + 1, n1 - 2, &code1) ||
+ !parseHex(tok2 + 1, n2 - 2, &code2)) {
+ error(errSyntaxWarning, -1,
+ "Illegal entry in cidrange block in ToUnicode CMap");
+ continue;
+ }
+ if (code1 > maxCode || code2 > maxCode) {
+ error(errSyntaxWarning, -1,
+ "Invalid entry in cidrange block in ToUnicode CMap");
+ if (code2 > maxCode) {
+ code2 = maxCode;
+ }
+ }
+ for (i = atoi(tok3); code1 <= code2; ++code1, ++i) {
+ addMappingInt(code1, i);
+ ok = gTrue;
+ }
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else {
+ strcpy(tok1, tok2);
+ }
+ }
+ delete pst;
+ return ok;
+}
+
+void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n,
+ int offset) {
+ CharCode oldLen, i;
+#if 1 //~utf16
+ Unicode u[maxUnicodeString];
+ int uLen, j;
+#else
+ Unicode u;
+ int j;
+#endif
+
+ if (code > 0xffffff) {
+ // This is an arbitrary limit to avoid integer overflow issues.
+ // (I've seen CMaps with mappings for <ffffffff>.)
+ return;
+ }
+#if 1 //~utf16
+ if ((uLen = parseUTF16String(uStr, n, u)) == 0) {
+ return;
+ }
+#endif
+ if (code >= mapLen) {
+ oldLen = mapLen;
+ mapLen = mapLen ? 2 * mapLen : 256;
+ if (code >= mapLen) {
+ mapLen = (code + 256) & ~255;
+ }
+ map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode));
+ for (i = oldLen; i < mapLen; ++i) {
+ map[i] = 0;
+ }
+ }
+#if 1 //~utf16
+ if (uLen == 1) {
+ map[code] = u[0] + offset;
+ } else {
+ if (sMapLen >= sMapSize) {
+ sMapSize = sMapSize + 16;
+ sMap = (CharCodeToUnicodeString *)
+ greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+ }
+ map[code] = 0;
+ sMap[sMapLen].c = code;
+ for (j = 0; j < uLen; ++j) {
+ sMap[sMapLen].u[j] = u[j];
+ }
+ sMap[sMapLen].u[uLen - 1] += offset;
+ sMap[sMapLen].len = uLen;
+ ++sMapLen;
+ }
+#else //~utf16
+ if (n <= 4) {
+ if (!parseHex(uStr, n, &u)) {
+ error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap");
+ return;
+ }
+ map[code] = u + offset;
+ } else {
+ if (sMapLen >= sMapSize) {
+ sMapSize = sMapSize + 16;
+ sMap = (CharCodeToUnicodeString *)
+ greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+ }
+ map[code] = 0;
+ sMap[sMapLen].c = code;
+ if ((sMap[sMapLen].len = n / 4) > maxUnicodeString) {
+ sMap[sMapLen].len = maxUnicodeString;
+ }
+ for (j = 0; j < sMap[sMapLen].len; ++j) {
+ if (!parseHex(uStr + j*4, 4, &sMap[sMapLen].u[j])) {
+ error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap");
+ return;
+ }
+ }
+ sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset;
+ ++sMapLen;
+ }
+#endif //~utf16
+}
+
+// Convert a UTF-16BE hex string into a sequence of up to
+// maxUnicodeString Unicode chars.
+int CharCodeToUnicode::parseUTF16String(char *uStr, int n, Unicode *uOut) {
+ int i = 0;
+ int uLen = 0;
+ while (i < n) {
+ Unicode u;
+ int j = n;
+ if (j - i > 4) {
+ j = i + 4;
+ }
+ if (!parseHex(uStr + i, j - i, &u)) {
+ error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap");
+ return 0;
+ }
+ // look for a UTF-16 pair
+ if (uLen > 0 && uOut[uLen-1] >= 0xd800 && uOut[uLen-1] <= 0xdbff &&
+ u >= 0xdc00 && u <= 0xdfff) {
+ uOut[uLen-1] = 0x10000 + ((uOut[uLen-1] & 0x03ff) << 10) + (u & 0x03ff);
+ } else {
+ if (uLen < maxUnicodeString) {
+ uOut[uLen++] = u;
+ }
+ }
+ i = j;
+ }
+ return uLen;
+}
+
+void CharCodeToUnicode::addMappingInt(CharCode code, Unicode u) {
+ CharCode oldLen, i;
+
+ if (code > 0xffffff) {
+ // This is an arbitrary limit to avoid integer overflow issues.
+ // (I've seen CMaps with mappings for <ffffffff>.)
+ return;
+ }
+ if (code >= mapLen) {
+ oldLen = mapLen;
+ mapLen = mapLen ? 2 * mapLen : 256;
+ if (code >= mapLen) {
+ mapLen = (code + 256) & ~255;
+ }
+ map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode));
+ for (i = oldLen; i < mapLen; ++i) {
+ map[i] = 0;
+ }
+ }
+ map[code] = u;
+}
+
+CharCodeToUnicode::CharCodeToUnicode() {
+ tag = NULL;
+ map = NULL;
+ mapLen = 0;
+ sMap = NULL;
+ sMapLen = sMapSize = 0;
+ refCnt = 1;
+}
+
+CharCodeToUnicode::CharCodeToUnicode(GString *tagA) {
+ CharCode i;
+
+ tag = tagA;
+ mapLen = 256;
+ map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
+ for (i = 0; i < mapLen; ++i) {
+ map[i] = 0;
+ }
+ sMap = NULL;
+ sMapLen = sMapSize = 0;
+ refCnt = 1;
+}
+
+CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA,
+ CharCode mapLenA, GBool copyMap,
+ CharCodeToUnicodeString *sMapA,
+ int sMapLenA, int sMapSizeA) {
+ tag = tagA;
+ mapLen = mapLenA;
+ if (copyMap) {
+ map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
+ memcpy(map, mapA, mapLen * sizeof(Unicode));
+ } else {
+ map = mapA;
+ }
+ sMap = sMapA;
+ sMapLen = sMapLenA;
+ sMapSize = sMapSizeA;
+ refCnt = 1;
+}
+
+CharCodeToUnicode::~CharCodeToUnicode() {
+ if (tag) {
+ delete tag;
+ }
+ gfree(map);
+ gfree(sMap);
+}
+
+void CharCodeToUnicode::incRefCnt() {
+#if MULTITHREADED
+ gAtomicIncrement(&refCnt);
+#else
+ ++refCnt;
+#endif
+}
+
+void CharCodeToUnicode::decRefCnt() {
+ GBool done;
+
+#if MULTITHREADED
+ done = gAtomicDecrement(&refCnt) == 0;
+#else
+ done = --refCnt == 0;
+#endif
+ if (done) {
+ delete this;
+ }
+}
+
+GBool CharCodeToUnicode::match(GString *tagA) {
+ return tag && !tag->cmp(tagA);
+}
+
+void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) {
+ int i, j;
+
+ if (!map) {
+ return;
+ }
+ if (len == 1) {
+ map[c] = u[0];
+ } else {
+ for (i = 0; i < sMapLen; ++i) {
+ if (sMap[i].c == c) {
+ break;
+ }
+ }
+ if (i == sMapLen) {
+ if (sMapLen == sMapSize) {
+ sMapSize += 8;
+ sMap = (CharCodeToUnicodeString *)
+ greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+ }
+ ++sMapLen;
+ }
+ map[c] = 0;
+ sMap[i].c = c;
+ sMap[i].len = len;
+ for (j = 0; j < len && j < maxUnicodeString; ++j) {
+ sMap[i].u[j] = u[j];
+ }
+ }
+}
+
+int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) {
+ int i, j;
+
+ if (!map) {
+ u[0] = (Unicode)c;
+ return 1;
+ }
+ if (c >= mapLen) {
+ return 0;
+ }
+ if (map[c]) {
+ u[0] = map[c];
+ return 1;
+ }
+ for (i = 0; i < sMapLen; ++i) {
+ if (sMap[i].c == c) {
+ for (j = 0; j < sMap[i].len && j < size; ++j) {
+ u[j] = sMap[i].u[j];
+ }
+ return j;
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------
+
+CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) {
+ int i;
+
+ size = sizeA;
+ cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *));
+ for (i = 0; i < size; ++i) {
+ cache[i] = NULL;
+ }
+}
+
+CharCodeToUnicodeCache::~CharCodeToUnicodeCache() {
+ int i;
+
+ for (i = 0; i < size; ++i) {
+ if (cache[i]) {
+ cache[i]->decRefCnt();
+ }
+ }
+ gfree(cache);
+}
+
+CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GString *tag) {
+ CharCodeToUnicode *ctu;
+ int i, j;
+
+ if (cache[0] && cache[0]->match(tag)) {
+ cache[0]->incRefCnt();
+ return cache[0];
+ }
+ for (i = 1; i < size; ++i) {
+ if (cache[i] && cache[i]->match(tag)) {
+ ctu = cache[i];
+ for (j = i; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = ctu;
+ ctu->incRefCnt();
+ return ctu;
+ }
+ }
+ return NULL;
+}
+
+void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) {
+ int i;
+
+ if (cache[size - 1]) {
+ cache[size - 1]->decRefCnt();
+ }
+ for (i = size - 1; i >= 1; --i) {
+ cache[i] = cache[i - 1];
+ }
+ cache[0] = ctu;
+ ctu->incRefCnt();
+}