Skip to content

Commit

Permalink
Upgrade PDFBox API to 2.0.27 (#469)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomRoush authored Jan 2, 2023
1 parent 47824b4 commit 45da926
Show file tree
Hide file tree
Showing 76 changed files with 3,789 additions and 3,921 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public void setUp() throws Exception
permission1.setCanModify(false);
permission1.setCanModifyAnnotations(false);
permission1.setCanPrint(false);
permission1.setCanPrintDegraded(false);
permission1.setCanPrintFaithful(false);

permission2 = new AccessPermission();
permission2.setCanAssembleDocument(false);
Expand All @@ -136,7 +136,7 @@ public void setUp() throws Exception
permission2.setCanModify(false);
permission2.setCanModifyAnnotations(false);
permission2.setCanPrint(true); // it is true now !
permission2.setCanPrintDegraded(false);
permission2.setCanPrintFaithful(false);

recipient1 = getRecipient("test1.der", permission1);
recipient2 = getRecipient("test2.der", permission2);
Expand Down Expand Up @@ -228,7 +228,7 @@ public void testProtection() throws Exception
Assert.assertFalse(permission.canModify());
Assert.assertFalse(permission.canModifyAnnotations());
Assert.assertFalse(permission.canPrint());
Assert.assertFalse(permission.canPrintDegraded());
Assert.assertFalse(permission.canPrintFaithful());
}
finally
{
Expand Down Expand Up @@ -264,7 +264,7 @@ public void testMultipleRecipients() throws Exception
Assert.assertFalse(permission.canModify());
Assert.assertFalse(permission.canModifyAnnotations());
Assert.assertFalse(permission.canPrint());
Assert.assertFalse(permission.canPrintDegraded());
Assert.assertFalse(permission.canPrintFaithful());
}
finally
{
Expand All @@ -283,7 +283,7 @@ public void testMultipleRecipients() throws Exception
Assert.assertFalse(permission.canModify());
Assert.assertFalse(permission.canModifyAnnotations());
Assert.assertTrue(permission.canPrint());
Assert.assertFalse(permission.canPrintDegraded());
Assert.assertFalse(permission.canPrintFaithful());
}
finally
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public void setUp() throws Exception
permission.setCanModify(false);
permission.setCanModifyAnnotations(false);
permission.setCanPrint(true);
permission.setCanPrintDegraded(false);
permission.setCanPrintFaithful(false);
permission.setReadOnly();
}

Expand Down Expand Up @@ -147,7 +147,7 @@ public void testPermissions() throws Exception

restrAP.setCanAssembleDocument(false);
restrAP.setCanExtractForAccessibility(false);
restrAP.setCanPrintDegraded(false);
restrAP.setCanPrintFaithful(false);

inputFileAsByteArray = getFileResourceAsByteArray("PasswordSample-128bit.pdf");
checkPerms(inputFileAsByteArray, "owner", fullAP);
Expand Down Expand Up @@ -196,7 +196,7 @@ private void checkPerms(byte[] inputFileAsByteArray, String password,
assertEquals(expectedPermissions.canModify(), currentAccessPermission.canModify());
assertEquals(expectedPermissions.canModifyAnnotations(), currentAccessPermission.canModifyAnnotations());
assertEquals(expectedPermissions.canPrint(), currentAccessPermission.canPrint());
assertEquals(expectedPermissions.canPrintDegraded(), currentAccessPermission.canPrintDegraded());
assertEquals(expectedPermissions.canPrintFaithful(), currentAccessPermission.canPrintFaithful());

new PDFRenderer(doc).renderImage(0);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package com.tom_roush.pdfbox.pdmodel.font;

import android.content.Context;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.Log;

import androidx.test.platform.app.InstrumentationRegistry;
Expand Down Expand Up @@ -51,7 +53,6 @@
import com.tom_roush.pdfbox.text.PDFTextStripper;

import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;

Expand Down Expand Up @@ -228,7 +229,7 @@ public void testFullEmbeddingTTC() throws IOException
break;
}
}
Assume.assumeTrue("testFullEmbeddingTTC skipped, no .ttc files available", ttc != null);
assumeTrue("testFullEmbeddingTTC skipped, no .ttc files available", ttc != null);

final List<String> names = new ArrayList<String>();
ttc.processAllFonts(new TrueTypeCollection.TrueTypeFontProcessor()
Expand Down Expand Up @@ -431,4 +432,31 @@ public void testSoftHyphen() throws IOException
Assert.assertEquals(text + "\n" + text, extractedText.trim());
doc.close();
}

