From a5e5649ecf16fa05770620dbbd4985935dc2bbff Mon Sep 17 00:00:00 2001
From: Albert Astals Cid <aacid@kde.org>
Date: Mon, 11 Sep 2017 12:35:16 +0200
Subject: Fix crash in FoFiType1C::convertToType0 in broken files

Bug #102653
---
 fofi/FoFiType1C.cc | 435 +++++++++++++++++++++++++++--------------------------
 1 file changed, 220 insertions(+), 215 deletions(-)

diff --git a/fofi/FoFiType1C.cc b/fofi/FoFiType1C.cc
index c4595a3..7a82785 100644
--- a/fofi/FoFiType1C.cc
+++ b/fofi/FoFiType1C.cc
@@ -13,7 +13,7 @@
 // All changes made under the Poppler project to this file are licensed
 // under GPL version 2 or later
 //
-// Copyright (C) 2009, 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009, 2010, 2017 Albert Astals Cid <aacid@kde.org>
 // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
 //
 // To see a description of the changes please see the Changelog file that
@@ -33,6 +33,7 @@
 #include "goo/gmem.h"
 #include "goo/gstrtod.h"
 #include "goo/GooString.h"
+#include "poppler/Error.h"
 #include "FoFiEncodings.h"
 #include "FoFiType1C.h"
 
@@ -879,253 +880,257 @@ void FoFiType1C::convertToType0(char *psName, int *codeMap, int nCodes,
     }
   }
 
