Skip to content

Commit

Permalink
Upgrade PDFBox API to 2.0.25 (#427)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomRoush committed Jul 23, 2022
1 parent 916e3e2 commit 1b9cbd6
Show file tree
Hide file tree
Showing 142 changed files with 1,762 additions and 1,312 deletions.
Expand Up @@ -379,4 +379,50 @@ public void testReadPubkeyEncryptedAES256() throws IOException
is.close();
doc.close();
}
}

/**
* PDFBOX-5249: Read a file encrypted with AES128 but not with PDFBox, and with exposed
* Metadata.
*
* @throws IOException
*/
@Test
public void testReadPubkeyEncryptedAES128withMetadataExposed() throws IOException
{
InputStream is = testContext.getAssets().open(path + "AES128ExposedMeta.pdf");
PDDocument doc = PDDocument.load(is, "",
testContext.getAssets().open(path + "PDFBOX-5249.p12"), "test",
MemoryUsageSetting.setupMainMemoryOnly());
Assert.assertEquals("PublicKeySecurityHandler",
doc.getEncryption().getSecurityHandler().getClass().getSimpleName());
Assert.assertEquals(128, doc.getEncryption().getSecurityHandler().getKeyLength());
PDFTextStripper stripper = new PDFTextStripper();
stripper.setLineSeparator("\n");
Assert.assertEquals("AES key length: 128\nwith exposed Metadata", stripper.getText(doc).trim());
doc.close();
is.close();
}

