You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2013/11/17 12:53:41 UTC
svn commit: r1542711 [1/2] - in /pdfbox/branches/1.8: ./
fontbox/src/main/java/org/apache/fontbox/cmap/
jempbox/src/main/java/org/apache/jempbox/xmp/
pdfbox/src/main/java/org/apache/pdfbox/cos/
pdfbox/src/main/java/org/apache/pdfbox/pdfparser/ pdfbox/s...
Author: lehmi
Date: Sun Nov 17 11:53:40 2013
New Revision: 1542711
URL: http://svn.apache.org/r1542711
Log:
merged the following changes from trunk into b1.8 branch:
PDFBOX-823 r1540811
PDFBOX-837 r1538341
PDFBOX-1540 r1469999,r1470242,r1470107,r1494083
PDFBOX-1576 r1530018
PDFBOX-1606 r1521194
PDFBOX-1607 r1536441
PDFBOX-1613 r1488049
PDFBOX-1629 r1490408
PDFBOX-1630 r1497532
PDFBOX-1643 r1495802,r1495803
PDFBOX-1653 r1519174
PDFBOX-1674 r1515101
PDFBOX-1690 r1538394
Added:
pdfbox/branches/1.8/preflight/src/main/java/org/apache/pdfbox/preflight/parser/XmlResultParser.java
- copied, changed from r1469999, pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/parser/XmlResultParser.java
pdfbox/branches/1.8/preflight/src/test/java/org/apache/pdfbox/preflight/TestPreflightConfiguration.java
- copied unchanged from r1495803, pdfbox/trunk/preflight/src/test/java/org/apache/pdfbox/preflight/TestPreflightConfiguration.java
pdfbox/branches/1.8/preflight/src/test/java/org/apache/pdfbox/preflight/parser/TestXmlResultParser.java
- copied unchanged from r1494083, pdfbox/trunk/preflight/src/test/java/org/apache/pdfbox/preflight/parser/TestXmlResultParser.java
Modified:
pdfbox/branches/1.8/ (props changed)
pdfbox/branches/1.8/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java
pdfbox/branches/1.8/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchema.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/NonSequentialPDFParser.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/filespecification/PDComplexFileSpecification.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/AccessPermission.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java
pdfbox/branches/1.8/preflight/src/main/java/org/apache/pdfbox/preflight/PreflightConfiguration.java
pdfbox/branches/1.8/preflight/src/main/java/org/apache/pdfbox/preflight/PreflightConstants.java
pdfbox/branches/1.8/preflight/src/main/java/org/apache/pdfbox/preflight/ValidationResult.java
pdfbox/branches/1.8/preflight/src/main/java/org/apache/pdfbox/preflight/Validator_A1b.java
pdfbox/branches/1.8/preflight/src/main/java/org/apache/pdfbox/preflight/font/Type0FontValidator.java
pdfbox/branches/1.8/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/SynchronizedMetaDataValidation.java
pdfbox/branches/1.8/preflight/src/main/java/org/apache/pdfbox/preflight/parser/PreflightParser.java
pdfbox/branches/1.8/preflight/src/test/java/org/apache/pdfbox/preflight/metadata/TestSynchronizedMetadataValidation.java
Propchange: pdfbox/branches/1.8/
------------------------------------------------------------------------------
Merged /pdfbox/trunk:r1469999,1470107,1470242,1488049,1490408,1494083,1495802-1495803,1497532,1515101,1519174,1521194,1530018,1536441,1538341,1538394,1540811
Modified: pdfbox/branches/1.8/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java (original)
+++ pdfbox/branches/1.8/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java Sun Nov 17 11:53:40 2013
@@ -18,11 +18,11 @@ package org.apache.fontbox.cmap;
import java.io.File;
import java.io.FileInputStream;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PushbackInputStream;
-
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -30,661 +30,683 @@ import java.util.Map;
import org.apache.fontbox.util.ResourceLoader;
/**
- * This will parser a CMap stream.
+ * This will parse a CMap stream.
*
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.9 $
+ *
*/
public class CMapParser
{
- private static final String BEGIN_CODESPACE_RANGE = "begincodespacerange";
- private static final String BEGIN_BASE_FONT_CHAR = "beginbfchar";
- private static final String BEGIN_BASE_FONT_RANGE = "beginbfrange";
- private static final String BEGIN_CID_CHAR = "begincidchar";
- private static final String BEGIN_CID_RANGE = "begincidrange";
- private static final String USECMAP = "usecmap";
-
- private static final String END_CODESPACE_RANGE = "endcodespacerange";
- private static final String END_BASE_FONT_CHAR = "endbfchar";
- private static final String END_BASE_FONT_RANGE = "endbfrange";
- private static final String END_CID_CHAR = "endcidchar";
- private static final String END_CID_RANGE = "endcidrange";
-
- private static final String WMODE = "WMode";
- private static final String CMAP_NAME = "CMapName";
- private static final String CMAP_VERSION = "CMapVersion";
- private static final String CMAP_TYPE = "CMapType";
- private static final String REGISTRY = "Registry";
- private static final String ORDERING = "Ordering";
- private static final String SUPPLEMENT = "Supplement";
-
- private static final String MARK_END_OF_DICTIONARY = ">>";
- private static final String MARK_END_OF_ARRAY = "]";
-
-
- private byte[] tokenParserByteBuffer = new byte[512];
-
- /**
- * Creates a new instance of CMapParser.
- */
- public CMapParser()
- {
- }
-
- /**
- * Parse a CMAP file on the file system.
- *
- * @param file The file to parse.
- *
- * @return A parsed CMAP file.
- *
- * @throws IOException If there is an issue while parsing the CMAP.
- */
- public CMap parse( File file ) throws IOException
- {
- String rootDir = file.getParent() + File.separator;
- FileInputStream input = null;
- try
- {
- input = new FileInputStream( file );
- return parse( rootDir, input );
- }
- finally
- {
- if( input != null )
- {
- input.close();
- }
- }
-
- }
-
- /**
- * This will parse the stream and create a cmap object.
- *
- * @param resourceRoot The root path to the cmap file. This will be used
- * to find referenced cmap files. It can be null.
- * @param input The CMAP stream to parse.
- *
- * @return The parsed stream as a java object.
- *
- * @throws IOException If there is an error parsing the stream.
- */
- public CMap parse( String resourceRoot, InputStream input ) throws IOException
- {
- PushbackInputStream cmapStream = new PushbackInputStream( input );
- CMap result = new CMap();
- Object previousToken = null;
- Object token = null;
- while( (token = parseNextToken( cmapStream )) != null )
- {
- if( token instanceof Operator )
- {
- Operator op = (Operator)token;
- if( op.op.equals( USECMAP ) )
- {
- LiteralName useCmapName = (LiteralName)previousToken;
- InputStream useStream = ResourceLoader.loadResource( resourceRoot + useCmapName.name );
- if( useStream == null )
- {
- throw new IOException( "Error: Could not find referenced cmap stream " + useCmapName.name );
- }
- CMap useCMap = parse( resourceRoot, useStream );
- result.useCmap( useCMap );
- }
- else if( op.op.equals( BEGIN_CODESPACE_RANGE ) )
- {
- Number cosCount = (Number)previousToken;
- for( int j=0; j<cosCount.intValue(); j++ )
- {
- Object nextToken = parseNextToken( cmapStream );
- if (nextToken instanceof Operator) {
- if (!((Operator)nextToken).op.equals( END_CODESPACE_RANGE )) {
- throw new IOException("Error : ~codespacerange contains an unexpected operator : " + ((Operator)nextToken).op);
- }
- break;
- }
- byte[] startRange = (byte[])nextToken;
- byte[] endRange = (byte[])parseNextToken( cmapStream );
- CodespaceRange range = new CodespaceRange();
- range.setStart( startRange );
- range.setEnd( endRange );
- result.addCodespaceRange( range );
- }
- }
- else if( op.op.equals( BEGIN_BASE_FONT_CHAR ) )
- {
- Number cosCount = (Number)previousToken;
- for( int j=0; j<cosCount.intValue(); j++ )
- {
- Object nextToken = parseNextToken( cmapStream );
- if (nextToken instanceof Operator) {
- if (!((Operator)nextToken).op.equals( END_BASE_FONT_CHAR )) {
- throw new IOException("Error : ~bfchar contains an unexpected operator : " + ((Operator)nextToken).op);
- }
- break;
- }
- byte[] inputCode = (byte[])nextToken;
- nextToken = parseNextToken( cmapStream );
- if( nextToken instanceof byte[] )
- {
- byte[] bytes = (byte[])nextToken;
- String value = createStringFromBytes( bytes );
- result.addMapping( inputCode, value );
- }
- else if( nextToken instanceof LiteralName )
- {
- result.addMapping( inputCode, ((LiteralName)nextToken).name );
- }
- else
- {
- throw new IOException( "Error parsing CMap beginbfchar, expected{COSString " +
- "or COSName} and not " + nextToken );
- }
- }
- }
- else if( op.op.equals( BEGIN_BASE_FONT_RANGE ) )
- {
- Number cosCount = (Number)previousToken;
-
- for( int j=0; j<cosCount.intValue(); j++ )
- {
- Object nextToken = parseNextToken( cmapStream );
- if (nextToken instanceof Operator) {
- if (!((Operator)nextToken).op.equals( END_BASE_FONT_RANGE )) {
- throw new IOException("Error : ~bfrange contains an unexpected operator : " + ((Operator)nextToken).op);
- }
- break;
- }
- byte[] startCode = (byte[])nextToken;
- byte[] endCode = (byte[])parseNextToken( cmapStream );
- nextToken = parseNextToken( cmapStream );
- List<byte[]> array = null;
- byte[] tokenBytes = null;
- if( nextToken instanceof List<?> )
- {
- array = (List<byte[]>)nextToken;
- tokenBytes = array.get( 0 );
- }
- else
- {
- tokenBytes = (byte[])nextToken;
- }
-
- String value = null;
-
- int arrayIndex = 0;
- boolean done = false;
- while( !done )
- {
- if( compare( startCode, endCode ) >= 0 )
- {
- done = true;
- }
- value = createStringFromBytes( tokenBytes );
- result.addMapping( startCode, value );
- increment( startCode );
-
- if( array == null )
- {
- increment( tokenBytes );
- }
- else
- {
- arrayIndex++;
- if( arrayIndex < array.size() )
- {
- tokenBytes = (byte[])array.get( arrayIndex );
- }
- }
- }
- }
- }
- else if( op.op.equals( BEGIN_CID_CHAR ) )
- {
- Number cosCount = (Number)previousToken;
- for( int j=0; j<cosCount.intValue(); j++ )
- {
- Object nextToken = parseNextToken( cmapStream );
- if (nextToken instanceof Operator) {
- if (!((Operator)nextToken).op.equals( END_CID_CHAR )) {
- throw new IOException("Error : ~cidchar contains an unexpected operator : " + ((Operator)nextToken).op);
- }
- break;
- }
- byte[] inputCode = (byte[])nextToken;
- int mappedCode = (Integer)parseNextToken( cmapStream );
- String mappedStr = createStringFromBytes(inputCode);
- result.addCIDMapping(mappedCode, mappedStr);
- }
- }
- else if( op.op.equals( BEGIN_CID_RANGE ) )
- {
- int numberOfLines = (Integer)previousToken;
- for (int n=0; n < numberOfLines;n++) {
- Object nextToken = parseNextToken( cmapStream );
- if (nextToken instanceof Operator) {
- if (!((Operator)nextToken).op.equals( END_CID_RANGE )) {
- throw new IOException("Error : ~cidrange contains an unexpected operator : " + ((Operator)nextToken).op);
- }
- break;
- }
- byte[] startCode = (byte[])nextToken;
- int start = createIntFromBytes(startCode);
- byte[] endCode = (byte[])parseNextToken( cmapStream );
- int end = createIntFromBytes(endCode);
- int mappedCode = (Integer)parseNextToken( cmapStream );
- if (startCode.length <= 2 && endCode.length <= 2) {
- result.addCIDRange(
- (char) start, (char) end, mappedCode);
- } else {
- // TODO: Is this even possible?
- int endOfMappings = mappedCode + end-start;
- while (mappedCode<=endOfMappings) {
- String mappedStr = createStringFromBytes(startCode);
- result.addCIDMapping(mappedCode++, mappedStr);
- increment(startCode);
- }
- }
- }
- }
- }
- else if (token instanceof LiteralName){
- LiteralName literal = (LiteralName)token;
- if (WMODE.equals(literal.name))
- {
- Object next = parseNextToken(cmapStream);
- if (next instanceof Integer)
- {
- result.setWMode((Integer)next);
- }
- }
- else if (CMAP_NAME.equals(literal.name))
- {
- Object next = parseNextToken(cmapStream);
- if (next instanceof LiteralName)
- {
- result.setName(((LiteralName)next).name);
- }
- }
- else if (CMAP_VERSION.equals(literal.name))
- {
- Object next = parseNextToken(cmapStream);
- if (next instanceof Number)
- {
- result.setVersion(((Number)next).toString());
- }
- else if (next instanceof String)
- {
- result.setVersion((String)next);
- }
- }
- else if (CMAP_TYPE.equals(literal.name))
- {
- Object next = parseNextToken(cmapStream);
- if (next instanceof Integer)
- {
- result.setType((Integer)next);
- }
- }
- else if (REGISTRY.equals(literal.name))
- {
- Object next = parseNextToken(cmapStream);
- if (next instanceof String)
- {
- result.setRegistry((String)next);
- }
- }
- else if (ORDERING.equals(literal.name))
- {
- Object next = parseNextToken(cmapStream);
- if (next instanceof String)
- {
- result.setOrdering((String)next);
- }
- }
- else if (SUPPLEMENT.equals(literal.name))
- {
- Object next = parseNextToken(cmapStream);
- if (next instanceof Integer)
- {
- result.setSupplement((Integer)next);
- }
- }
- }
- previousToken = token;
- }
- return result;
- }
-
- private Object parseNextToken( PushbackInputStream is ) throws IOException
- {
- Object retval = null;
- int nextByte = is.read();
- //skip whitespace
- while( nextByte == 0x09 || nextByte == 0x20 || nextByte == 0x0D || nextByte == 0x0A )
- {
- nextByte = is.read();
- }
- switch( nextByte )
- {
- case '%':
- {
- //header operations, for now return the entire line
- //may need to smarter in the future
- StringBuffer buffer = new StringBuffer();
- buffer.append( (char)nextByte );
- readUntilEndOfLine( is, buffer );
- retval = buffer.toString();
- break;
- }
- case '(':
- {
- StringBuffer buffer = new StringBuffer();
- int stringByte = is.read();
-
- while( stringByte != -1 && stringByte != ')' )
- {
- buffer.append( (char)stringByte );
- stringByte = is.read();
- }
- retval = buffer.toString();
- break;
- }
- case '>':
- {
- int secondCloseBrace = is.read();
- if( secondCloseBrace == '>' )
- {
- retval = MARK_END_OF_DICTIONARY;
- }
- else
- {
- throw new IOException( "Error: expected the end of a dictionary.");
- }
- break;
- }
- case ']':
- {
- retval = MARK_END_OF_ARRAY;
- break;
- }
- case '[':
- {
- List<Object> list = new ArrayList<Object>();
-
- Object nextToken = parseNextToken( is );
- while( nextToken != null && nextToken != MARK_END_OF_ARRAY )
- {
- list.add( nextToken );
- nextToken = parseNextToken( is );
- }
- retval = list;
- break;
- }
- case '<':
- {
- int theNextByte = is.read();
- if( theNextByte == '<' )
- {
- Map<String,Object> result = new HashMap<String,Object>();
- //we are reading a dictionary
- Object key = parseNextToken( is );
- while( key instanceof LiteralName && key != MARK_END_OF_DICTIONARY )
- {
- Object value = parseNextToken( is );
- result.put( ((LiteralName)key).name, value );
- key = parseNextToken( is );
- }
- retval = result;
- }
- else
- {
- //won't read more than 512 bytes
-
- int multiplyer = 16;
- int bufferIndex = -1;
- while( theNextByte != -1 && theNextByte != '>' )
- {
- int intValue = 0;
- if( theNextByte >= '0' && theNextByte <= '9' )
- {
- intValue = theNextByte - '0';
- }
- else if( theNextByte >= 'A' && theNextByte <= 'F' )
- {
- intValue = 10 + theNextByte - 'A';
- }
- else if( theNextByte >= 'a' && theNextByte <= 'f' )
- {
- intValue = 10 + theNextByte - 'a';
- }
- else if( theNextByte == 0x20 )
- {
- // skipping whitespaces
- theNextByte = is.read();
- continue;
- }
- else
- {
- throw new IOException( "Error: expected hex character and not " +
- (char)theNextByte + ":" + theNextByte );
- }
- intValue *= multiplyer;
- if( multiplyer == 16 )
- {
- bufferIndex++;
- tokenParserByteBuffer[bufferIndex] = 0;
- multiplyer = 1;
- }
- else
- {
- multiplyer = 16;
- }
- tokenParserByteBuffer[bufferIndex]+= intValue;
- theNextByte = is.read();
- }
- byte[] finalResult = new byte[bufferIndex+1];
- System.arraycopy(tokenParserByteBuffer,0,finalResult, 0, bufferIndex+1);
- retval = finalResult;
- }
- break;
- }
- case '/':
- {
- StringBuffer buffer = new StringBuffer();
- int stringByte = is.read();
-
- while( !isWhitespaceOrEOF( stringByte ) )
- {
- buffer.append( (char)stringByte );
- stringByte = is.read();
- }
- retval = new LiteralName( buffer.toString() );
- break;
- }
- case -1:
- {
- //EOF return null;
- break;
- }
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- {
- StringBuffer buffer = new StringBuffer();
- buffer.append( (char)nextByte );
- nextByte = is.read();
-
- while( !isWhitespaceOrEOF( nextByte ) &&
- (Character.isDigit( (char)nextByte )||
- nextByte == '.' ) )
- {
- buffer.append( (char)nextByte );
- nextByte = is.read();
- }
- is.unread( nextByte );
- String value = buffer.toString();
- if( value.indexOf( '.' ) >=0 )
- {
- retval = new Double( value );
- }
- else
- {
- retval = new Integer( value );
- }
- break;
- }
- default:
- {
- StringBuffer buffer = new StringBuffer();
- buffer.append( (char)nextByte );
- nextByte = is.read();
-
- while( !isWhitespaceOrEOF( nextByte ) )
- {
- buffer.append( (char)nextByte );
- nextByte = is.read();
- }
- retval = new Operator( buffer.toString() );
-
- break;
- }
- }
- return retval;
- }
-
- private void readUntilEndOfLine( InputStream is, StringBuffer buf ) throws IOException
- {
- int nextByte = is.read();
- while( nextByte != -1 && nextByte != 0x0D && nextByte != 0x0A )
- {
- buf.append( (char)nextByte );
- nextByte = is.read();
- }
- }
-
- private boolean isWhitespaceOrEOF( int aByte )
- {
- return aByte == -1 || aByte == 0x20 || aByte == 0x0D || aByte == 0x0A;
- }
-
-
- private void increment( byte[] data )
- {
- increment( data, data.length-1 );
- }
-
- private void increment( byte[] data, int position )
- {
- if( position > 0 && (data[position]+256)%256 == 255 )
- {
- data[position]=0;
- increment( data, position-1);
- }
- else
- {
- data[position] = (byte)(data[position]+1);
- }
- }
-
- private int createIntFromBytes(byte[] bytes)
- {
- int intValue = (bytes[0]+256)%256;
- if (bytes.length == 2)
- {
- intValue <<= 8;
- intValue += (bytes[1]+256)%256;
- }
- return intValue;
- }
-
- private String createStringFromBytes( byte[] bytes ) throws IOException
- {
- String retval = null;
- if( bytes.length == 1 )
- {
- retval = new String( bytes, "ISO-8859-1" );
- }
- else
- {
- retval = new String( bytes, "UTF-16BE" );
- }
- return retval;
- }
-
- private int compare( byte[] first, byte[] second )
- {
- int retval = 1;
- int firstLength = first.length;
- for( int i=0; i<firstLength; i++ )
- {
- if( first[i] == second[i] )
- {
- continue;
- }
- else if( ((first[i]+256)%256) < ((second[i]+256)%256) )
- {
- retval = -1;
- break;
- }
- else
- {
- retval = 1;
- break;
- }
- }
- return retval;
- }
-
- /**
- * Internal class.
- */
- private class LiteralName
- {
- private String name;
- private LiteralName( String theName )
- {
- name = theName;
- }
- }
-
- /**
- * Internal class.
- */
- private class Operator
- {
- private String op;
- private Operator( String theOp )
- {
- op = theOp;
- }
- }
-
- /**
- * A simple class to test parsing of cmap files.
- *
- * @param args Some command line arguments.
- *
- * @throws Exception If there is an error parsing the file.
- */
- public static void main( String[] args ) throws Exception
- {
- if( args.length != 1 )
- {
- System.err.println( "usage: java org.pdfbox.cmapparser.CMapParser <CMAP File>" );
- System.exit( -1 );
- }
- CMapParser parser = new CMapParser( );
- File cmapFile = new File( args[0] );
- CMap result = parser.parse( cmapFile );
- System.out.println( "Result:" + result );
- }
-}
\ No newline at end of file
+ private static final String BEGIN_CODESPACE_RANGE = "begincodespacerange";
+ private static final String BEGIN_BASE_FONT_CHAR = "beginbfchar";
+ private static final String BEGIN_BASE_FONT_RANGE = "beginbfrange";
+ private static final String BEGIN_CID_CHAR = "begincidchar";
+ private static final String BEGIN_CID_RANGE = "begincidrange";
+ private static final String USECMAP = "usecmap";
+
+ private static final String END_CODESPACE_RANGE = "endcodespacerange";
+ private static final String END_BASE_FONT_CHAR = "endbfchar";
+ private static final String END_BASE_FONT_RANGE = "endbfrange";
+ private static final String END_CID_CHAR = "endcidchar";
+ private static final String END_CID_RANGE = "endcidrange";
+
+ private static final String WMODE = "WMode";
+ private static final String CMAP_NAME = "CMapName";
+ private static final String CMAP_VERSION = "CMapVersion";
+ private static final String CMAP_TYPE = "CMapType";
+ private static final String REGISTRY = "Registry";
+ private static final String ORDERING = "Ordering";
+ private static final String SUPPLEMENT = "Supplement";
+
+ private static final String MARK_END_OF_DICTIONARY = ">>";
+ private static final String MARK_END_OF_ARRAY = "]";
+
+ private byte[] tokenParserByteBuffer = new byte[512];
+
+ /**
+ * Creates a new instance of CMapParser.
+ */
+ public CMapParser()
+ {
+ }
+
+ /**
+ * Parse a CMAP file on the file system.
+ *
+ * @param file The file to parse.
+ *
+ * @return A parsed CMAP file.
+ *
+ * @throws IOException If there is an issue while parsing the CMAP.
+ */
+ public CMap parse(File file) throws IOException
+ {
+ String rootDir = file.getParent() + File.separator;
+ FileInputStream input = null;
+ try
+ {
+ input = new FileInputStream(file);
+ return parse(rootDir, input);
+ }
+ finally
+ {
+ if (input != null)
+ {
+ input.close();
+ }
+ }
+
+ }
+
+ /**
+ * This will parse the stream and create a cmap object.
+ *
+ * @param resourceRoot The root path to the cmap file. This will be used
+ * to find referenced cmap files. It can be null.
+ * @param input The CMAP stream to parse.
+ *
+ * @return The parsed stream as a java object.
+ *
+ * @throws IOException If there is an error parsing the stream.
+ */
+ public CMap parse(String resourceRoot, InputStream input) throws IOException
+ {
+ PushbackInputStream cmapStream = new PushbackInputStream(input);
+ CMap result = new CMap();
+ Object previousToken = null;
+ Object token = null;
+ while ((token = parseNextToken(cmapStream)) != null)
+ {
+ if (token instanceof Operator)
+ {
+ Operator op = (Operator) token;
+ if (op.op.equals(USECMAP))
+ {
+ LiteralName useCmapName = (LiteralName) previousToken;
+ InputStream useStream = ResourceLoader.loadResource(resourceRoot + useCmapName.name);
+ if (useStream == null)
+ {
+ throw new IOException("Error: Could not find referenced cmap stream " + useCmapName.name);
+ }
+ CMap useCMap = parse(resourceRoot, useStream);
+ result.useCmap(useCMap);
+ }
+ else if (op.op.equals(BEGIN_CODESPACE_RANGE))
+ {
+ Number cosCount = (Number) previousToken;
+ for (int j = 0; j < cosCount.intValue(); j++)
+ {
+ Object nextToken = parseNextToken(cmapStream);
+ if (nextToken instanceof Operator)
+ {
+ if (!((Operator) nextToken).op.equals(END_CODESPACE_RANGE))
+ {
+ throw new IOException("Error : ~codespacerange contains an unexpected operator : "
+ + ((Operator) nextToken).op);
+ }
+ break;
+ }
+ byte[] startRange = (byte[]) nextToken;
+ byte[] endRange = (byte[]) parseNextToken(cmapStream);
+ CodespaceRange range = new CodespaceRange();
+ range.setStart(startRange);
+ range.setEnd(endRange);
+ result.addCodespaceRange(range);
+ }
+ }
+ else if (op.op.equals(BEGIN_BASE_FONT_CHAR))
+ {
+ Number cosCount = (Number) previousToken;
+ for (int j = 0; j < cosCount.intValue(); j++)
+ {
+ Object nextToken = parseNextToken(cmapStream);
+ if (nextToken instanceof Operator)
+ {
+ if (!((Operator) nextToken).op.equals(END_BASE_FONT_CHAR))
+ {
+ throw new IOException("Error : ~bfchar contains an unexpected operator : "
+ + ((Operator) nextToken).op);
+ }
+ break;
+ }
+ byte[] inputCode = (byte[]) nextToken;
+ nextToken = parseNextToken(cmapStream);
+ if (nextToken instanceof byte[])
+ {
+ byte[] bytes = (byte[]) nextToken;
+ String value = createStringFromBytes(bytes);
+ result.addMapping(inputCode, value);
+ }
+ else if (nextToken instanceof LiteralName)
+ {
+ result.addMapping(inputCode, ((LiteralName) nextToken).name);
+ }
+ else
+ {
+ throw new IOException("Error parsing CMap beginbfchar, expected{COSString "
+ + "or COSName} and not " + nextToken);
+ }
+ }
+ }
+ else if (op.op.equals(BEGIN_BASE_FONT_RANGE))
+ {
+ Number cosCount = (Number) previousToken;
+
+ for (int j = 0; j < cosCount.intValue(); j++)
+ {
+ Object nextToken = parseNextToken(cmapStream);
+ if (nextToken instanceof Operator)
+ {
+ if (!((Operator) nextToken).op.equals(END_BASE_FONT_RANGE))
+ {
+ throw new IOException("Error : ~bfrange contains an unexpected operator : "
+ + ((Operator) nextToken).op);
+ }
+ break;
+ }
+ byte[] startCode = (byte[]) nextToken;
+ byte[] endCode = (byte[]) parseNextToken(cmapStream);
+ nextToken = parseNextToken(cmapStream);
+ List<byte[]> array = null;
+ byte[] tokenBytes = null;
+ if (nextToken instanceof List<?>)
+ {
+ array = (List<byte[]>) nextToken;
+ tokenBytes = array.get(0);
+ }
+ else
+ {
+ tokenBytes = (byte[]) nextToken;
+ }
+ boolean done = false;
+ // don't add 1:1 mappings to reduce the memory footprint
+ if (Arrays.equals(startCode, tokenBytes))
+ {
+ done = true;
+ }
+ String value = null;
+
+ int arrayIndex = 0;
+ while (!done)
+ {
+ if (compare(startCode, endCode) >= 0)
+ {
+ done = true;
+ }
+ value = createStringFromBytes(tokenBytes);
+ result.addMapping(startCode, value);
+ increment(startCode);
+
+ if (array == null)
+ {
+ increment(tokenBytes);
+ }
+ else
+ {
+ arrayIndex++;
+ if (arrayIndex < array.size())
+ {
+ tokenBytes = (byte[]) array.get(arrayIndex);
+ }
+ }
+ }
+ }
+ }
+ else if (op.op.equals(BEGIN_CID_CHAR))
+ {
+ Number cosCount = (Number) previousToken;
+ for (int j = 0; j < cosCount.intValue(); j++)
+ {
+ Object nextToken = parseNextToken(cmapStream);
+ if (nextToken instanceof Operator)
+ {
+ if (!((Operator) nextToken).op.equals(END_CID_CHAR))
+ {
+ throw new IOException("Error : ~cidchar contains an unexpected operator : "
+ + ((Operator) nextToken).op);
+ }
+ break;
+ }
+ byte[] inputCode = (byte[]) nextToken;
+ int mappedCode = (Integer) parseNextToken(cmapStream);
+ String mappedStr = createStringFromBytes(inputCode);
+ result.addCIDMapping(mappedCode, mappedStr);
+ }
+ }
+ else if (op.op.equals(BEGIN_CID_RANGE))
+ {
+ int numberOfLines = (Integer) previousToken;
+ for (int n = 0; n < numberOfLines; n++)
+ {
+ Object nextToken = parseNextToken(cmapStream);
+ if (nextToken instanceof Operator)
+ {
+ if (!((Operator) nextToken).op.equals(END_CID_RANGE))
+ {
+ throw new IOException("Error : ~cidrange contains an unexpected operator : "
+ + ((Operator) nextToken).op);
+ }
+ break;
+ }
+ byte[] startCode = (byte[]) nextToken;
+ int start = createIntFromBytes(startCode);
+ byte[] endCode = (byte[]) parseNextToken(cmapStream);
+ int end = createIntFromBytes(endCode);
+ int mappedCode = (Integer) parseNextToken(cmapStream);
+ if (startCode.length <= 2 && endCode.length <= 2)
+ {
+ result.addCIDRange((char) start, (char) end, mappedCode);
+ }
+ else
+ {
+ // TODO Is this even possible?
+ int endOfMappings = mappedCode + end - start;
+ while (mappedCode <= endOfMappings)
+ {
+ String mappedStr = createStringFromBytes(startCode);
+ result.addCIDMapping(mappedCode++, mappedStr);
+ increment(startCode);
+ }
+ }
+ }
+ }
+ }
+ else if (token instanceof LiteralName)
+ {
+ LiteralName literal = (LiteralName) token;
+ if (WMODE.equals(literal.name))
+ {
+ Object next = parseNextToken(cmapStream);
+ if (next instanceof Integer)
+ {
+ result.setWMode((Integer) next);
+ }
+ }
+ else if (CMAP_NAME.equals(literal.name))
+ {
+ Object next = parseNextToken(cmapStream);
+ if (next instanceof LiteralName)
+ {
+ result.setName(((LiteralName) next).name);
+ }
+ }
+ else if (CMAP_VERSION.equals(literal.name))
+ {
+ Object next = parseNextToken(cmapStream);
+ if (next instanceof Number)
+ {
+ result.setVersion(((Number) next).toString());
+ }
+ else if (next instanceof String)
+ {
+ result.setVersion((String) next);
+ }
+ }
+ else if (CMAP_TYPE.equals(literal.name))
+ {
+ Object next = parseNextToken(cmapStream);
+ if (next instanceof Integer)
+ {
+ result.setType((Integer) next);
+ }
+ }
+ else if (REGISTRY.equals(literal.name))
+ {
+ Object next = parseNextToken(cmapStream);
+ if (next instanceof String)
+ {
+ result.setRegistry((String) next);
+ }
+ }
+ else if (ORDERING.equals(literal.name))
+ {
+ Object next = parseNextToken(cmapStream);
+ if (next instanceof String)
+ {
+ result.setOrdering((String) next);
+ }
+ }
+ else if (SUPPLEMENT.equals(literal.name))
+ {
+ Object next = parseNextToken(cmapStream);
+ if (next instanceof Integer)
+ {
+ result.setSupplement((Integer) next);
+ }
+ }
+ }
+ previousToken = token;
+ }
+ return result;
+ }
+
+ private Object parseNextToken(PushbackInputStream is) throws IOException
+ {
+ Object retval = null;
+ int nextByte = is.read();
+ // skip whitespace
+ while (nextByte == 0x09 || nextByte == 0x20 || nextByte == 0x0D || nextByte == 0x0A)
+ {
+ nextByte = is.read();
+ }
+ switch (nextByte)
+ {
+ case '%':
+ {
+ // header operations, for now return the entire line
+ // may need to smarter in the future
+ StringBuffer buffer = new StringBuffer();
+ buffer.append((char) nextByte);
+ readUntilEndOfLine(is, buffer);
+ retval = buffer.toString();
+ break;
+ }
+ case '(':
+ {
+ StringBuffer buffer = new StringBuffer();
+ int stringByte = is.read();
+
+ while (stringByte != -1 && stringByte != ')')
+ {
+ buffer.append((char) stringByte);
+ stringByte = is.read();
+ }
+ retval = buffer.toString();
+ break;
+ }
+ case '>':
+ {
+ int secondCloseBrace = is.read();
+ if (secondCloseBrace == '>')
+ {
+ retval = MARK_END_OF_DICTIONARY;
+ }
+ else
+ {
+ throw new IOException("Error: expected the end of a dictionary.");
+ }
+ break;
+ }
+ case ']':
+ {
+ retval = MARK_END_OF_ARRAY;
+ break;
+ }
+ case '[':
+ {
+ List<Object> list = new ArrayList<Object>();
+
+ Object nextToken = parseNextToken(is);
+ while (nextToken != null && nextToken != MARK_END_OF_ARRAY)
+ {
+ list.add(nextToken);
+ nextToken = parseNextToken(is);
+ }
+ retval = list;
+ break;
+ }
+ case '<':
+ {
+ int theNextByte = is.read();
+ if (theNextByte == '<')
+ {
+ Map<String, Object> result = new HashMap<String, Object>();
+ // we are reading a dictionary
+ Object key = parseNextToken(is);
+ while (key instanceof LiteralName && key != MARK_END_OF_DICTIONARY)
+ {
+ Object value = parseNextToken(is);
+ result.put(((LiteralName) key).name, value);
+ key = parseNextToken(is);
+ }
+ retval = result;
+ }
+ else
+ {
+ // won't read more than 512 bytes
+
+ int multiplyer = 16;
+ int bufferIndex = -1;
+ while (theNextByte != -1 && theNextByte != '>')
+ {
+ int intValue = 0;
+ if (theNextByte >= '0' && theNextByte <= '9')
+ {
+ intValue = theNextByte - '0';
+ }
+ else if (theNextByte >= 'A' && theNextByte <= 'F')
+ {
+ intValue = 10 + theNextByte - 'A';
+ }
+ else if (theNextByte >= 'a' && theNextByte <= 'f')
+ {
+ intValue = 10 + theNextByte - 'a';
+ }
+ else if (theNextByte == 0x20)
+ {
+ // skipping whitespaces
+ theNextByte = is.read();
+ continue;
+ }
+ else
+ {
+ throw new IOException("Error: expected hex character and not " + (char) theNextByte + ":"
+ + theNextByte);
+ }
+ intValue *= multiplyer;
+ if (multiplyer == 16)
+ {
+ bufferIndex++;
+ tokenParserByteBuffer[bufferIndex] = 0;
+ multiplyer = 1;
+ }
+ else
+ {
+ multiplyer = 16;
+ }
+ tokenParserByteBuffer[bufferIndex] += intValue;
+ theNextByte = is.read();
+ }
+ byte[] finalResult = new byte[bufferIndex + 1];
+ System.arraycopy(tokenParserByteBuffer, 0, finalResult, 0, bufferIndex + 1);
+ retval = finalResult;
+ }
+ break;
+ }
+ case '/':
+ {
+ StringBuffer buffer = new StringBuffer();
+ int stringByte = is.read();
+
+ while (!isWhitespaceOrEOF(stringByte))
+ {
+ buffer.append((char) stringByte);
+ stringByte = is.read();
+ }
+ retval = new LiteralName(buffer.toString());
+ break;
+ }
+ case -1:
+ {
+ // EOF return null;
+ break;
+ }
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append((char) nextByte);
+ nextByte = is.read();
+
+ while (!isWhitespaceOrEOF(nextByte) && (Character.isDigit((char) nextByte) || nextByte == '.'))
+ {
+ buffer.append((char) nextByte);
+ nextByte = is.read();
+ }
+ is.unread(nextByte);
+ String value = buffer.toString();
+ if (value.indexOf('.') >= 0)
+ {
+ retval = new Double(value);
+ }
+ else
+ {
+ retval = new Integer(value);
+ }
+ break;
+ }
+ default:
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append((char) nextByte);
+ nextByte = is.read();
+
+ while (!isWhitespaceOrEOF(nextByte))
+ {
+ buffer.append((char) nextByte);
+ nextByte = is.read();
+ }
+ retval = new Operator(buffer.toString());
+
+ break;
+ }
+ }
+ return retval;
+ }
+
+ private void readUntilEndOfLine(InputStream is, StringBuffer buf) throws IOException
+ {
+ int nextByte = is.read();
+ while (nextByte != -1 && nextByte != 0x0D && nextByte != 0x0A)
+ {
+ buf.append((char) nextByte);
+ nextByte = is.read();
+ }
+ }
+
+ private boolean isWhitespaceOrEOF(int aByte)
+ {
+ return aByte == -1 || aByte == 0x20 || aByte == 0x0D || aByte == 0x0A;
+ }
+
+ private void increment(byte[] data)
+ {
+ increment(data, data.length - 1);
+ }
+
+ private void increment(byte[] data, int position)
+ {
+ if (position > 0 && (data[position] + 256) % 256 == 255)
+ {
+ data[position] = 0;
+ increment(data, position - 1);
+ }
+ else
+ {
+ data[position] = (byte) (data[position] + 1);
+ }
+ }
+
+ private int createIntFromBytes(byte[] bytes)
+ {
+ int intValue = (bytes[0] + 256) % 256;
+ if (bytes.length == 2)
+ {
+ intValue <<= 8;
+ intValue += (bytes[1] + 256) % 256;
+ }
+ return intValue;
+ }
+
+ private String createStringFromBytes(byte[] bytes) throws IOException
+ {
+ String retval = null;
+ if (bytes.length == 1)
+ {
+ retval = new String(bytes, "ISO-8859-1");
+ }
+ else
+ {
+ retval = new String(bytes, "UTF-16BE");
+ }
+ return retval;
+ }
+
+ private int compare(byte[] first, byte[] second)
+ {
+ int retval = 1;
+ int firstLength = first.length;
+ for (int i = 0; i < firstLength; i++)
+ {
+ if (first[i] == second[i])
+ {
+ continue;
+ }
+ else if (((first[i] + 256) % 256) < ((second[i] + 256) % 256))
+ {
+ retval = -1;
+ break;
+ }
+ else
+ {
+ retval = 1;
+ break;
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Internal class.
+ */
+ private class LiteralName
+ {
+ private String name;
+
+ private LiteralName(String theName)
+ {
+ name = theName;
+ }
+ }
+
+ /**
+ * Internal class.
+ */
+ private class Operator
+ {
+ private String op;
+
+ private Operator(String theOp)
+ {
+ op = theOp;
+ }
+ }
+
+ /**
+ * A simple class to test parsing of cmap files.
+ *
+ * @param args Some command line arguments.
+ *
+ * @throws Exception If there is an error parsing the file.
+ */
+ public static void main(String[] args) throws Exception
+ {
+ if (args.length != 1)
+ {
+ System.err.println("usage: java org.apache.fontbox.cmap.CMapParser <CMAP File>");
+ System.exit(-1);
+ }
+ CMapParser parser = new CMapParser();
+ File cmapFile = new File(args[0]);
+ CMap result = parser.parse(cmapFile);
+ System.out.println("Result:" + result);
+ }
+}
Modified: pdfbox/branches/1.8/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchema.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchema.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchema.java (original)
+++ pdfbox/branches/1.8/jempbox/src/main/java/org/apache/jempbox/xmp/XMPSchema.java Sun Nov 17 11:53:40 2013
@@ -36,7 +36,7 @@ import org.w3c.dom.NodeList;
* subclasses for access to specific properties.
*
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.8 $
+ *
*/
public class XMPSchema
{
@@ -246,7 +246,15 @@ public class XMPSchema
*/
public void setDateProperty(String propertyName, Calendar date)
{
- setTextProperty(propertyName, DateConverter.toISO8601(date));
+ if (date != null)
+ {
+ setTextProperty(propertyName, DateConverter.toISO8601(date));
+ }
+ else
+ {
+ // remove the value for the given property
+ setTextProperty(propertyName, null);
+ }
}
/**
@@ -820,7 +828,8 @@ public class XMPSchema
}
}
}
- else if (property.getChildNodes().getLength() == 1 && Node.TEXT_NODE == property.getFirstChild().getNodeType())
+ else if (property.getChildNodes().getLength() == 1
+ && Node.TEXT_NODE == property.getFirstChild().getNodeType())
{
retval = property.getFirstChild().getNodeValue();
}
Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java Sun Nov 17 11:53:40 2013
@@ -30,7 +30,7 @@ import org.apache.pdfbox.persistence.uti
* This class represents a PDF named object.
*
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.42 $
+ *
*/
public final class COSName extends COSBase implements Comparable<COSName>
{
@@ -385,6 +385,10 @@ public final class COSName extends COSBa
/**
* A common COSName value.
*/
+ public static final COSName DESC = new COSName("Desc");
+ /**
+ * A common COSName value.
+ */
public static final COSName DESCENT = new COSName( "Descent" );
/**
* A common COSName value.
@@ -1030,6 +1034,26 @@ public final class COSName extends COSBa
/**
* A common COSName value.
*/
+ public static final COSName OUTPUT_INTENT = new COSName("OutputIntent");
+
+ /**
+ * A common COSName value.
+ */
+ public static final COSName OUTPUT_INTENTS = new COSName("OutputIntents");
+
+ /**
+ * A common COSName value.
+ */
+ public static final COSName OUTPUT_CONDITION = new COSName("OutputCondition");
+
+ /**
+ * A common COSName value.
+ */
+ public static final COSName OUTPUT_CONDITION_IDENTIFIER = new COSName("OutputConditionIdentifier");
+
+ /**
+ * A common COSName value.
+ */
public static final COSName OPEN_ACTION = new COSName("OpenAction");
/** A common COSName value. */
Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java Sun Nov 17 11:53:40 2013
@@ -994,10 +994,11 @@ public abstract class BaseParser
}
else
{
- // if invalid chars was found
+ // if invalid chars was found: discard last
+ // hex character if it is not part of a pair
if (sBuf.length()%2!=0)
{
- sBuf.deleteCharAt(strmBuf.length-1);
+ sBuf.deleteCharAt(sBuf.length()-1);
}
// read till the closing bracket was found
Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/NonSequentialPDFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/NonSequentialPDFParser.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/NonSequentialPDFParser.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/NonSequentialPDFParser.java Sun Nov 17 11:53:40 2013
@@ -94,18 +94,15 @@ public class NonSequentialPDFParser exte
/**
* EOF-marker.
*/
- protected static final char[] EOF_MARKER = new char[]
- { '%', '%', 'E', 'O', 'F' };
+ protected static final char[] EOF_MARKER = new char[] { '%', '%', 'E', 'O', 'F' };
/**
* StartXRef-marker.
*/
- protected static final char[] STARTXREF_MARKER = new char[]
- { 's', 't', 'a', 'r', 't', 'x', 'r', 'e', 'f' };
+ protected static final char[] STARTXREF_MARKER = new char[] { 's', 't', 'a', 'r', 't', 'x', 'r', 'e', 'f' };
/**
* obj-marker.
*/
- protected static final char[] OBJ_MARKER = new char[]
- { 'o', 'b', 'j' };
+ protected static final char[] OBJ_MARKER = new char[] { 'o', 'b', 'j' };
private final File pdfFile;
private final RandomAccessBufferedFileInputStream raStream;
@@ -365,15 +362,6 @@ public class NonSequentialPDFParser exte
COSDictionary trailer = xrefTrailerResolver.getTrailer();
document.setTrailer(trailer);
- // JIRA-1557 - ensure that all COSObject are loaded in the trailer
- for (COSBase trailerEntry : trailer.getValues())
- {
- if (trailerEntry instanceof COSObject)
- {
- COSObject tmpObj = (COSObject) trailerEntry;
- parseObjectDynamically(tmpObj, false);
- }
- }
// ---- prepare encryption if necessary
COSBase trailerEncryptItem = document.getTrailer().getItem(COSName.ENCRYPT);
if (trailerEncryptItem != null)
@@ -413,11 +401,23 @@ public class NonSequentialPDFParser exte
catch (Exception e)
{
throw new IOException("Error (" + e.getClass().getSimpleName()
- + ") while creating security handler for decryption: "
- + e.getMessage() /*, e TODO: remove remark with Java 1.6 */);
+ + ") while creating security handler for decryption: " + e.getMessage() /*
+ * , e TODO: remove
+ * remark with Java 1.6
+ */);
}
}
+ // PDFBOX-1557 - ensure that all COSObject are loaded in the trailer
+ // PDFBOX-1606 - after securityHandler has been instantiated
+ for (COSBase trailerEntry : trailer.getValues())
+ {
+ if (trailerEntry instanceof COSObject)
+ {
+ COSObject tmpObj = (COSObject) trailerEntry;
+ parseObjectDynamically(tmpObj, false);
+ }
+ }
// ---- parse catalog or root object
COSObject root = (COSObject) xrefTrailerResolver.getTrailer().getItem(COSName.ROOT);
@@ -1049,9 +1049,7 @@ public class NonSequentialPDFParser exte
.intValue());
if (!(parsedObjects.contains(objId) /*
- * ||
- * document.hasObjectInPool
- * ( objKey )
+ * || document.hasObjectInPool ( objKey )
*/))
{
Long fileOffset = xrefTrailerResolver.getXrefTable().get(objKey);
@@ -1223,8 +1221,7 @@ public class NonSequentialPDFParser exte
// this is not legal
// the combination of a dict and the stream/endstream
// forms a complete stream object
- throw new IOException("Stream not preceded by dictionary (offset: "
- + offsetOrObjstmObNr + ").");
+ throw new IOException("Stream not preceded by dictionary (offset: " + offsetOrObjstmObNr + ").");
}
skipSpaces();
endObjectKey = readLine();
@@ -1483,8 +1480,7 @@ public class NonSequentialPDFParser exte
}
/*
- * This needs to be dic.getItem because when we are parsing, the
- * underlying object might still be null.
+ * This needs to be dic.getItem because when we are parsing, the underlying object might still be null.
*/
COSNumber streamLengthObj = getLength(dic.getItem(COSName.LENGTH));
if (streamLengthObj == null)
Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java Sun Nov 17 11:53:40 2013
@@ -185,7 +185,8 @@ public class PDFParser extends BaseParse
}
try
{
- wasLastParsedObjectEOF = parseObject();
+ // don't reset flag to false if it is already true
+ wasLastParsedObjectEOF |= parseObject();
}
catch(IOException e)
{
Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java Sun Nov 17 11:53:40 2013
@@ -1420,7 +1420,10 @@ public class COSWriter implements ICOSVi
* @throws COSVisitorException If an error occurs while generating the data.
*/
public void write(PDDocument doc) throws COSVisitorException
- {
+ {
+ Long idTime = doc.getDocumentId() == null ? System.currentTimeMillis() :
+ doc.getDocumentId();
+
document = doc;
if(incrementalUpdate)
{
@@ -1473,7 +1476,7 @@ public class COSWriter implements ICOSVi
//algorithm says to use time/path/size/values in doc to generate
//the id. We don't have path or size, so do the best we can
MessageDigest md = MessageDigest.getInstance( "MD5" );
- md.update( Long.toString( System.currentTimeMillis()).getBytes("ISO-8859-1") );
+ md.update( Long.toString(idTime).getBytes("ISO-8859-1") );
COSDictionary info = (COSDictionary)trailer.getDictionaryObject( COSName.INFO );
if( info != null )
{
Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java Sun Nov 17 11:53:40 2013
@@ -116,6 +116,14 @@ public class PDDocument implements Pagea
* from this documents.
*/
private boolean allSecurityToBeRemoved = false;
+
+ /**
+ * Keep tracking customized documentId for the trailer. If null, a new
+ * id will be generated for the document. This ID doesn't represent the
+ * actual documentId from the trailer.
+ */
+ private Long documentId;
+
/**
* Constructor, creates a new PDF Document with no pages. You need to add
@@ -1632,5 +1640,15 @@ public class PDDocument implements Pagea
{
allSecurityToBeRemoved = removeAllSecurity;
}
+
+ public Long getDocumentId()
+ {
+ return documentId;
+ }
+
+ public void setDocumentId(Long docId)
+ {
+ documentId = docId;
+ }
}
Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/filespecification/PDComplexFileSpecification.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/filespecification/PDComplexFileSpecification.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/filespecification/PDComplexFileSpecification.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/filespecification/PDComplexFileSpecification.java Sun Nov 17 11:53:40 2013
@@ -25,7 +25,7 @@ import org.apache.pdfbox.cos.COSStream;
* This represents a file specification.
*
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.4 $
+ *
*/
public class PDComplexFileSpecification extends PDFileSpecification
{
@@ -353,5 +353,26 @@ public class PDComplexFileSpecification
ef.setItem( COSName.UNIX, file );
}
}
+
+ /**
+ * Set the file description.
+ *
+ * @param description The file description
+ */
+ public void setFileDescription( String description )
+ {
+ fs.setString( COSName.DESC, description );
+ }
+
+ /**
+ * This will get the description.
+ *
+ * @return The file description.
+ */
+ public String getFileDescription()
+ {
+ return fs.getString( COSName.DESC );
+ }
+
}
Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/AccessPermission.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/AccessPermission.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/AccessPermission.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/AccessPermission.java Sun Nov 17 11:53:40 2013
@@ -44,7 +44,6 @@ package org.apache.pdfbox.pdmodel.encryp
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
* @author Benoit Guillon (benoit.guillon@snv.jussieu.fr)
*
- * @version $Revision: 1.4 $
*/
public class AccessPermission
@@ -419,4 +418,30 @@ public class AccessPermission
{
return readOnly;
}
+
+ /**
+ * Indicates if any revision 3 access permission is set or not.
+ *
+ * @return true if any revision 3 access permission is set
+ */
+ protected boolean hasAnyRevision3PermissionSet()
+ {
+ if (canFillInForm())
+ {
+ return true;
+ }
+ if (canExtractForAccessibility())
+ {
+ return true;
+ }
+ if (canAssembleDocument())
+ {
+ return true;
+ }
+ if (canPrintDegraded())
+ {
+ return true;
+ }
+ return false;
+ }
}
Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java?rev=1542711&r1=1542710&r2=1542711&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java Sun Nov 17 11:53:40 2013
@@ -59,23 +59,22 @@ import org.apache.pdfbox.pdmodel.PDDocum
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
* @author Benoit Guillon (benoit.guillon@snv.jussieu.fr)
*
- * @version $Revision: 1.4 $
*/
public abstract class SecurityHandler
{
- /* ------------------------------------------------
- * CONSTANTS
- -------------------------------------------------- */
+ /**
+ * CONSTANTS.
+ */
private static final int DEFAULT_KEY_LENGTH = 40;
/*
* See 7.6.2, page 58, PDF 32000-1:2008
*/
- private final static byte[] AES_SALT = {(byte) 0x73, (byte) 0x41, (byte) 0x6c, (byte) 0x54};
-
+ private static final byte[] AES_SALT = { (byte) 0x73, (byte) 0x41, (byte) 0x6c, (byte) 0x54 };
+
/**
* The value of V field of the Encryption dictionary.
*/
@@ -106,11 +105,11 @@ public abstract class SecurityHandler
private Set<COSDictionary> potentialSignatures = new HashSet<COSDictionary>();
- /*
- * If true, AES will be used
+ /**
+ * If true, AES will be used.
*/
private boolean aes;
-
+
/**
* The access permission granted to the current user for the document. These
* permissions are computed during decryption and are in read only mode.
@@ -142,9 +141,8 @@ public abstract class SecurityHandler
* @throws CryptographyException If there is an error with decryption.
*/
public abstract void prepareForDecryption(PDEncryptionDictionary encDictionary, COSArray documentIDArray,
- DecryptionMaterial decryptionMaterial)
- throws CryptographyException, IOException;
-
+ DecryptionMaterial decryptionMaterial) throws CryptographyException, IOException;
+
/**
* Prepare the document for decryption.
*
@@ -153,9 +151,8 @@ public abstract class SecurityHandler
* @throws CryptographyException If there is an error while preparing.
* @throws IOException If there is an error with the document.
*/
- public abstract void decryptDocument(PDDocument doc, DecryptionMaterial mat)
- throws CryptographyException, IOException;
-
+ public abstract void decryptDocument(PDDocument doc, DecryptionMaterial mat) throws CryptographyException,
+ IOException;
/**
* This method must be called by an implementation of this class to really proceed
@@ -168,18 +165,18 @@ public abstract class SecurityHandler
{
COSDictionary trailer = document.getDocument().getTrailer();
- COSArray fields = (COSArray)trailer.getObjectFromPath( "Root/AcroForm/Fields" );
+ COSArray fields = (COSArray) trailer.getObjectFromPath("Root/AcroForm/Fields");
- //We need to collect all the signature dictionaries, for some
- //reason the 'Contents' entry of signatures is not really encrypted
- if( fields != null )
+ // We need to collect all the signature dictionaries, for some
+ // reason the 'Contents' entry of signatures is not really encrypted
+ if (fields != null)
{
- for( int i=0; i<fields.size(); i++ )
+ for (int i = 0; i < fields.size(); i++)
{
- COSDictionary field = (COSDictionary)fields.getObject( i );
- if (field!= null)
+ COSDictionary field = (COSDictionary) fields.getObject(i);
+ if (field != null)
{
- addDictionaryAndSubDictionary( potentialSignatures, field );
+ addDictionaryAndSubDictionary(potentialSignatures, field);
}
else
{
@@ -190,29 +187,29 @@ public abstract class SecurityHandler
List<COSObject> allObjects = document.getDocument().getObjects();
Iterator<COSObject> objectIter = allObjects.iterator();
- while( objectIter.hasNext() )
+ while (objectIter.hasNext())
{
- decryptObject( objectIter.next() );
+ decryptObject(objectIter.next());
}
- document.setEncryptionDictionary( null );
+ document.setEncryptionDictionary(null);
}
- private void addDictionaryAndSubDictionary( Set<COSDictionary> set, COSDictionary dic )
+ private void addDictionaryAndSubDictionary(Set<COSDictionary> set, COSDictionary dic)
{
- if ( dic != null ) // in case dictionary is part of object stream we have null value here
- {
- set.add( dic );
- COSArray kids = (COSArray)dic.getDictionaryObject( COSName.KIDS );
- for( int i=0; kids != null && i<kids.size(); i++ )
- {
- addDictionaryAndSubDictionary( set, (COSDictionary)kids.getObject( i ) );
- }
- COSBase value = dic.getDictionaryObject( COSName.V );
- if( value instanceof COSDictionary )
- {
- addDictionaryAndSubDictionary( set, (COSDictionary)value );
- }
- }
+ if (dic != null) // in case dictionary is part of object stream we have null value here
+ {
+ set.add(dic);
+ COSArray kids = (COSArray) dic.getDictionaryObject(COSName.KIDS);
+ for (int i = 0; kids != null && i < kids.size(); i++)
+ {
+ addDictionaryAndSubDictionary(set, (COSDictionary) kids.getObject(i));
+ }
+ COSBase value = dic.getDictionaryObject(COSName.V);
+ if (value instanceof COSDictionary)
+ {
+ addDictionaryAndSubDictionary(set, (COSDictionary) value);
+ }
+ }
}
/**
@@ -230,7 +227,7 @@ public abstract class SecurityHandler
* reasons and will be removed in the future.
*/
public void encryptData(long objectNumber, long genNumber, InputStream data, OutputStream output)
- throws CryptographyException, IOException
+ throws CryptographyException, IOException
{
// default to encrypting since the function is named "encryptData"
encryptData(objectNumber, genNumber, data, output, false);
@@ -248,97 +245,106 @@ public abstract class SecurityHandler
* @throws CryptographyException If there is an error during the encryption.
* @throws IOException If there is an error reading the data.
*/
- public void encryptData(long objectNumber, long genNumber, InputStream data, OutputStream output, boolean decrypt)
- throws CryptographyException, IOException
+ public void encryptData(long objectNumber, long genNumber, InputStream data, OutputStream output, boolean decrypt)
+ throws CryptographyException, IOException
{
- if (aes && !decrypt) {
+ if (aes && !decrypt)
+ {
throw new IllegalArgumentException("AES encryption is not yet implemented.");
}
-
- byte[] newKey = new byte[ encryptionKey.length + 5 ];
- System.arraycopy( encryptionKey, 0, newKey, 0, encryptionKey.length );
- //PDF 1.4 reference pg 73
- //step 1
- //we have the reference
-
- //step 2
- newKey[newKey.length -5] = (byte)(objectNumber & 0xff);
- newKey[newKey.length -4] = (byte)((objectNumber >> 8) & 0xff);
- newKey[newKey.length -3] = (byte)((objectNumber >> 16) & 0xff);
- newKey[newKey.length -2] = (byte)(genNumber & 0xff);
- newKey[newKey.length -1] = (byte)((genNumber >> 8) & 0xff);
+ byte[] newKey = new byte[encryptionKey.length + 5];
+ System.arraycopy(encryptionKey, 0, newKey, 0, encryptionKey.length);
+ // PDF 1.4 reference pg 73
+ // step 1
+ // we have the reference
+
+ // step 2
+ newKey[newKey.length - 5] = (byte) (objectNumber & 0xff);
+ newKey[newKey.length - 4] = (byte) ((objectNumber >> 8) & 0xff);
+ newKey[newKey.length - 3] = (byte) ((objectNumber >> 16) & 0xff);
+ newKey[newKey.length - 2] = (byte) (genNumber & 0xff);
+ newKey[newKey.length - 1] = (byte) ((genNumber >> 8) & 0xff);
- //step 3
+ // step 3
byte[] digestedKey = null;
try
{
- MessageDigest md = MessageDigest.getInstance( "MD5" );
+ MessageDigest md = MessageDigest.getInstance("MD5");
md.update(newKey);
- if (aes) {
+ if (aes)
+ {
md.update(AES_SALT);
}
digestedKey = md.digest();
}
- catch( NoSuchAlgorithmException e )
+ catch (NoSuchAlgorithmException e)
{
- throw new CryptographyException( e );
+ throw new CryptographyException(e);
}
- //step 4
- int length = Math.min( newKey.length, 16 );
- byte[] finalKey = new byte[ length ];
- System.arraycopy( digestedKey, 0, finalKey, 0, length );
+ // step 4
+ int length = Math.min(newKey.length, 16);
+ byte[] finalKey = new byte[length];
+ System.arraycopy(digestedKey, 0, finalKey, 0, length);
if (aes)
{
byte[] iv = new byte[16];
-
+
data.read(iv);
-
- try {
+
+ try
+ {
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
-
+
SecretKey aesKey = new SecretKeySpec(finalKey, "AES");
-
+
IvParameterSpec ips = new IvParameterSpec(iv);
-
+
decryptCipher.init(decrypt ? Cipher.DECRYPT_MODE : Cipher.ENCRYPT_MODE, aesKey, ips);
-
+
CipherInputStream cipherStream = new CipherInputStream(data, decryptCipher);
-
- try {
- byte buffer[] = new byte[4096];
- for(int n = 0; -1 != (n = cipherStream.read(buffer));)
+
+ try
+ {
+ byte[] buffer = new byte[4096];
+ for (int n = 0; -1 != (n = cipherStream.read(buffer));)
{
output.write(buffer, 0, n);
}
}
- finally {
+ finally
+ {
cipherStream.close();
}
}
- catch (InvalidKeyException e) {
+ catch (InvalidKeyException e)
+ {
throw new WrappedIOException(e);
}
- catch (InvalidAlgorithmParameterException e) {
+ catch (InvalidAlgorithmParameterException e)
+ {
throw new WrappedIOException(e);
}
- catch (NoSuchAlgorithmException e) {
+ catch (NoSuchAlgorithmException e)
+ {
throw new WrappedIOException(e);
}
- catch (NoSuchPaddingException e) {
+ catch (NoSuchPaddingException e)
+ {
throw new WrappedIOException(e);
}
}
- else {
- rc4.setKey( finalKey );
- rc4.write( data, output );
+ else
+ {
+ rc4.setKey(finalKey);
+ rc4.write(data, output);
}
-
+
output.flush();
}
-
+
/**
* This will decrypt an object in the document.
*
@@ -347,13 +353,12 @@ public abstract class SecurityHandler
* @throws CryptographyException If there is an error decrypting the stream.
* @throws IOException If there is an error getting the stream data.
*/
- private void decryptObject( COSObject object )
- throws CryptographyException, IOException
+ private void decryptObject(COSObject object) throws CryptographyException, IOException
{
long objNum = object.getObjectNumber().intValue();
long genNum = object.getGenerationNumber().intValue();
COSBase base = object.getObject();
- decrypt( base, objNum, genNum );
+ decrypt(base, objNum, genNum);
}
/**
@@ -366,28 +371,27 @@ public abstract class SecurityHandler
* @throws CryptographyException If there is an error decrypting the stream.
* @throws IOException If there is an error getting the stream data.
*/
- private void decrypt( COSBase obj, long objNum, long genNum )
- throws CryptographyException, IOException
+ private void decrypt(COSBase obj, long objNum, long genNum) throws CryptographyException, IOException
{
- if( !objects.contains( obj ) )
+ if (!objects.contains(obj))
{
- objects.add( obj );
+ objects.add(obj);
- if( obj instanceof COSString )
+ if (obj instanceof COSString)
{
- decryptString( (COSString)obj, objNum, genNum );
+ decryptString((COSString) obj, objNum, genNum);
}
- else if( obj instanceof COSStream )
+ else if (obj instanceof COSStream)
{
- decryptStream( (COSStream)obj, objNum, genNum );
+ decryptStream((COSStream) obj, objNum, genNum);
}
- else if( obj instanceof COSDictionary )
+ else if (obj instanceof COSDictionary)
{
- decryptDictionary( (COSDictionary)obj, objNum, genNum );
+ decryptDictionary((COSDictionary) obj, objNum, genNum);
}
- else if( obj instanceof COSArray )
+ else if (obj instanceof COSArray)
{
- decryptArray( (COSArray)obj, objNum, genNum );
+ decryptArray((COSArray) obj, objNum, genNum);
}
}
}
@@ -402,18 +406,13 @@ public abstract class SecurityHandler
* @throws CryptographyException If there is an error getting the stream.
* @throws IOException If there is an error getting the stream data.
*/
- public void decryptStream( COSStream stream, long objNum, long genNum )
- throws CryptographyException, IOException
+ public void decryptStream(COSStream stream, long objNum, long genNum) throws CryptographyException, IOException
{
- decryptDictionary( stream, objNum, genNum );
+ decryptDictionary(stream, objNum, genNum);
InputStream encryptedStream = stream.getFilteredStream();
- encryptData( objNum,
- genNum,
- encryptedStream,
- stream.createFilteredStream(),
- true /* decrypt */);
+ encryptData(objNum, genNum, encryptedStream, stream.createFilteredStream(), true /* decrypt */);
}
-
+
/**
* This will encrypt a stream, but not the dictionary as the dictionary is
* encrypted by visitFromString() in COSWriter and we don't want to encrypt
@@ -426,15 +425,10 @@ public abstract class SecurityHandler
* @throws CryptographyException If there is an error getting the stream.
* @throws IOException If there is an error getting the stream data.
*/
- public void encryptStream( COSStream stream, long objNum, long genNum )
- throws CryptographyException, IOException
+ public void encryptStream(COSStream stream, long objNum, long genNum) throws CryptographyException, IOException
{
InputStream encryptedStream = stream.getFilteredStream();
- encryptData( objNum,
- genNum,
- encryptedStream,
- stream.createFilteredStream(),
- false /* encrypt */);
+ encryptData(objNum, genNum, encryptedStream, stream.createFilteredStream(), false /* encrypt */);
}
/**
@@ -447,22 +441,22 @@ public abstract class SecurityHandler
* @throws CryptographyException If there is an error decrypting the document.
* @throws IOException If there is an error creating a new string.
*/
- private void decryptDictionary( COSDictionary dictionary, long objNum, long genNum )
- throws CryptographyException, IOException
+ private void decryptDictionary(COSDictionary dictionary, long objNum, long genNum) throws CryptographyException,
+ IOException
{
- for( Map.Entry<COSName, COSBase> entry : dictionary.entrySet() )
+ for (Map.Entry<COSName, COSBase> entry : dictionary.entrySet())
{
COSBase value = entry.getValue();
// within a dictionary only strings and streams have to be decrypted
- if (!(value instanceof COSString) && !(value instanceof COSStream))
- continue;
- //if we are a signature dictionary and contain a Contents entry then
- //we don't decrypt it.
- if( !(entry.getKey().getName().equals( "Contents" ) &&
- value instanceof COSString &&
- potentialSignatures.contains( dictionary )))
+ if (value instanceof COSString || value instanceof COSStream || value instanceof COSArray)
{
- decrypt( entry.getValue(), objNum, genNum );
+ // if we are a signature dictionary and contain a Contents entry then
+ // we don't decrypt it.
+ if (!(entry.getKey().getName().equals("Contents") && value instanceof COSString && potentialSignatures
+ .contains(dictionary)))
+ {
+ decrypt(entry.getValue(), objNum, genNum);
+ }
}
}
}
@@ -477,14 +471,13 @@ public abstract class SecurityHandler
* @throws CryptographyException If an error occurs during decryption.
* @throws IOException If an error occurs writing the new string.
*/
- public void decryptString( COSString string, long objNum, long genNum )
- throws CryptographyException, IOException
+ public void decryptString(COSString string, long objNum, long genNum) throws CryptographyException, IOException
{
- ByteArrayInputStream data = new ByteArrayInputStream( string.getBytes() );
+ ByteArrayInputStream data = new ByteArrayInputStream(string.getBytes());
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- encryptData( objNum, genNum, data, buffer, true /* decrypt */ );
+ encryptData(objNum, genNum, data, buffer, true /* decrypt */);
string.reset();
- string.append( buffer.toByteArray() );
+ string.append(buffer.toByteArray());
}
/**
@@ -497,12 +490,11 @@ public abstract class SecurityHandler
* @throws CryptographyException If an error occurs during decryption.
* @throws IOException If there is an error accessing the data.
*/
- private void decryptArray( COSArray array, long objNum, long genNum )
- throws CryptographyException, IOException
+ private void decryptArray(COSArray array, long objNum, long genNum) throws CryptographyException, IOException
{
- for( int i=0; i<array.size(); i++ )
+ for (int i = 0; i < array.size(); i++)
{
- decrypt( array.get( i ), objNum, genNum );
+ decrypt(array.get(i), objNum, genNum);
}
}
@@ -537,17 +529,24 @@ public abstract class SecurityHandler
return currentAccessPermission;
}
- /*
+ /**
* True if AES is used for encryption and decryption.
+ *
+ * @return true if AEs is used
*/
- public boolean isAES() {
+ public boolean isAES()
+ {
return aes;
}
- /*
+ /**
* Set to true if AES for encryption and decryption should be used.
+ *
+ * @param aes if true AES will be used
+ *
*/
- public void setAES(boolean aes) {
- this.aes = aes;
+ public void setAES(boolean aesValue)
+ {
+ aes = aesValue;
}
}