+  if (privateDicts) {
   // write the descendant Type 1 fonts
-  for (i = 0; i < nCIDs; i += 256) {
-
-    //~ this assumes that all CIDs in this block have the same FD --
-    //~ to handle multiple FDs correctly, need to somehow divide the
-    //~ font up by FD; as a kludge we ignore CID 0, which is .notdef
-    fd = 0;
-    // if fdSelect is NULL, we have an 8-bit font, so just leave fd=0
-    if (fdSelect) {
-      for (j = i==0 ? 1 : 0; j < 256 && i+j < nCIDs; ++j) {
-        if (cidMap[i+j] >= 0) {
-          fd = fdSelect[cidMap[i+j]];
-          break;
-        }
+    for (i = 0; i < nCIDs; i += 256) {
+
+      //~ this assumes that all CIDs in this block have the same FD --
+      //~ to handle multiple FDs correctly, need to somehow divide the
+      //~ font up by FD; as a kludge we ignore CID 0, which is .notdef
+      fd = 0;
+      // if fdSelect is NULL, we have an 8-bit font, so just leave fd=0
+      if (fdSelect) {
+	for (j = i==0 ? 1 : 0; j < 256 && i+j < nCIDs; ++j) {
+	  if (cidMap[i+j] >= 0) {
+	    fd = fdSelect[cidMap[i+j]];
+	    break;
+	  }
+	}
       }
-    }
 
-    // font dictionary (unencrypted section)
-    (*outputFunc)(outputStream, "16 dict begin\n", 14);
-    (*outputFunc)(outputStream, "/FontName /", 11);
-    (*outputFunc)(outputStream, psName, strlen(psName));
-    buf = GooString::format("_{0:02x} def\n", i >> 8);
-    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
-    delete buf;
-    (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
-    if (privateDicts[fd].hasFontMatrix) {
-      buf = GooString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n",
-			    privateDicts[fd].fontMatrix[0],
-			    privateDicts[fd].fontMatrix[1],
-			    privateDicts[fd].fontMatrix[2],
-			    privateDicts[fd].fontMatrix[3],
-			    privateDicts[fd].fontMatrix[4],
-			    privateDicts[fd].fontMatrix[5]);
+      // font dictionary (unencrypted section)
+      (*outputFunc)(outputStream, "16 dict begin\n", 14);
+      (*outputFunc)(outputStream, "/FontName /", 11);
+      (*outputFunc)(outputStream, psName, strlen(psName));
+      buf = GooString::format("_{0:02x} def\n", i >> 8);
       (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
       delete buf;
-    } else if (topDict.hasFontMatrix) {
-      (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
-    } else {
-      (*outputFunc)(outputStream,
-		    "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38);
-    }
-    buf = GooString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n",
-			  topDict.fontBBox[0], topDict.fontBBox[1],
-			  topDict.fontBBox[2], topDict.fontBBox[3]);
-    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
-    delete buf;
-    buf = GooString::format("/PaintType {0:d} def\n", topDict.paintType);
-    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
-    delete buf;
-    if (topDict.paintType != 0) {
-      buf = GooString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth);
-      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
-      delete buf;
-    }
-    (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
-    for (j = 0; j < 256 && i+j < nCIDs; ++j) {
-      buf = GooString::format("dup {0:d} /c{1:02x} put\n", j, j);
+      (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
+      if (privateDicts[fd].hasFontMatrix) {
+	buf = GooString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n",
+			      privateDicts[fd].fontMatrix[0],
+			      privateDicts[fd].fontMatrix[1],
+			      privateDicts[fd].fontMatrix[2],
+			      privateDicts[fd].fontMatrix[3],
+			      privateDicts[fd].fontMatrix[4],
+			      privateDicts[fd].fontMatrix[5]);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
+      } else if (topDict.hasFontMatrix) {
+	(*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+      } else {
+	(*outputFunc)(outputStream,
+		      "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38);
+      }
+      buf = GooString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n",
+			    topDict.fontBBox[0], topDict.fontBBox[1],
+			    topDict.fontBBox[2], topDict.fontBBox[3]);
       (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
       delete buf;
-    }
-    if (j < 256) {
-      buf = GooString::format("{0:d} 1 255 {{ 1 index exch /.notdef put }} for\n",
-			    j);
+      buf = GooString::format("/PaintType {0:d} def\n", topDict.paintType);
       (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
       delete buf;
-    }
-    (*outputFunc)(outputStream, "readonly def\n", 13);
-    (*outputFunc)(outputStream, "currentdict end\n", 16);
-
-    // start the binary section
-    (*outputFunc)(outputStream, "currentfile eexec\n", 18);
-    eb.outputFunc = outputFunc;
-    eb.outputStream = outputStream;
-    eb.ascii = gTrue;
-    eb.r1 = 55665;
-    eb.line = 0;
-
-    // start the private dictionary
-    eexecWrite(&eb, "\x83\xca\x73\xd5");
-    eexecWrite(&eb, "dup /Private 32 dict dup begin\n");
-    eexecWrite(&eb, "/RD {string currentfile exch readstring pop}"
-	       " executeonly def\n");
-    eexecWrite(&eb, "/ND {noaccess def} executeonly def\n");
-    eexecWrite(&eb, "/NP {noaccess put} executeonly def\n");
-    eexecWrite(&eb, "/MinFeature {16 16} def\n");
-    eexecWrite(&eb, "/password 5839 def\n");
-    if (privateDicts[fd].nBlueValues) {
-      eexecWrite(&eb, "/BlueValues [");
-      for (k = 0; k < privateDicts[fd].nBlueValues; ++k) {
-	buf = GooString::format("{0:s}{1:d}",
-			      k > 0 ? " " : "",
-			      privateDicts[fd].blueValues[k]);
+      if (topDict.paintType != 0) {
+	buf = GooString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
+      }
+      (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
+      for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+	buf = GooString::format("dup {0:d} /c{1:02x} put\n", j, j);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
+      }
+      if (j < 256) {
+	buf = GooString::format("{0:d} 1 255 {{ 1 index exch /.notdef put }} for\n",
+			      j);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
+      }
+      (*outputFunc)(outputStream, "readonly def\n", 13);
+      (*outputFunc)(outputStream, "currentdict end\n", 16);
+
+      // start the binary section
+      (*outputFunc)(outputStream, "currentfile eexec\n", 18);
+      eb.outputFunc = outputFunc;
+      eb.outputStream = outputStream;
+      eb.ascii = gTrue;
+      eb.r1 = 55665;
+      eb.line = 0;
+
+      // start the private dictionary
+      eexecWrite(&eb, "\x83\xca\x73\xd5");
+      eexecWrite(&eb, "dup /Private 32 dict dup begin\n");
+      eexecWrite(&eb, "/RD {string currentfile exch readstring pop}"
+		" executeonly def\n");
+      eexecWrite(&eb, "/ND {noaccess def} executeonly def\n");
+      eexecWrite(&eb, "/NP {noaccess put} executeonly def\n");
+      eexecWrite(&eb, "/MinFeature {16 16} def\n");
+      eexecWrite(&eb, "/password 5839 def\n");
+      if (privateDicts[fd].nBlueValues) {
+	eexecWrite(&eb, "/BlueValues [");
+	for (k = 0; k < privateDicts[fd].nBlueValues; ++k) {
+	  buf = GooString::format("{0:s}{1:d}",
+				k > 0 ? " " : "",
+				privateDicts[fd].blueValues[k]);
+	  eexecWrite(&eb, buf->getCString());
+	  delete buf;
+	}
+	eexecWrite(&eb, "] def\n");
+      }
+      if (privateDicts[fd].nOtherBlues) {
+	eexecWrite(&eb, "/OtherBlues [");
+	for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) {
+	  buf = GooString::format("{0:s}{1:d}",
+				k > 0 ? " " : "",
+				privateDicts[fd].otherBlues[k]);
+	  eexecWrite(&eb, buf->getCString());
+	  delete buf;
+	}
+	eexecWrite(&eb, "] def\n");
+      }
+      if (privateDicts[fd].nFamilyBlues) {
+	eexecWrite(&eb, "/FamilyBlues [");
+	for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) {
+	  buf = GooString::format("{0:s}{1:d}", k > 0 ? " " : "",
+				privateDicts[fd].familyBlues[k]);
+	  eexecWrite(&eb, buf->getCString());
+	  delete buf;
+	}
+	eexecWrite(&eb, "] def\n");
+      }
+      if (privateDicts[fd].nFamilyOtherBlues) {
+	eexecWrite(&eb, "/FamilyOtherBlues [");
+	for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) {
+	  buf = GooString::format("{0:s}{1:d}", k > 0 ? " " : "",
+				privateDicts[fd].familyOtherBlues[k]);
+	  eexecWrite(&eb, buf->getCString());
+	  delete buf;
+	}
+	eexecWrite(&eb, "] def\n");
+      }
+      if (privateDicts[fd].blueScale != 0.039625) {
+	buf = GooString::format("/BlueScale {0:.4g} def\n",
+			      privateDicts[fd].blueScale);
 	eexecWrite(&eb, buf->getCString());
 	delete buf;
       }
-      eexecWrite(&eb, "] def\n");
-    }
-    if (privateDicts[fd].nOtherBlues) {
-      eexecWrite(&eb, "/OtherBlues [");
-      for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) {
-	buf = GooString::format("{0:s}{1:d}",
-			      k > 0 ? " " : "",
-			      privateDicts[fd].otherBlues[k]);
+      if (privateDicts[fd].blueShift != 7) {
+	buf = GooString::format("/BlueShift {0:d} def\n",
+			      privateDicts[fd].blueShift);
 	eexecWrite(&eb, buf->getCString());
 	delete buf;
       }
-      eexecWrite(&eb, "] def\n");
-    }
-    if (privateDicts[fd].nFamilyBlues) {
-      eexecWrite(&eb, "/FamilyBlues [");
-      for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) {
-	buf = GooString::format("{0:s}{1:d}", k > 0 ? " " : "",
-			      privateDicts[fd].familyBlues[k]);
+      if (privateDicts[fd].blueFuzz != 1) {
+	buf = GooString::format("/BlueFuzz {0:d} def\n",
+			      privateDicts[fd].blueFuzz);
 	eexecWrite(&eb, buf->getCString());
 	delete buf;
       }
-      eexecWrite(&eb, "] def\n");
-    }
-    if (privateDicts[fd].nFamilyOtherBlues) {
-      eexecWrite(&eb, "/FamilyOtherBlues [");
-      for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) {
-	buf = GooString::format("{0:s}{1:d}", k > 0 ? " " : "",
-			      privateDicts[fd].familyOtherBlues[k]);
+      if (privateDicts[fd].hasStdHW) {
+	buf = GooString::format("/StdHW [{0:.4g}] def\n", privateDicts[fd].stdHW);
 	eexecWrite(&eb, buf->getCString());
 	delete buf;
       }
-      eexecWrite(&eb, "] def\n");
-    }
-    if (privateDicts[fd].blueScale != 0.039625) {
-      buf = GooString::format("/BlueScale {0:.4g} def\n",
-			    privateDicts[fd].blueScale);
-      eexecWrite(&eb, buf->getCString());
-      delete buf;
-    }
-    if (privateDicts[fd].blueShift != 7) {
-      buf = GooString::format("/BlueShift {0:d} def\n",
-			    privateDicts[fd].blueShift);
-      eexecWrite(&eb, buf->getCString());
-      delete buf;
-    }
-    if (privateDicts[fd].blueFuzz != 1) {
-      buf = GooString::format("/BlueFuzz {0:d} def\n",
-			    privateDicts[fd].blueFuzz);
-      eexecWrite(&eb, buf->getCString());
-      delete buf;
-    }
-    if (privateDicts[fd].hasStdHW) {
-      buf = GooString::format("/StdHW [{0:.4g}] def\n", privateDicts[fd].stdHW);
-      eexecWrite(&eb, buf->getCString());
-      delete buf;
-    }
-    if (privateDicts[fd].hasStdVW) {
-      buf = GooString::format("/StdVW [{0:.4g}] def\n", privateDicts[fd].stdVW);
-      eexecWrite(&eb, buf->getCString());
-      delete buf;
-    }
-    if (privateDicts[fd].nStemSnapH) {
-      eexecWrite(&eb, "/StemSnapH [");
-      for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) {
-	buf = GooString::format("{0:s}{1:.4g}",
-			      k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]);
+      if (privateDicts[fd].hasStdVW) {
+	buf = GooString::format("/StdVW [{0:.4g}] def\n", privateDicts[fd].stdVW);
 	eexecWrite(&eb, buf->getCString());
 	delete buf;
       }
-      eexecWrite(&eb, "] def\n");
-    }
-    if (privateDicts[fd].nStemSnapV) {
-      eexecWrite(&eb, "/StemSnapV [");
-      for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) {
-	buf = GooString::format("{0:s}{1:.4g}",
-			      k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]);
+      if (privateDicts[fd].nStemSnapH) {
+	eexecWrite(&eb, "/StemSnapH [");
+	for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) {
+	  buf = GooString::format("{0:s}{1:.4g}",
+				k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]);
+	  eexecWrite(&eb, buf->getCString());
+	  delete buf;
+	}
+	eexecWrite(&eb, "] def\n");
+      }
+      if (privateDicts[fd].nStemSnapV) {
+	eexecWrite(&eb, "/StemSnapV [");
+	for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) {
+	  buf = GooString::format("{0:s}{1:.4g}",
+				k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]);
+	  eexecWrite(&eb, buf->getCString());
+	  delete buf;
+	}
+	eexecWrite(&eb, "] def\n");
+      }
+      if (privateDicts[fd].hasForceBold) {
+	buf = GooString::format("/ForceBold {0:s} def\n",
+			      privateDicts[fd].forceBold ? "true" : "false");
+	eexecWrite(&eb, buf->getCString());
+	delete buf;
+      }
+      if (privateDicts[fd].forceBoldThreshold != 0) {
+	buf = GooString::format("/ForceBoldThreshold {0:.4g} def\n",
+			      privateDicts[fd].forceBoldThreshold);
+	eexecWrite(&eb, buf->getCString());
+	delete buf;
+      }
+      if (privateDicts[fd].languageGroup != 0) {
+	buf = GooString::format("/LanguageGroup {0:d} def\n",
+			      privateDicts[fd].languageGroup);
+	eexecWrite(&eb, buf->getCString());
+	delete buf;
+      }
+      if (privateDicts[fd].expansionFactor != 0.06) {
+	buf = GooString::format("/ExpansionFactor {0:.4g} def\n",
+			      privateDicts[fd].expansionFactor);
 	eexecWrite(&eb, buf->getCString());
 	delete buf;
       }
-      eexecWrite(&eb, "] def\n");
-    }
-    if (privateDicts[fd].hasForceBold) {
-      buf = GooString::format("/ForceBold {0:s} def\n",
-			    privateDicts[fd].forceBold ? "true" : "false");
-      eexecWrite(&eb, buf->getCString());
-      delete buf;
-    }
-    if (privateDicts[fd].forceBoldThreshold != 0) {
-      buf = GooString::format("/ForceBoldThreshold {0:.4g} def\n",
-			    privateDicts[fd].forceBoldThreshold);
-      eexecWrite(&eb, buf->getCString());
-      delete buf;
-    }
-    if (privateDicts[fd].languageGroup != 0) {
-      buf = GooString::format("/LanguageGroup {0:d} def\n",
-			    privateDicts[fd].languageGroup);
-      eexecWrite(&eb, buf->getCString());
-      delete buf;
-    }
-    if (privateDicts[fd].expansionFactor != 0.06) {
-      buf = GooString::format("/ExpansionFactor {0:.4g} def\n",
-			    privateDicts[fd].expansionFactor);
-      eexecWrite(&eb, buf->getCString());
-      delete buf;
-    }
 
-    // set up the subroutines
-    ok = gTrue;
-    getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok);
-    if (!ok) {
-      subrIdx.pos = -1;
-    }
+      // set up the subroutines
+      ok = gTrue;
+      getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok);
+      if (!ok) {
+	subrIdx.pos = -1;
+      }
 
