[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