/**
* PDFBOX-5249: Read a file encrypted with AES128 but not with PDFBox, and with exposed
* Metadata.
*
* @throws IOException
*/
@Test
public void testReadPubkeyEncryptedAES256withMetadataExposed() throws IOException
{
InputStream is = testContext.getAssets().open(path + "AES256ExposedMeta.pdf");
PDDocument doc = PDDocument.load(is, "",
testContext.getAssets().open(path + "PDFBOX-5249.p12"), "test",
MemoryUsageSetting.setupMainMemoryOnly());
Assert.assertEquals("PublicKeySecurityHandler",
doc.getEncryption().getSecurityHandler().getClass().getSimpleName());
Assert.assertEquals(256, doc.getEncryption().getSecurityHandler().getKeyLength());
PDFTextStripper stripper = new PDFTextStripper();
stripper.setLineSeparator("\n");
Assert.assertEquals("AES key length: 256 \nwith exposed Metadata", stripper.getText(doc).trim());
doc.close();
is.close();
}
}
Expand Up @@ -750,7 +750,6 @@ public void testFileDeletion() throws IOException
/**
* Check that there is a top level Document and Parts below in a merge of 2 documents.
*
* @param file
* @throws IOException
*/
public void testPDFBox5198_2() throws IOException
Expand All @@ -767,7 +766,6 @@ public void testPDFBox5198_2() throws IOException
/**
* Check that there is a top level Document and Parts below in a merge of 3 documents.
*
* @param file
* @throws IOException
*/
public void testPDFBox5198_3() throws IOException
Expand Down
Expand Up @@ -51,6 +51,7 @@
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 @@ -227,11 +228,7 @@ public void testFullEmbeddingTTC() throws IOException
break;
}
}
if (ttc == null)
{
Log.i("PdfBox-Android", "testFullEmbeddingTTC skipped, no .ttc files available");
return;
}
Assume.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 @@ -57,58 +57,58 @@ public void setUp() throws IOException
@Test
public void fillFields() throws IOException
{
PDTextField field = (PDTextField) acroForm.getField("AlignLeft");
PDField field = acroForm.getField("AlignLeft");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignLeft-Border_Small");
field = acroForm.getField("AlignLeft-Border_Small");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignLeft-Border_Medium");
field = acroForm.getField("AlignLeft-Border_Medium");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignLeft-Border_Wide");
field = acroForm.getField("AlignLeft-Border_Wide");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignLeft-Border_Wide_Clipped");
field = acroForm.getField("AlignLeft-Border_Wide_Clipped");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignLeft-Border_Small_Outside");
field = acroForm.getField("AlignLeft-Border_Small_Outside");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignMiddle");
field = acroForm.getField("AlignMiddle");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignMiddle-Border_Small");
field = acroForm.getField("AlignMiddle-Border_Small");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignMiddle-Border_Medium");
field = acroForm.getField("AlignMiddle-Border_Medium");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignMiddle-Border_Wide");
field = acroForm.getField("AlignMiddle-Border_Wide");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignMiddle-Border_Wide_Clipped");
field = acroForm.getField("AlignMiddle-Border_Wide_Clipped");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignMiddle-Border_Medium_Outside");
field = acroForm.getField("AlignMiddle-Border_Medium_Outside");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignRight");
field = acroForm.getField("AlignRight");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignRight-Border_Small");
field = acroForm.getField("AlignRight-Border_Small");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignRight-Border_Medium");
field = acroForm.getField("AlignRight-Border_Medium");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignRight-Border_Wide");
field = acroForm.getField("AlignRight-Border_Wide");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignRight-Border_Wide_Clipped");
field = acroForm.getField("AlignRight-Border_Wide_Clipped");
field.setValue(TEST_VALUE);

field = (PDTextField) acroForm.getField("AlignRight-Border_Wide_Outside");
field = acroForm.getField("AlignRight-Border_Wide_Outside");
field.setValue(TEST_VALUE);

// compare rendering
Expand Down
@@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.tom_roush.pdfbox.pdmodel.interactive.form;

import android.content.Context;

import androidx.test.platform.app.InstrumentationRegistry;

import java.io.File;
import java.io.IOException;

import com.tom_roush.pdfbox.android.PDFBoxResourceLoader;
import com.tom_roush.pdfbox.pdmodel.PDDocument;
import com.tom_roush.pdfbox.rendering.TestRendering;

import org.junit.Before;
import org.junit.Test;

/**
*
* @author Tilman Hausherr
*/
public class CombAlignmentTest
{
private static File OUT_DIR;
private static final String IN_DIR = "pdfbox/com/tom_roush/pdfbox/pdmodel/interactive/form";
private static final String NAME_OF_PDF = "CombTest.pdf";
private static final String TEST_VALUE = "1234567";

private Context testContext;

@Before
public void setUp() throws IOException
{
testContext = InstrumentationRegistry.getInstrumentation().getContext();
PDFBoxResourceLoader.init(testContext);
OUT_DIR = new File(testContext.getCacheDir(), "pdfbox-test-output/interactive");
OUT_DIR.mkdirs();
}

// PDFBOX-5256
@Test
public void testCombFields() throws IOException
{
PDDocument document = PDDocument.load(testContext.getAssets().open(IN_DIR + "/" + NAME_OF_PDF));
PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
PDField field = acroForm.getField("PDFBoxCombLeft");
field.setValue(TEST_VALUE);
field = acroForm.getField("PDFBoxCombMiddle");
field.setValue(TEST_VALUE);
field = acroForm.getField("PDFBoxCombRight");
field.setValue(TEST_VALUE);
// compare rendering
File file = new File(OUT_DIR, NAME_OF_PDF);
document.save(file);
document.close();
TestRendering testRendering = new TestRendering();
testRendering.setUp();
testRendering.render(file);
}
}
Binary file not shown.
47 changes: 35 additions & 12 deletions library/src/main/java/com/tom_roush/fontbox/cff/CFFParser.java
Expand Up @@ -437,6 +437,10 @@ private CFFFont parseFont(CFFDataInput input, String name, byte[] topDictIndex)
{
CFFCIDFont cffCIDFont = new CFFCIDFont();
DictData.Entry rosEntry = topDict.getEntry("ROS");
if (rosEntry == null || rosEntry.size() < 3)
{
throw new IOException("ROS entry must have 3 elements");
}
cffCIDFont.setRegistry(readString(rosEntry.getNumber(0).intValue()));
cffCIDFont.setOrdering(readString(rosEntry.getNumber(1).intValue()));
cffCIDFont.setSupplement(rosEntry.getNumber(2).intValue());
Expand Down Expand Up @@ -476,14 +480,18 @@ private CFFFont parseFont(CFFDataInput input, String name, byte[] topDictIndex)

// charstrings index
DictData.Entry charStringsEntry = topDict.getEntry("CharStrings");
if (charStringsEntry == null || !charStringsEntry.hasOperands())
{
throw new IOException("CharStrings is missing or empty");
}
int charStringsOffset = charStringsEntry.getNumber(0).intValue();
input.setPosition(charStringsOffset);
byte[][] charStringsIndex = readIndexData(input);

// charset
DictData.Entry charsetEntry = topDict.getEntry("charset");
CFFCharset charset;
if (charsetEntry != null)
if (charsetEntry != null && charsetEntry.hasOperands())
{
int charsetId = charsetEntry.getNumber(0).intValue();
if (!isCIDFont && charsetId == 0)
Expand Down Expand Up @@ -602,7 +610,7 @@ private void parseCIDFontDicts(CFFDataInput input, DictData topDict, CFFCIDFont
// In a CIDKeyed Font, the Private dictionary isn't in the Top Dict but in the Font dict
// which can be accessed by a lookup using FDArray and FDSelect
DictData.Entry fdArrayEntry = topDict.getEntry("FDArray");
if (fdArrayEntry == null)
if (fdArrayEntry == null || !fdArrayEntry.hasOperands())
{
throw new IOException("FDArray is missing for a CIDKeyed Font.");
}
Expand All @@ -626,7 +634,7 @@ private void parseCIDFontDicts(CFFDataInput input, DictData topDict, CFFCIDFont

// read private dict
DictData.Entry privateEntry = fontDict.getEntry("Private");
if (privateEntry == null)
if (privateEntry == null || privateEntry.size() < 2)
{
throw new IOException("Font DICT invalid without \"Private\" entry");
}
Expand All @@ -650,16 +658,20 @@ private void parseCIDFontDicts(CFFDataInput input, DictData topDict, CFFCIDFont
privateDictionaries.add(privDict);

// local subrs
int localSubrOffset = (Integer) privateDict.getNumber("Subrs", 0);
if (localSubrOffset > 0)
Number localSubrOffset = privateDict.getNumber("Subrs", 0);
if (localSubrOffset instanceof Integer && ((Integer) localSubrOffset) > 0)
{
input.setPosition(privateOffset + localSubrOffset);
input.setPosition(privateOffset + (Integer) localSubrOffset);
privDict.put("Subrs", readIndexData(input));
}
}

// font-dict (FD) select
DictData.Entry fdSelectEntry = topDict.getEntry("FDSelect");
if (fdSelectEntry == null || !fdSelectEntry.hasOperands())
{
throw new IOException("FDSelect is missing or empty");
}
int fdSelectPos = fdSelectEntry.getNumber(0).intValue();
input.setPosition(fdSelectPos);
FDSelect fdSelect = readFDSelect(input, nrOfcharStrings, font);
Expand Down Expand Up @@ -705,7 +717,8 @@ private void parseType1Dicts(CFFDataInput input, DictData topDict, CFFType1Font
// encoding
DictData.Entry encodingEntry = topDict.getEntry("Encoding");
CFFEncoding encoding;
int encodingId = encodingEntry != null ? encodingEntry.getNumber(0).intValue() : 0;
int encodingId = encodingEntry != null && encodingEntry.hasOperands() ?
encodingEntry.getNumber(0).intValue() : 0;
switch (encodingId)
{
case 0:
Expand All @@ -723,7 +736,7 @@ private void parseType1Dicts(CFFDataInput input, DictData topDict, CFFType1Font

// read private dict
DictData.Entry privateEntry = topDict.getEntry("Private");
if (privateEntry == null)
if (privateEntry == null || privateEntry.size() < 2)
{
throw new IOException("Private dictionary entry missing for font " + font.fontName);
}
Expand All @@ -740,10 +753,10 @@ private void parseType1Dicts(CFFDataInput input, DictData topDict, CFFType1Font
}

// local subrs
int localSubrOffset = (Integer) privateDict.getNumber("Subrs", 0);
if (localSubrOffset > 0)
Number localSubrOffset = privateDict.getNumber("Subrs", 0);
if (localSubrOffset instanceof Integer && ((Integer) localSubrOffset) > 0)
{
input.setPosition(privateOffset + localSubrOffset);
input.setPosition(privateOffset + (Integer) localSubrOffset);
font.addToPrivateDict("Subrs", readIndexData(input));
}
}
Expand All @@ -768,7 +781,7 @@ private String readString(int index)
private String getString(DictData dict, String name)
{
DictData.Entry entry = dict.getEntry(name);
return entry != null ? readString(entry.getNumber(0).intValue()) : null;
return entry != null && entry.hasOperands() ? readString(entry.getNumber(0).intValue()) : null;
}

private CFFEncoding readEncoding(CFFDataInput dataInput, CFFCharset charset) throws IOException
Expand Down Expand Up @@ -1224,6 +1237,11 @@ public Number getNumber(int index)
return operands.get(index);
}

public int size()
{
return operands.size();
}

public Boolean getBoolean(int index)
{
Number operand = operands.get(index);
Expand All @@ -1242,6 +1260,11 @@ public Boolean getBoolean(int index)
throw new IllegalArgumentException();
}

public boolean hasOperands()
{
return !operands.isEmpty();
}

public List<Number> getArray()
{
return operands;
Expand Down
Expand Up @@ -29,7 +29,7 @@
public class DataInput
{

private byte[] inputBuffer = null;
private final byte[] inputBuffer;
private int bufferPosition = 0;

/**
Expand Down

0 comments on commit 1b9cbd6

Please sign in to comment.