-    // start the CharStrings
-    eexecWrite(&eb, "2 index /CharStrings 256 dict dup begin\n");
+      // start the CharStrings
+      eexecWrite(&eb, "2 index /CharStrings 256 dict dup begin\n");
 
-    // write the .notdef CharString
-    ok = gTrue;
-    getIndexVal(&charStringsIdx, 0, &val, &ok);
-    if (ok) {
-      eexecCvtGlyph(&eb, ".notdef", val.pos, val.len,
-		    &subrIdx, &privateDicts[fd]);
-    }
-
-    // write the CharStrings
-    for (j = 0; j < 256 && i+j < nCIDs; ++j) {
-      if (cidMap[i+j] >= 0) {
-	ok = gTrue;
-	getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok);
-	if (ok) {
-	  buf = GooString::format("c{0:02x}", j);
-	  eexecCvtGlyph(&eb, buf->getCString(), val.pos, val.len,
-			&subrIdx, &privateDicts[fd]);
-	  delete buf;
-	}
+      // write the .notdef CharString
+      ok = gTrue;
+      getIndexVal(&charStringsIdx, 0, &val, &ok);
+      if (ok) {
+	eexecCvtGlyph(&eb, ".notdef", val.pos, val.len,
+		      &subrIdx, &privateDicts[fd]);
       }
-    }
-    eexecWrite(&eb, "end\n");
-    eexecWrite(&eb, "end\n");
-    eexecWrite(&eb, "readonly put\n");
-    eexecWrite(&eb, "noaccess put\n");
-    eexecWrite(&eb, "dup /FontName get exch definefont pop\n");
-    eexecWrite(&eb, "mark currentfile closefile\n");
 