/**
* Test font with an unusual cmap table combination (0, 3).
*
* @throws IOException
*/
@Test
public void testPDFBox5484() throws IOException
{
File fontFile = TestResourceGenerator.downloadTestResource(IN_DIR, "PDFBOX-5484.ttf", "https://issues.apache.org/jira/secure/attachment/13047577/PDFBOX-5484.ttf");
assumeTrue(fontFile.exists());

TrueTypeFont ttf = new TTFParser().parse(fontFile);
PDDocument doc = new PDDocument();
PDTrueTypeFont tr = PDTrueTypeFont.load(doc, ttf, WinAnsiEncoding.INSTANCE);
Path path1 = tr.getPath("oslash");
Path path2 = tr.getPath(248);
Assert.assertFalse(path2.isEmpty()); // not empty

RectF area1 = new RectF();
path1.computeBounds(area1, true);
RectF area2 = new RectF();
path2.computeBounds(area2, true);

Assert.assertTrue(area1.equals(area2)); // assertEquals does not test equals()
doc.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,10 @@ private CFFFont parseFont(CFFDataInput input, String name, byte[] topDictIndex)
int charStringsOffset = charStringsEntry.getNumber(0).intValue();
input.setPosition(charStringsOffset);
byte[][] charStringsIndex = readIndexData(input);
if (charStringsIndex == null)
{
throw new IOException("CharStringsIndex is missing");
}

// charset
DictData.Entry charsetEntry = topDict.getEntry("charset");
Expand Down
32 changes: 24 additions & 8 deletions library/src/main/java/com/tom_roush/fontbox/cmap/CMapParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ private void parseBegincodespacerange(Number cosCount, PushbackInputStream cmapS
checkExpectedOperator((Operator) nextToken, "endcodespacerange", "codespacerange");
break;
}
if (!(nextToken instanceof byte[]))
{
throw new IOException("start range missing");
}
byte[] startRange = (byte[]) nextToken;
byte[] endRange = (byte[]) parseNextToken(cmapStream);
try
Expand All @@ -298,6 +302,10 @@ private void parseBeginbfchar(Number cosCount, PushbackInputStream cmapStream, C
checkExpectedOperator((Operator) nextToken, "endbfchar", "bfchar");
break;
}
if (!(nextToken instanceof byte[]))
{
throw new IOException("input code missing");
}
byte[] inputCode = (byte[]) nextToken;
nextToken = parseNextToken(cmapStream);
if (nextToken instanceof byte[])
Expand Down Expand Up @@ -328,6 +336,10 @@ private void parseBegincidrange(int numberOfLines, PushbackInputStream cmapStrea
checkExpectedOperator((Operator) nextToken, "endcidrange", "cidrange");
break;
}
if (!(nextToken instanceof byte[]))
{
throw new IOException("start range missing");
}
byte[] startCode = (byte[]) nextToken;
int start = createIntFromBytes(startCode);
byte[] endCode = (byte[]) parseNextToken(cmapStream);
Expand Down Expand Up @@ -369,6 +381,10 @@ private void parseBegincidchar(Number cosCount, PushbackInputStream cmapStream,
checkExpectedOperator((Operator) nextToken, "endcidchar", "cidchar");
break;
}
if (!(nextToken instanceof byte[]))
{
throw new IOException("start code missing");
}
byte[] inputCode = (byte[]) nextToken;
int mappedCode = (Integer) parseNextToken(cmapStream);
int mappedCID = createIntFromBytes(inputCode);
Expand All @@ -381,26 +397,26 @@ private void parseBeginbfrange(Number cosCount, PushbackInputStream cmapStream,
for (int j = 0; j < cosCount.intValue(); j++)
{
Object nextToken = parseNextToken(cmapStream);
if (nextToken == null)
{
throw new IOException("start code missing");
}
if (nextToken instanceof Operator)
{
checkExpectedOperator((Operator) nextToken, "endbfrange", "bfrange");
break;
}
byte[] startCode = (byte[]) nextToken;
nextToken = parseNextToken(cmapStream);
if (nextToken == null)
if (!(nextToken instanceof byte[]))
{
throw new IOException("end code missing");
throw new IOException("start code missing");
}
byte[] startCode = (byte[]) nextToken;
nextToken = parseNextToken(cmapStream);
if (nextToken instanceof Operator)
{
checkExpectedOperator((Operator) nextToken, "endbfrange", "bfrange");
break;
}
if (!(nextToken instanceof byte[]))
{
throw new IOException("end code missing");
}
byte[] endCode = (byte[]) nextToken;
int start = CMap.toInt(startCode, startCode.length);
int end = CMap.toInt(endCode, endCode.length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,9 @@ private void parsePfb(final byte[] pfb) throws IOException
}
if (size > pfbdata.length - pointer)
{
throw new IOException("PFB record size (" + size +
") doesn't fit in buffer, position: " + pointer +
", total length: " + pfbdata.length);
throw new EOFException("attempted to read " + size + " bytes at position " + pointer +
" into array of size " + pfbdata.length + ", but only space for " +
(pfbdata.length - pointer) + " bytes left");
}
int got = in.read(pfbdata, pointer, size);
if (got < 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ public Integer getCharacterCode(int gid)

private int getCharCode(int gid)
{
if (gid < 0 || gid >= glyphIdToCharacterCode.length)
if (gid < 0 || glyphIdToCharacterCode == null || gid >= glyphIdToCharacterCode.length)
{
return -1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public class GlyphTable extends TTFTable

private int cached = 0;

private HorizontalMetricsTable hmt = null;

/**
* Don't even bother to cache huge fonts.
*/
Expand Down Expand Up @@ -75,6 +77,12 @@ void read(TrueTypeFont ttf, TTFDataStream data) throws IOException

// we don't actually read the complete table here because it can contain tens of thousands of glyphs
this.data = data;

// PDFBOX-5460: read hmtx table early to avoid deadlock if getGlyph() locks "data"
// and then locks TrueTypeFont to read this table, while another thread
// locks TrueTypeFont and then tries to lock "data"
hmt = font.getHorizontalMetrics();

initialized = true;
}

Expand Down Expand Up @@ -207,7 +215,6 @@ public GlyphData getGlyph(int gid) throws IOException
private GlyphData getGlyphData(int gid) throws IOException
{
GlyphData glyph = new GlyphData();
HorizontalMetricsTable hmt = font.getHorizontalMetrics();
int leftSideBearing = hmt == null ? 0 : hmt.getLeftSideBearing(gid);
glyph.initData(this, data, leftSideBearing);
// resolve composite glyph
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,11 @@ private void readSubrs(int lenIV) throws IOException

// RD
Token charstring = read(Token.CHARSTRING);
font.subrs.set(index.intValue(), decrypt(charstring.getData(), CHARSTRING_KEY, lenIV));
int j = index.intValue();
if (j < font.subrs.size())
{
font.subrs.set(j, decrypt(charstring.getData(), CHARSTRING_KEY, lenIV));
}
readPut();
}
readDef();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,12 +682,12 @@ else if(obj instanceof COSString)
}
else if (obj instanceof COSArray)
{
Log.e("PdfBox-Android", "Nested arrays are not allowed in an array for TJ operation:" + obj);
Log.e("PdfBox-Android", "Nested arrays are not allowed in an array for TJ operation: " + obj);
}
else
{
throw new IOException("Unknown type " + obj.getClass().getSimpleName()
+ " in array for TJ operation:" + obj);
Log.e("PdfBox-Android", "Unknown type " + obj.getClass().getSimpleName()
+ " in array for TJ operation: " + obj);
}
}
}
Expand Down
17 changes: 12 additions & 5 deletions library/src/main/java/com/tom_roush/pdfbox/cos/COSDictionary.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand All @@ -40,6 +41,7 @@
public class COSDictionary extends COSBase implements COSUpdateInfo
{
private static final String PATH_SEPARATOR = "/";
private static final int MAP_THRESHOLD = 1000;
private boolean needToBeUpdated;

/**
Expand All @@ -62,7 +64,7 @@ public COSDictionary()
*/
public COSDictionary(COSDictionary dict)
{
items.putAll(dict.items);
addAll(dict);
}

/**
Expand Down Expand Up @@ -214,6 +216,10 @@ public void setItem(COSName key, COSBase value)
}
else
{
if (items instanceof SmallMap && items.size() >= MAP_THRESHOLD)
{
items = new LinkedHashMap<COSName, COSBase>(items);
}
items.put(key, value);
}
}
Expand Down Expand Up @@ -1438,14 +1444,15 @@ public void setNeedToBeUpdated(boolean flag)
* This will add all of the dictionaries keys/values to this dictionary. Existing key/value pairs will be
* overwritten.
*
* @param dic The dictionaries to get the key/value pairs from.
* @param dict The dictionaries to get the key/value pairs from.
*/
public void addAll(COSDictionary dic)
public void addAll(COSDictionary dict)
{
for (Map.Entry<COSName, COSBase> entry : dic.entrySet())
if (items instanceof SmallMap && items.size() + dict.items.size() >= MAP_THRESHOLD)
{
setItem(entry.getKey(), entry.getValue());
items = new LinkedHashMap<COSName, COSBase>(items);
}
items.putAll(dict.items);
}

/**
Expand Down
Loading

0 comments on commit 45da926

Please sign in to comment.