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;
     }
 }