[poppler] Branch 'xpdf303merge' - CMakeLists.txt fofi/FoFiIdentifier.cc fofi/FoFiIdentifier.h fofi/Makefile.am
Albert Astals Cid
aacid at kemper.freedesktop.org
Tue Aug 30 08:36:27 PDT 2011
CMakeLists.txt | 2
fofi/FoFiIdentifier.cc | 630 +++++++++++++++++++++++++++++++++++++++++++++++++
fofi/FoFiIdentifier.h | 42 +++
fofi/Makefile.am | 2
4 files changed, 676 insertions(+)
New commits:
commit 39ce4575f96953b499d09074e847d492d18379fa
Author: Albert Astals Cid <aacid at kde.org>
Date: Tue Aug 30 17:39:30 2011 +0200
xpdf303: Add FoFiIdentifier
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1db4be1..103ac73 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -214,6 +214,7 @@ set(poppler_SRCS
fofi/FoFiTrueType.cc
fofi/FoFiType1.cc
fofi/FoFiType1C.cc
+ fofi/FoFiIdentifier.cc
poppler/Annot.cc
poppler/Array.cc
poppler/BuiltinFont.cc
@@ -460,6 +461,7 @@ if(ENABLE_XPDF_HEADERS)
fofi/FoFiTrueType.h
fofi/FoFiType1.h
fofi/FoFiType1C.h
+ fofi/FoFiIdentifier.h
DESTINATION include/poppler/fofi)
if(ENABLE_LIBCURL)
install(FILES
diff --git a/fofi/FoFiIdentifier.cc b/fofi/FoFiIdentifier.cc
new file mode 100644
index 0000000..0864a23
--- /dev/null
+++ b/fofi/FoFiIdentifier.cc
@@ -0,0 +1,630 @@
+//========================================================================
+//
+// FoFiIdentifier.cc
+//
+// Copyright 2009 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include "gtypes.h"
+#include "FoFiIdentifier.h"
+
+//------------------------------------------------------------------------
+
+class Reader {
+public:
+
+ virtual ~Reader() {}
+
+ // Read one byte. Returns -1 if past EOF.
+ virtual int getByte(int pos) = 0;
+
+ // Read a big-endian unsigned 16-bit integer. Fills in *val and
+ // returns true if successful.
+ virtual GBool getU16BE(int pos, int *val) = 0;
+
+ // Read a big-endian unsigned 32-bit integer. Fills in *val and
+ // returns true if successful.
+ virtual GBool getU32BE(int pos, Guint *val) = 0;
+
+ // Read a little-endian unsigned 32-bit integer. Fills in *val and
+ // returns true if successful.
+ virtual GBool getU32LE(int pos, Guint *val) = 0;
+
+ // Read a big-endian unsigned <size>-byte integer, where 1 <= size
+ // <= 4. Fills in *val and returns true if successful.
+ virtual GBool getUVarBE(int pos, int size, Guint *val) = 0;
+
+ // Compare against a string. Returns true if equal.
+ virtual GBool cmp(int pos, const char *s) = 0;
+
+};
+
+//------------------------------------------------------------------------
+
+class MemReader: public Reader {
+public:
+
+ static MemReader *make(char *bufA, int lenA);
+ virtual ~MemReader();
+ virtual int getByte(int pos);
+ virtual GBool getU16BE(int pos, int *val);
+ virtual GBool getU32BE(int pos, Guint *val);
+ virtual GBool getU32LE(int pos, Guint *val);
+ virtual GBool getUVarBE(int pos, int size, Guint *val);
+ virtual GBool cmp(int pos, const char *s);
+
+private:
+
+ MemReader(char *bufA, int lenA);
+
+ char *buf;
+ int len;
+};
+
+MemReader *MemReader::make(char *bufA, int lenA) {
+ return new MemReader(bufA, lenA);
+}
+
+MemReader::MemReader(char *bufA, int lenA) {
+ buf = bufA;
+ len = lenA;
+}
+
+MemReader::~MemReader() {
+}
+
+int MemReader::getByte(int pos) {
+ if (pos < 0 || pos >= len) {
+ return -1;
+ }
+ return buf[pos] & 0xff;
+}
+
+GBool MemReader::getU16BE(int pos, int *val) {
+ if (pos < 0 || pos > len - 2) {
+ return gFalse;
+ }
+ *val = ((buf[pos] & 0xff) << 8) +
+ (buf[pos+1] & 0xff);
+ return gTrue;
+}
+
+GBool MemReader::getU32BE(int pos, Guint *val) {
+ if (pos < 0 || pos > len - 4) {
+ return gFalse;
+ }
+ *val = ((buf[pos] & 0xff) << 24) +
+ ((buf[pos+1] & 0xff) << 16) +
+ ((buf[pos+2] & 0xff) << 8) +
+ (buf[pos+3] & 0xff);
+ return gTrue;
+}
+
+GBool MemReader::getU32LE(int pos, Guint *val) {
+ if (pos < 0 || pos > len - 4) {
+ return gFalse;
+ }
+ *val = (buf[pos] & 0xff) +
+ ((buf[pos+1] & 0xff) << 8) +
+ ((buf[pos+2] & 0xff) << 16) +
+ ((buf[pos+3] & 0xff) << 24);
+ return gTrue;
+}
+
+GBool MemReader::getUVarBE(int pos, int size, Guint *val) {
+ int i;
+
+ if (size < 1 || size > 4 || pos < 0 || pos > len - size) {
+ return gFalse;
+ }
+ *val = 0;
+ for (i = 0; i < size; ++i) {
+ *val = (*val << 8) + (buf[pos + i] & 0xff);
+ }
+ return gTrue;
+}
+
+GBool MemReader::cmp(int pos, const char *s) {
+ int n;
+
+ n = (int)strlen(s);
+ if (pos < 0 || len < n || pos > len - n) {
+ return gFalse;
+ }
+ return !memcmp(buf + pos, s, n);
+}
+
+//------------------------------------------------------------------------
+
+class FileReader: public Reader {
+public:
+
+ static FileReader *make(char *fileName);
+ virtual ~FileReader();
+ virtual int getByte(int pos);
+ virtual GBool getU16BE(int pos, int *val);
+ virtual GBool getU32BE(int pos, Guint *val);
+ virtual GBool getU32LE(int pos, Guint *val);
+ virtual GBool getUVarBE(int pos, int size, Guint *val);
+ virtual GBool cmp(int pos, const char *s);
+
+private:
+
+ FileReader(FILE *fA);
+ GBool fillBuf(int pos, int len);
+
+ FILE *f;
+ char buf[1024];
+ int bufPos, bufLen;
+};
+
+FileReader *FileReader::make(char *fileName) {
+ FILE *fA;
+
+ if (!(fA = fopen(fileName, "rb"))) {
+ return NULL;
+ }
+ return new FileReader(fA);
+}
+
+FileReader::FileReader(FILE *fA) {
+ f = fA;
+ bufPos = 0;
+ bufLen = 0;
+}
+
+FileReader::~FileReader() {
+ fclose(f);
+}
+
+int FileReader::getByte(int pos) {
+ if (!fillBuf(pos, 1)) {
+ return -1;
+ }
+ return buf[pos - bufPos] & 0xff;
+}
+
+GBool FileReader::getU16BE(int pos, int *val) {
+ if (!fillBuf(pos, 2)) {
+ return gFalse;
+ }
+ *val = ((buf[pos - bufPos] & 0xff) << 8) +
+ (buf[pos - bufPos + 1] & 0xff);
+ return gTrue;
+}
+
+GBool FileReader::getU32BE(int pos, Guint *val) {
+ if (!fillBuf(pos, 4)) {
+ return gFalse;
+ }
+ *val = ((buf[pos - bufPos] & 0xff) << 24) +
+ ((buf[pos - bufPos + 1] & 0xff) << 16) +
+ ((buf[pos - bufPos + 2] & 0xff) << 8) +
+ (buf[pos - bufPos + 3] & 0xff);
+ return gTrue;
+}
+
+GBool FileReader::getU32LE(int pos, Guint *val) {
+ if (!fillBuf(pos, 4)) {
+ return gFalse;
+ }
+ *val = (buf[pos - bufPos] & 0xff) +
+ ((buf[pos - bufPos + 1] & 0xff) << 8) +
+ ((buf[pos - bufPos + 2] & 0xff) << 16) +
+ ((buf[pos - bufPos + 3] & 0xff) << 24);
+ return gTrue;
+}
+
+GBool FileReader::getUVarBE(int pos, int size, Guint *val) {
+ int i;
+
+ if (size < 1 || size > 4 || !fillBuf(pos, size)) {
+ return gFalse;
+ }
+ *val = 0;
+ for (i = 0; i < size; ++i) {
+ *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff);
+ }
+ return gTrue;
+}
+
+GBool FileReader::cmp(int pos, const char *s) {
+ int n;
+
+ n = (int)strlen(s);
+ if (!fillBuf(pos, n)) {
+ return gFalse;
+ }
+ return !memcmp(buf - bufPos + pos, s, n);
+}
+
+GBool FileReader::fillBuf(int pos, int len) {
+ if (pos < 0 || len < 0 || len > (int)sizeof(buf) ||
+ pos > INT_MAX - (int)sizeof(buf)) {
+ return gFalse;
+ }
+ if (pos >= bufPos && pos + len <= bufPos + bufLen) {
+ return gTrue;
+ }
+ if (fseek(f, pos, SEEK_SET)) {
+ return gFalse;
+ }
+ bufPos = pos;
+ bufLen = (int)fread(buf, 1, sizeof(buf), f);
+ if (bufLen < len) {
+ return gFalse;
+ }
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+
+class StreamReader: public Reader {
+public:
+
+ static StreamReader *make(int (*getCharA)(void *data), void *dataA);
+ virtual ~StreamReader();
+ virtual int getByte(int pos);
+ virtual GBool getU16BE(int pos, int *val);
+ virtual GBool getU32BE(int pos, Guint *val);
+ virtual GBool getU32LE(int pos, Guint *val);
+ virtual GBool getUVarBE(int pos, int size, Guint *val);
+ virtual GBool cmp(int pos, const char *s);
+
+private:
+
+ StreamReader(int (*getCharA)(void *data), void *dataA);
+ GBool fillBuf(int pos, int len);
+
+ int (*getChar)(void *data);
+ void *data;
+ int streamPos;
+ char buf[1024];
+ int bufPos, bufLen;
+};
+
+StreamReader *StreamReader::make(int (*getCharA)(void *data), void *dataA) {
+ return new StreamReader(getCharA, dataA);
+}
+
+StreamReader::StreamReader(int (*getCharA)(void *data), void *dataA) {
+ getChar = getCharA;
+ data = dataA;
+ streamPos = 0;
+ bufPos = 0;
+ bufLen = 0;
+}
+
+StreamReader::~StreamReader() {
+}
+
+int StreamReader::getByte(int pos) {
+ if (!fillBuf(pos, 1)) {
+ return -1;
+ }
+ return buf[pos - bufPos] & 0xff;
+}
+
+GBool StreamReader::getU16BE(int pos, int *val) {
+ if (!fillBuf(pos, 2)) {
+ return gFalse;
+ }
+ *val = ((buf[pos - bufPos] & 0xff) << 8) +
+ (buf[pos - bufPos + 1] & 0xff);
+ return gTrue;
+}
+
+GBool StreamReader::getU32BE(int pos, Guint *val) {
+ if (!fillBuf(pos, 4)) {
+ return gFalse;
+ }
+ *val = ((buf[pos - bufPos] & 0xff) << 24) +
+ ((buf[pos - bufPos + 1] & 0xff) << 16) +
+ ((buf[pos - bufPos + 2] & 0xff) << 8) +
+ (buf[pos - bufPos + 3] & 0xff);
+ return gTrue;
+}
+
+GBool StreamReader::getU32LE(int pos, Guint *val) {
+ if (!fillBuf(pos, 4)) {
+ return gFalse;
+ }
+ *val = (buf[pos - bufPos] & 0xff) +
+ ((buf[pos - bufPos + 1] & 0xff) << 8) +
+ ((buf[pos - bufPos + 2] & 0xff) << 16) +
+ ((buf[pos - bufPos + 3] & 0xff) << 24);
+ return gTrue;
+}
+
+GBool StreamReader::getUVarBE(int pos, int size, Guint *val) {
+ int i;
+
+ if (size < 1 || size > 4 || !fillBuf(pos, size)) {
+ return gFalse;
+ }
+ *val = 0;
+ for (i = 0; i < size; ++i) {
+ *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff);
+ }
+ return gTrue;
+}
+
+GBool StreamReader::cmp(int pos, const char *s) {
+ int n;
+
+ n = (int)strlen(s);
+ if (!fillBuf(pos, n)) {
+ return gFalse;
+ }
+ return !memcmp(buf - bufPos + pos, s, n);
+}
+
+GBool StreamReader::fillBuf(int pos, int len) {
+ int c;
+
+ if (pos < 0 || len < 0 || len > (int)sizeof(buf) ||
+ pos > INT_MAX - (int)sizeof(buf)) {
+ return gFalse;
+ }
+ if (pos < bufPos) {
+ return gFalse;
+ }
+
+ // if requested region will not fit in the current buffer...
+ if (pos + len > bufPos + (int)sizeof(buf)) {
+
+ // if the start of the requested data is already in the buffer, move
+ // it to the start of the buffer
+ if (pos < bufPos + bufLen) {
+ bufLen -= pos - bufPos;
+ memmove(buf, buf + (pos - bufPos), bufLen);
+ bufPos = pos;
+
+ // otherwise discard data from the
+ // stream until we get to the requested position
+ } else {
+ bufPos += bufLen;
+ bufLen = 0;
+ while (bufPos < pos) {
+ if ((c = (*getChar)(data)) < 0) {
+ return gFalse;
+ }
+ ++bufPos;
+ }
+ }
+ }
+
+ // read the rest of the requested data
+ while (bufPos + bufLen < pos + len) {
+ if ((c = (*getChar)(data)) < 0) {
+ return gFalse;
+ }
+ buf[bufLen++] = (char)c;
+ }
+
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+
+static FoFiIdentifierType identify(Reader *reader);
+static FoFiIdentifierType identifyOpenType(Reader *reader);
+static FoFiIdentifierType identifyCFF(Reader *reader, int start);
+
+FoFiIdentifierType FoFiIdentifier::identifyMem(char *file, int len) {
+ MemReader *reader;
+ FoFiIdentifierType type;
+
+ if (!(reader = MemReader::make(file, len))) {
+ return fofiIdError;
+ }
+ type = identify(reader);
+ delete reader;
+ return type;
+}
+
+FoFiIdentifierType FoFiIdentifier::identifyFile(char *fileName) {
+ FileReader *reader;
+ FoFiIdentifierType type;
+
+ if (!(reader = FileReader::make(fileName))) {
+ return fofiIdError;
+ }
+ type = identify(reader);
+ delete reader;
+ return type;
+}
+
+FoFiIdentifierType FoFiIdentifier::identifyStream(int (*getChar)(void *data),
+ void *data) {
+ StreamReader *reader;
+ FoFiIdentifierType type;
+
+ if (!(reader = StreamReader::make(getChar, data))) {
+ return fofiIdError;
+ }
+ type = identify(reader);
+ delete reader;
+ return type;
+}
+
+static FoFiIdentifierType identify(Reader *reader) {
+ Guint n;
+
+ //----- PFA
+ if (reader->cmp(0, "%!PS-AdobeFont-1") ||
+ reader->cmp(0, "%!FontType1")) {
+ return fofiIdType1PFA;
+ }
+
+ //----- PFB
+ if (reader->getByte(0) == 0x80 &&
+ reader->getByte(1) == 0x01 &&
+ reader->getU32LE(2, &n)) {
+ if ((n >= 16 && reader->cmp(6, "%!PS-AdobeFont-1")) ||
+ (n >= 11 && reader->cmp(6, "%!FontType1"))) {
+ return fofiIdType1PFB;
+ }
+ }
+
+ //----- TrueType
+ if ((reader->getByte(0) == 0x00 &&
+ reader->getByte(1) == 0x01 &&
+ reader->getByte(2) == 0x00 &&
+ reader->getByte(3) == 0x00) ||
+ (reader->getByte(0) == 0x74 && // 'true'
+ reader->getByte(1) == 0x72 &&
+ reader->getByte(2) == 0x75 &&
+ reader->getByte(3) == 0x65)) {
+ return fofiIdTrueType;
+ }
+ if (reader->getByte(0) == 0x74 && // 'ttcf'
+ reader->getByte(1) == 0x74 &&
+ reader->getByte(2) == 0x63 &&
+ reader->getByte(3) == 0x66) {
+ return fofiIdTrueTypeCollection;
+ }
+
+ //----- OpenType
+ if (reader->getByte(0) == 0x4f && // 'OTTO
+ reader->getByte(1) == 0x54 &&
+ reader->getByte(2) == 0x54 &&
+ reader->getByte(3) == 0x4f) {
+ return identifyOpenType(reader);
+ }
+
+ //----- CFF
+ if (reader->getByte(0) == 0x01 &&
+ reader->getByte(1) == 0x00) {
+ return identifyCFF(reader, 0);
+ }
+ // some tools embed CFF fonts with an extra whitespace char at the
+ // beginning
+ if (reader->getByte(1) == 0x01 &&
+ reader->getByte(2) == 0x00) {
+ return identifyCFF(reader, 1);
+ }
+
+ return fofiIdUnknown;
+}
+
+static FoFiIdentifierType identifyOpenType(Reader *reader) {
+ FoFiIdentifierType type;
+ Guint offset;
+ int nTables, i;
+
+ if (!reader->getU16BE(4, &nTables)) {
+ return fofiIdUnknown;
+ }
+ for (i = 0; i < nTables; ++i) {
+ if (reader->cmp(12 + i*16, "CFF ")) {
+ if (reader->getU32BE(12 + i*16 + 8, &offset) &&
+ offset < (Guint)INT_MAX) {
+ type = identifyCFF(reader, (int)offset);
+ if (type == fofiIdCFF8Bit) {
+ type = fofiIdOpenTypeCFF8Bit;
+ } else if (type == fofiIdCFFCID) {
+ type = fofiIdOpenTypeCFFCID;
+ }
+ return type;
+ }
+ return fofiIdUnknown;
+ }
+ }
+ return fofiIdUnknown;
+}
+
+static FoFiIdentifierType identifyCFF(Reader *reader, int start) {
+ Guint offset0, offset1;
+ int hdrSize, offSize0, offSize1, pos, endPos, b0, n, i;
+
+ //----- read the header
+ if (reader->getByte(start) != 0x01 ||
+ reader->getByte(start + 1) != 0x00) {
+ return fofiIdUnknown;
+ }
+ if ((hdrSize = reader->getByte(start + 2)) < 0) {
+ return fofiIdUnknown;
+ }
+ if ((offSize0 = reader->getByte(start + 3)) < 1 || offSize0 > 4) {
+ return fofiIdUnknown;
+ }
+ pos = start + hdrSize;
+ if (pos < 0) {
+ return fofiIdUnknown;
+ }
+
+ //----- skip the name index
+ if (!reader->getU16BE(pos, &n)) {
+ return fofiIdUnknown;
+ }
+ if (n == 0) {
+ pos += 2;
+ } else {
+ if ((offSize1 = reader->getByte(pos + 2)) < 1 || offSize1 > 4) {
+ return fofiIdUnknown;
+ }
+ if (!reader->getUVarBE(pos + 3 + n * offSize1, offSize1, &offset1) ||
+ offset1 > (Guint)INT_MAX) {
+ return fofiIdUnknown;
+ }
+ pos += 3 + (n + 1) * offSize1 + (int)offset1 - 1;
+ }
+ if (pos < 0) {
+ return fofiIdUnknown;
+ }
+
+ //----- parse the top dict index
+ if (!reader->getU16BE(pos, &n) || n < 1) {
+ return fofiIdUnknown;
+ }
+ if ((offSize1 = reader->getByte(pos + 2)) < 1 || offSize1 > 4) {
+ return fofiIdUnknown;
+ }
+ if (!reader->getUVarBE(pos + 3, offSize1, &offset0) ||
+ offset0 > (Guint)INT_MAX ||
+ !reader->getUVarBE(pos + 3 + offSize1, offSize1, &offset1) ||
+ offset1 > (Guint)INT_MAX ||
+ offset0 > offset1) {
+ return fofiIdUnknown;
+ }
+ pos = pos + 3 + (n + 1) * offSize1 + (int)offset0 - 1;
+ endPos = pos + 3 + (n + 1) * offSize1 + (int)offset1 - 1;
+ if (pos < 0 || endPos < 0 || pos > endPos) {
+ return fofiIdUnknown;
+ }
+
+ //----- parse the top dict, look for ROS as first entry
+ // for a CID font, the top dict starts with:
+ // <int> <int> <int> ROS
+ for (i = 0; i < 3; ++i) {
+ b0 = reader->getByte(pos++);
+ if (b0 == 0x1c) {
+ pos += 2;
+ } else if (b0 == 0x1d) {
+ pos += 4;
+ } else if (b0 >= 0xf7 && b0 <= 0xfe) {
+ pos += 1;
+ } else if (b0 < 0x20 || b0 > 0xf6) {
+ return fofiIdCFF8Bit;
+ }
+ if (pos >= endPos || pos < 0) {
+ return fofiIdCFF8Bit;
+ }
+ }
+ if (pos + 1 < endPos &&
+ reader->getByte(pos) == 12 &&
+ reader->getByte(pos + 1) == 30) {
+ return fofiIdCFFCID;
+ } else {
+ return fofiIdCFF8Bit;
+ }
+}
diff --git a/fofi/FoFiIdentifier.h b/fofi/FoFiIdentifier.h
new file mode 100644
index 0000000..af1323b
--- /dev/null
+++ b/fofi/FoFiIdentifier.h
@@ -0,0 +1,42 @@
+//========================================================================
+//
+// FoFiIdentifier.h
+//
+// Copyright 2009 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef FOFIIDENTIFIER_H
+#define FOFIIDENTIFIER_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+//------------------------------------------------------------------------
+// FoFiIdentifier
+//------------------------------------------------------------------------
+
+enum FoFiIdentifierType {
+ fofiIdType1PFA, // Type 1 font in PFA format
+ fofiIdType1PFB, // Type 1 font in PFB format
+ fofiIdCFF8Bit, // 8-bit CFF font
+ fofiIdCFFCID, // CID CFF font
+ fofiIdTrueType, // TrueType font
+ fofiIdTrueTypeCollection, // TrueType collection
+ fofiIdOpenTypeCFF8Bit, // OpenType wrapper with 8-bit CFF font
+ fofiIdOpenTypeCFFCID, // OpenType wrapper with CID CFF font
+ fofiIdUnknown, // unknown type
+ fofiIdError // error in reading the file
+};
+
+class FoFiIdentifier {
+public:
+
+ static FoFiIdentifierType identifyMem(char *file, int len);
+ static FoFiIdentifierType identifyFile(char *fileName);
+ static FoFiIdentifierType identifyStream(int (*getChar)(void *data),
+ void *data);
+};
+
+#endif
diff --git a/fofi/Makefile.am b/fofi/Makefile.am
index 7a30248..c4654dd 100644
--- a/fofi/Makefile.am
+++ b/fofi/Makefile.am
@@ -10,6 +10,7 @@ poppler_fofi_include_HEADERS = \
FoFiEncodings.h \
FoFiTrueType.h \
FoFiType1.h \
+ FoFiIdentifier.h \
FoFiType1C.h
endif
@@ -23,4 +24,5 @@ libfofi_la_SOURCES = \
FoFiType1.cc \
FoFiType1.h \
FoFiType1C.cc \
+ FoFiIdentifier.cc \
FoFiType1C.h
More information about the poppler
mailing list