Author: ssteiner Date: Wed Dec 2 14:16:54 2015 New Revision: 1717631 URL: http://svn.apache.org/viewvc?rev=1717631&view=rev Log: FOP-2546: ArrayIndexOutOfBoundsException merging fonts
Modified: xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleByteFont.java xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/MergeCFFFonts.java xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/MergeTTFonts.java xmlgraphics/fop-pdf-images/trunk/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java Modified: xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleByteFont.java URL: http://svn.apache.org/viewvc/xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleByteFont.java?rev=1717631&r1=1717630&r2=1717631&view=diff ============================================================================== --- xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleByteFont.java (original) +++ xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleByteFont.java Wed Dec 2 14:16:54 2015 @@ -37,7 +37,6 @@ import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; -import org.apache.pdfbox.encoding.DictionaryEncoding; import org.apache.pdfbox.encoding.Encoding; import org.apache.pdfbox.encoding.EncodingManager; import org.apache.pdfbox.pdmodel.common.PDStream; @@ -61,7 +60,7 @@ public class FOPPDFSingleByteFont extend protected Map<String, Integer> charMapGlobal = new LinkedHashMap<String, Integer>(); private Map<Integer, Integer> newWidth = new HashMap<Integer, Integer>(); private Map<String, byte[]> charStringsDict; - private MergeTTFonts.Cmap newCmap = new MergeTTFonts.Cmap(); + private List<MergeTTFonts.Cmap> newCmap = new ArrayList<MergeTTFonts.Cmap>(); private Map<Integer, String> encodingMap = new TreeMap<Integer, String>(); private int encodingSkip; private MergeTTFonts mergeTTFonts = new MergeTTFonts(); @@ -183,18 +182,27 @@ public class FOPPDFSingleByteFont extend TrueTypeFont ttfont = ((PDTrueTypeFont) font).getTTFFont(); CMAPEncodingEntry[] cmapList = ttfont.getCMAP().getCmaps(); for (CMAPEncodingEntry c : cmapList) { - newCmap.platformId = c.getPlatformId(); - newCmap.platformEncodingId = c.getPlatformEncodingId(); + MergeTTFonts.Cmap tempCmap = getNewCmap(c.getPlatformId(), c.getPlatformEncodingId()); for (int i = 0; i < 256 * 256; i++) { if (c.getGlyphId(i) != 0) { - newCmap.glyphIdToCharacterCode.put(i, c.getGlyphId(i)); + tempCmap.glyphIdToCharacterCode.put(i, c.getGlyphId(i)); } } + newCmap.add(tempCmap); } FOPPDFMultiByteFont.mergeMaxp(ttfont, mergeTTFonts.maxp); } } + private MergeTTFonts.Cmap getNewCmap(int platformID, int platformEncodingID) { + for (MergeTTFonts.Cmap cmap : newCmap) { + if (cmap.platformId == platformID && cmap.platformEncodingId == platformEncodingID) { + return cmap; + } + } + return new MergeTTFonts.Cmap(platformID, platformEncodingID); + } + @Override public boolean hasChar(char c) { return charMapGlobal.containsKey(String.valueOf(c)); @@ -329,10 +337,7 @@ public class FOPPDFSingleByteFont extend return c.lookup(i, size); } Encoding enc = (Encoding)cmap; - if (enc instanceof DictionaryEncoding) { - return enc.getName(i); - } - return enc.getCharacter(i); + return enc.getName(i); } public String getEncodingName() { @@ -360,7 +365,7 @@ public class FOPPDFSingleByteFont extend for (int i = fontForEnc.getFirstChar(); i <= fontForEnc.getLastChar(); i++) { if (codeToName.keySet().contains(i)) { String s = codeToName.get(i); - if (!added.contains(s)) { + if (!added.contains(s) || (added.contains(s) && !encodingMap.containsKey(i))) { if (!encodingMap.containsKey(i)) { encodingMap.put(i, s); } else { Modified: xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/MergeCFFFonts.java URL: http://svn.apache.org/viewvc/xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/MergeCFFFonts.java?rev=1717631&r1=1717630&r2=1717631&view=diff ============================================================================== --- xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/MergeCFFFonts.java (original) +++ xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/MergeCFFFonts.java Wed Dec 2 14:16:54 2015 @@ -49,9 +49,7 @@ public class MergeCFFFonts extends OTFSu private List<Integer> chars = new ArrayList<Integer>(); private List<String> added = new ArrayList<String>(); private Map<Integer, Integer> range = new LinkedHashMap<Integer, Integer>(); - private Set<String> stringsForRange = new HashSet<String>(); private int noOfFonts; - private CFFEncoding encoding = null; public MergeCFFFonts() throws IOException { gidToSID = new LinkedHashMap<Integer, Integer>(); @@ -63,23 +61,24 @@ public class MergeCFFFonts extends OTFSu FontFileReader fontFile = new FontFileReader(stream); CFFParser p = new CFFParser(); CFFFont ff = p.parse(fontFile.getAllBytes()).get(0); - if (used.containsAll(ff.getCharStringsDict().keySet())) { + + if (used.containsAll(getStrings(ff).keySet())) { return; } fontFileSize += fontFile.getFileSize(); this.fontFile = fontFile; - used.addAll(ff.getCharStringsDict().keySet()); + used.addAll(getStrings(ff).keySet()); if (fileFont == null) { fileFont = ff; } LinkedHashMap<Integer, Integer> sg = new LinkedHashMap<Integer, Integer>(); - for (int i = 0; i < ff.getCharset().getEntries().size() + 1; i++) { + for (int i = 0; i < ff.getCharStringsDict().size() + 1; i++) { sg.put(i, i); } subsetGlyphsList.add(sg); cffReader = new CFFDataReader(fontFile); - for (CFFCharset.Entry e : ff.getCharset().getEntries()) { - int sid = e.getSID(); + + for (int sid : getSids(ff.getCharset())) { if (sid >= NUM_STANDARD_STRINGS) { int index = sid - NUM_STANDARD_STRINGS; if (index <= cffReader.getStringIndex().getNumObjects()) { @@ -91,36 +90,18 @@ public class MergeCFFFonts extends OTFSu } } - encoding = ff.getEncoding(); + CFFEncoding encoding = ff.getEncoding(); if (!(encoding instanceof CFFStandardEncoding)) { for (CFFEncoding.Entry e : encoding.getEntries()) { int c = e.getCode(); - if (!chars.contains(c)) { + if (!chars.contains(c) && c != 0) { chars.add(c); } } } + setupMapping(ff.getCharset(), sg); - int subsetGlyphIndex = 0; - for (CFFCharset.Entry e : ff.getCharset().getEntries()) { - int sid = e.getSID(); - int gid = sg.get(subsetGlyphIndex); - - //Check whether the SID falls into the standard string set - if (sid < NUM_STANDARD_STRINGS) { - gidToSID.put(sg.get(gid), sid); - } else { - int index = sid - NUM_STANDARD_STRINGS; - if (index <= cffReader.getStringIndex().getNumObjects()) { - gidToSID.put(sg.get(gid), stringIndexData.size() + NUM_STANDARD_STRINGS - 1); - } else { - gidToSID.put(sg.get(gid), index); - } - } - subsetGlyphIndex++; - } - - for (Map.Entry<String, byte[]> s : ff.getCharStringsDict().entrySet()) { + for (Map.Entry<String, byte[]> s : getStrings(ff).entrySet()) { if (!added.contains(s.getKey())) { subsetCharStringsIndex.add(s.getValue()); added.add(s.getKey()); @@ -131,16 +112,49 @@ public class MergeCFFFonts extends OTFSu String cClass = cSet.getClass().getName(); if (cClass.equals("org.apache.fontbox.cff.CFFParser$Format1Charset") || cClass.equals("org.apache.fontbox.cff.CFFParser$Format0Charset")) { - for (CFFCharset.Entry m : cSet.getEntries()) { - if (!stringsForRange.contains(m.getName())) { - range.put(m.getSID(), 0); - stringsForRange.add(m.getName()); - } + for (int sid : getSids(cSet)) { + range.put(sid, 0); } } noOfFonts++; } + private void setupMapping(CFFCharset charset, LinkedHashMap<Integer, Integer> sg) { + int subsetGlyphIndex = 0; + for (int sid : getSids(charset)) { + if (sg.containsKey(subsetGlyphIndex)) { + int gid = sg.get(subsetGlyphIndex); + + //Check whether the SID falls into the standard string set + if (sid < NUM_STANDARD_STRINGS) { + gidToSID.put(sg.get(gid), sid); + } else { + int index = sid - NUM_STANDARD_STRINGS; + if (index <= cffReader.getStringIndex().getNumObjects()) { + gidToSID.put(sg.get(gid), stringIndexData.size() + NUM_STANDARD_STRINGS - 1); + } else { + gidToSID.put(sg.get(gid), index); + } + } + subsetGlyphIndex++; + } + } + } + + public static List<Integer> getSids(CFFCharset cSet) { + List<Integer> sids = new ArrayList<Integer>(); + for (CFFCharset.Entry x : cSet.getEntries()) { + if (x.getSID() != 0) { + sids.add(x.getSID()); + } + } + return sids; + } + + public static Map<String, byte[]> getStrings(CFFFont ff) throws IOException { + return ff.getCharStringsDict(); + } + public void writeFont() throws IOException { output = new byte[fontFileSize * 2]; if (noOfFonts == 1) { @@ -260,26 +274,6 @@ public class MergeCFFFonts extends OTFSu } protected void writeEncoding() throws IOException { - if (encoding instanceof CFFStandardEncoding) { - LinkedHashMap<String, CFFDataReader.DICTEntry> topDICT = cffReader.getTopDictEntries(); - final CFFDataReader.DICTEntry encodingEntry = topDICT.get("Encoding"); - if (encodingEntry != null && encodingEntry.getOperands().get(0).intValue() != 0 - && encodingEntry.getOperands().get(0).intValue() != 1) { - int len = encoding.getEntries().size(); - if (len != gidToSID.size() - 1) { - return; - } - writeByte(0); - writeByte(len); - for (Map.Entry<Integer, Integer> gid : gidToSID.entrySet()) { - if (gid.getKey() == 0) { - continue; - } - int code = encoding.getCode(gid.getValue()); - writeByte(code); - } - } - } if (!chars.isEmpty()) { writeCard16(chars.size()); for (int i : chars) { @@ -289,6 +283,7 @@ public class MergeCFFFonts extends OTFSu } protected void writeStringIndex() throws IOException { + int stringIndexSize = stringIndexData.size(); for (String s : strings) { stringIndexData.add(s.getBytes("US-ASCII")); } @@ -296,8 +291,10 @@ public class MergeCFFFonts extends OTFSu //Write the String Index if (!stringIndexData.isEmpty()) { if (!strings.isEmpty() && !new String(stringIndexData.get(0), "UTF-8").equals(strings.get(0))) { - //Move copyright string to end - stringIndexData.add(stringIndexData.remove(0)); + //Keep strings in order as they are referenced from the TopDICT + for (int i = 0; i < stringIndexSize; i++) { + stringIndexData.add(stringIndexData.remove(0)); + } } else { String notice = (String)fileFont.getProperty("Notice"); if (notice != null && !(fileFont instanceof CFFFontROS)) { Modified: xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/MergeTTFonts.java URL: http://svn.apache.org/viewvc/xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/MergeTTFonts.java?rev=1717631&r1=1717630&r2=1717631&view=diff ============================================================================== --- xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/MergeTTFonts.java (original) +++ xmlgraphics/fop-pdf-images/trunk/src/java/org/apache/fop/render/pdf/pdfbox/MergeTTFonts.java Wed Dec 2 14:16:54 2015 @@ -17,6 +17,7 @@ package org.apache.fop.render.pdf.pdfbox; import java.io.IOException; +import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -107,6 +108,9 @@ public class MergeTTFonts extends TTFSub byte[] glyphData = gly.getValue().data; int glyphLength = glyphData.length; int i = gly.getKey(); + if (i >= origIndexesLen) { + continue; + } int endOffset1 = endOffset; // Copy glyph writeBytes(glyphData); @@ -261,7 +265,7 @@ public class MergeTTFonts extends TTFSub } } - public void writeFont(Cmap cmap) throws IOException { + public void writeFont(List<Cmap> cmap) throws IOException { output = new byte[size * 2]; createDirectory(); // Create the TrueType header and directory int sgsize = added.size(); @@ -270,11 +274,7 @@ public class MergeTTFonts extends TTFSub // copyTable(fontFile, OFTableName.CMAP); } createHmtx(); // Create hmtx table - if (cid || locaFormat == 1) { - createLoca(sgsize); // create empty loca table - } else { - createLoca(numberOfGlyphs / 2); // create empty loca table - } + createLoca(sgsize); // create empty loca table createHead(fontFile); createOS2(fontFile); // copy the OS/2 table if (!cid) { @@ -287,23 +287,10 @@ public class MergeTTFonts extends TTFSub } else { writeMaxp(); } - boolean optionalTableFound; - optionalTableFound = createCvt(fontFile); // copy the cvt table - if (!optionalTableFound) { - // cvt is optional (used in TrueType fonts only) - log.debug("TrueType: ctv table not present. Skipped."); - } - optionalTableFound = createFpgm(fontFile); // copy fpgm table - if (!optionalTableFound) { - // fpgm is optional (used in TrueType fonts only) - log.debug("TrueType: fpgm table not present. Skipped."); - } + createCvt(fontFile); // copy the cvt table + createFpgm(fontFile); // copy fpgm table createPost(fontFile); // copy the post table - optionalTableFound = createPrep(fontFile); // copy prep table - if (!optionalTableFound) { - // prep is optional (used in TrueType fonts only) - log.debug("TrueType: prep table not present. Skipped."); - } + createPrep(fontFile); // copy prep table createName(fontFile); // copy the name table createGlyf(); //create glyf table and update loca table pad4(); @@ -334,35 +321,40 @@ public class MergeTTFonts extends TTFSub realSize += currentPos - startPos; } - private void writeCMAP(Cmap cmap) { + private void writeCMAP(List<Cmap> cmaps) { int checksum = currentPos; pad4(); int cmapPos = currentPos; writeUShort(0); //version - writeUShort(1); //number of tables - - Map<Integer, Integer> glyphIdToCharacterCode = cmap.glyphIdToCharacterCode; - writeUShort(cmap.platformId); //platformid - writeUShort(cmap.platformEncodingId); //platformEncodingId - writeULong(currentPos, currentPos - cmapPos + 12); //subTableOffset - currentPos += 12; + writeUShort(cmaps.size()); //number of tables - writeUShort(12); //subtableFormat - writeUShort(0); - writeULong(currentPos, (glyphIdToCharacterCode.size() * 12) + 16); - currentPos += 4; - writeULong(currentPos, 0); - currentPos += 4; - writeULong(currentPos, glyphIdToCharacterCode.size()); - currentPos += 4; + int tablesSize = 8 * cmaps.size(); + for (int i = 0; i < cmaps.size(); i++) { + Cmap cmap = cmaps.get(i); + writeUShort(cmap.platformId); //platformid + writeUShort(cmap.platformEncodingId); //platformEncodingId + writeULong(currentPos, 4 + tablesSize + getCmapOffset(cmaps, i)); //subTableOffset + currentPos += 4; + } - for (Map.Entry<Integer, Integer> g : glyphIdToCharacterCode.entrySet()) { - writeULong(currentPos, g.getKey()); + for (Cmap cmap : cmaps) { + writeUShort(12); //subtableFormat + writeUShort(0); + writeULong(currentPos, (cmap.glyphIdToCharacterCode.size() * 12) + 16); currentPos += 4; - writeULong(currentPos, g.getKey()); + writeULong(currentPos, 0); currentPos += 4; - writeULong(currentPos, g.getValue()); + writeULong(currentPos, cmap.glyphIdToCharacterCode.size()); currentPos += 4; + + for (Map.Entry<Integer, Integer> g : cmap.glyphIdToCharacterCode.entrySet()) { + writeULong(currentPos, g.getKey()); + currentPos += 4; + writeULong(currentPos, g.getKey()); + currentPos += 4; + writeULong(currentPos, g.getValue()); + currentPos += 4; + } } // writeUShort(6); //subtableFormat @@ -396,6 +388,15 @@ public class MergeTTFonts extends TTFSub realSize += currentPos - cmapPos; } + private int getCmapOffset(List<Cmap> cmaps, int index) { + int result = 0; + for (int i = 0; i < index; i++) { + Cmap curCmap = cmaps.get(i); + result += (curCmap.glyphIdToCharacterCode.size() * 12) + 16; + } + return result; + } + /** * Get index from starting at lowest glyph position * @param glyphs map @@ -421,5 +422,10 @@ public class MergeTTFonts extends TTFSub int platformId; int platformEncodingId; Map<Integer, Integer> glyphIdToCharacterCode = new TreeMap<Integer, Integer>(); + + public Cmap(int platformID, int platformEncodingID) { + this.platformId = platformID; + this.platformEncodingId = platformEncodingID; + } } } Modified: xmlgraphics/fop-pdf-images/trunk/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java URL: http://svn.apache.org/viewvc/xmlgraphics/fop-pdf-images/trunk/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java?rev=1717631&r1=1717630&r2=1717631&view=diff ============================================================================== --- xmlgraphics/fop-pdf-images/trunk/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java (original) +++ xmlgraphics/fop-pdf-images/trunk/test/java/org/apache/fop/render/pdf/PDFBoxAdapterTestCase.java Wed Dec 2 14:16:54 2015 @@ -284,7 +284,7 @@ public class PDFBoxAdapterTestCase { Assert.assertEquals(name, "TimesNewRomanPSMT_TrueType"); Assert.assertEquals(mbfont.getFontName(), "TimesNewRomanPSMT_TrueType"); byte[] is = IOUtils.toByteArray(mbfont.getInputStream()); - Assert.assertEquals(is.length, 34264); + Assert.assertEquals(is.length, 41352); doc.close(); doc2.close(); } --------------------------------------------------------------------- To unsubscribe, e-mail: fop-commits-unsubscr...@xmlgraphics.apache.org For additional commands, e-mail: fop-commits-h...@xmlgraphics.apache.org