-    // trailer
-    if (eb.line > 0) {
-      (*outputFunc)(outputStream, "\n", 1);
-    }
-    for (j = 0; j < 8; ++j) {
-      (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65);
+      // write the CharStrings
+      for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+	if (cidMap[i+j] >= 0) {
+	  ok = gTrue;
+	  getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok);
+	  if (ok) {
+	    buf = GooString::format("c{0:02x}", j);
+	    eexecCvtGlyph(&eb, buf->getCString(), val.pos, val.len,
+			  &subrIdx, &privateDicts[fd]);
+	    delete buf;
+	  }
+	}
+      }
+      eexecWrite(&eb, "end\n");
+      eexecWrite(&eb, "end\n");
+      eexecWrite(&eb, "readonly put\n");
+      eexecWrite(&eb, "noaccess put\n");
+      eexecWrite(&eb, "dup /FontName get exch definefont pop\n");
+      eexecWrite(&eb, "mark currentfile closefile\n");
+
+      // trailer
+      if (eb.line > 0) {
+	(*outputFunc)(outputStream, "\n", 1);
+      }
+      for (j = 0; j < 8; ++j) {
+	(*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65);
+      }
+      (*outputFunc)(outputStream, "cleartomark\n", 12);
     }
-    (*outputFunc)(outputStream, "cleartomark\n", 12);
+  } else {
+    error(errSyntaxError, -1, "FoFiType1C::convertToType0 without privateDicts");
   }
 
   // write the Type 0 parent font
-- 
cgit v1.1

