소스 검색

Bugfix: Some string objects were not encrypted (for example in named destinations)

I had to refactor the PDF library a little bit but since it only affects the inner API it shouldn't be a problem that I removed some methods which caused trouble because a didn't think about encryption when I worked on the PDF library last year.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@611114 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_95beta
Jeremias Maerki 16 년 전
부모
커밋
db4f3b282c

+ 15
- 26
src/java/org/apache/fop/pdf/AbstractPDFStream.java 파일 보기

@@ -21,8 +21,10 @@ package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

import org.apache.commons.io.output.CountingOutputStream;

import org.apache.fop.util.CloseBlockerOutputStream;

/**
@@ -169,8 +171,12 @@ public abstract class AbstractPDFStream extends PDFDictionary {
* {@inheritDoc}
*/
protected int output(OutputStream stream) throws IOException {
int length = 0;
setupFilterList();

CountingOutputStream cout = new CountingOutputStream(stream);
Writer writer = PDFDocument.getWriterFor(cout);
writer.write(getObjectID());
//int length = 0;
StreamCache encodedStream = null;
PDFNumber refLength = null;
@@ -184,38 +190,21 @@ public abstract class AbstractPDFStream extends PDFDictionary {
lengthEntry = new Integer(encodedStream.getSize() + 1);
}
byte[] p = encode(buildStreamDict(lengthEntry));
stream.write(p);
length += p.length;
populateStreamDict(lengthEntry);
writeDictionary(cout, writer);
//Send encoded stream to target OutputStream
writer.flush();
if (encodedStream == null) {
int bytesWritten = encodeAndWriteStream(stream, refLength);
length += bytesWritten;
encodeAndWriteStream(cout, refLength);
} else {
length += outputStreamData(encodedStream, stream);
outputStreamData(encodedStream, cout);
encodedStream.clear(); //Encoded stream can now be discarded
}
p = encode("\nendobj\n");
stream.write(p);
length += p.length;
return length;
}

/**
* Constructs the dictionary for the stream. Override this method if you
* need additional entries.
* @param lengthEntry value for the /Length entry
* @return the newly constructed dictionary
*/
protected String buildStreamDict(Object lengthEntry) {
StringBuffer sb = new StringBuffer();
sb.append(getObjectID());
populateStreamDict(lengthEntry);
writeDictionary(sb);
return sb.toString();
writer.write("\nendobj\n");
writer.flush();
return cout.getCount();
}

/**

+ 0
- 9
src/java/org/apache/fop/pdf/BitmapImage.java 파일 보기

@@ -163,15 +163,6 @@ public class BitmapImage implements PDFImage {
return null;
}

/**
* Get the soft mask reference for this image.
*
* @return the soft mask reference if any
*/
public String getSoftMask() {
return maskRef.toInlinePDFString();
}
/** {@inheritDoc} */
public PDFReference getSoftMaskReference() {
return maskRef;

+ 46
- 26
src/java/org/apache/fop/pdf/PDFArray.java 파일 보기

@@ -19,9 +19,14 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Collection;
import java.util.List;

import org.apache.commons.io.output.CountingOutputStream;

/**
* Class representing an array object.
*/
@@ -33,20 +38,21 @@ public class PDFArray extends PDFObject {

/**
* Create a new, empty array object
* @param parent the array's parent if any
*/
public PDFArray() {
public PDFArray(PDFObject parent) {
/* generic creation of PDF object */
super();
super(parent);
}

/**
* Create the array object
*
* Create an array object.
* @param parent the array's parent if any
* @param values the actual array wrapped by this object
*/
public PDFArray(int[] values) {
public PDFArray(PDFObject parent, int[] values) {
/* generic creation of PDF object */
super();
super(parent);

for (int i = 0, c = values.length; i < c; i++) {
this.values.add(new Integer(values[i]));
@@ -54,25 +60,25 @@ public class PDFArray extends PDFObject {
}

/**
* Create the array object
*
* Create an array object.
* @param parent the array's parent if any
* @param values the actual values wrapped by this object
*/
public PDFArray(Collection values) {
public PDFArray(PDFObject parent, Collection values) {
/* generic creation of PDF object */
super();
super(parent);
this.values.addAll(values);
}
/**
* Create the array object
*
* @param parent the array's parent if any
* @param values the actual array wrapped by this object
*/
public PDFArray(Object[] values) {
public PDFArray(PDFObject parent, Object[] values) {
/* generic creation of PDF object */
super();
super(parent);
for (int i = 0, c = values.length; i < c; i++) {
this.values.add(values[i]);
@@ -114,6 +120,17 @@ public class PDFArray extends PDFObject {
return this.values.get(index);
}
/**
* Adds a new value to the array.
* @param obj the value
*/
public void add(PDFObject obj) {
if (obj != null) {
obj.setParent(this);
}
this.values.add(obj);
}
/**
* Adds a new value to the array.
* @param obj the value
@@ -130,27 +147,30 @@ public class PDFArray extends PDFObject {
this.values.add(new Double(value));
}
/**
* {@inheritDoc}
*/
public String toPDFString() {
StringBuffer p = new StringBuffer(64);
/** {@inheritDoc} */
protected int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
Writer writer = PDFDocument.getWriterFor(cout);
if (hasObjectNumber()) {
p.append(getObjectID());
writer.write(getObjectID());
}
p.append("[");
writer.write('[');
for (int i = 0; i < values.size(); i++) {
if (i > 0) {
p.append(" ");
writer.write(' ');
}
Object obj = this.values.get(i);
formatObject(obj, p);
formatObject(obj, cout, writer);
}
p.append("]");
writer.write(']');
if (hasObjectNumber()) {
p.append("\nendobj\n");
writer.write("\nendobj\n");
}
return p.toString();
writer.flush();
return cout.getCount();
}

}

+ 19
- 21
src/java/org/apache/fop/pdf/PDFDestination.java 파일 보기

@@ -19,6 +19,12 @@

package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

import org.apache.commons.io.output.CountingOutputStream;

/**
* class representing a named destination
*/
@@ -40,30 +46,24 @@ public class PDFDestination extends PDFObject {
* @param goToRef Object reference to the GoTo Action
*/
public PDFDestination(String idRef, Object goToRef) {
super();
this.goToReference = goToRef;
this.idRef = idRef;
}

/**
* Creates the key/value pair for this destination entry for the name tree.
* @return the formatted key/value pair
*/
public String toKeyValuePair() {
StringBuffer sb = new StringBuffer();
sb.append("(").append(getIDRef()).append(") ");
if (goToReference instanceof PDFWritable) {
sb.append(((PDFWritable)goToReference).toInlinePDFString());
} else {
sb.append(goToReference);
}
return sb.toString();
}
/** {@inheritDoc} */
protected String toPDFString() {
return toKeyValuePair();
protected int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
Writer writer = PDFDocument.getWriterFor(cout);
formatObject(getIDRef(), cout, writer);
writer.write(' ');
formatObject(goToReference, cout, writer);
writer.flush();
return cout.getCount();
}

/**
* Sets the GoToReference in the associated DestinationData object.
*
@@ -124,9 +124,7 @@ public class PDFDestination extends PDFObject {
return false;
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public int hashCode() {
return getIDRef().hashCode();
}

+ 1
- 1
src/java/org/apache/fop/pdf/PDFDests.java 파일 보기

@@ -40,7 +40,7 @@ public class PDFDests extends PDFNameTreeNode {
*/
public PDFDests(List destinationList) {
this();
setNames(new PDFArray(destinationList));
setNames(new PDFArray(this, destinationList));
}

}

+ 41
- 23
src/java/org/apache/fop/pdf/PDFDictionary.java 파일 보기

@@ -19,10 +19,15 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.output.CountingOutputStream;

/**
* Class representing a PDF dictionary object
*/
@@ -40,13 +45,20 @@ public class PDFDictionary extends PDFObject {
protected List order = new java.util.ArrayList();
/**
* Create the dictionary object
* Create a new dictionary object.
*/
public PDFDictionary() {
/* generic creation of PDF object */
super();
}

/**
* Create a new dictionary object.
* @param parent the object's parent if any
*/
public PDFDictionary(PDFObject parent) {
super(parent);
}

/**
* Puts a new name/value pair.
* @param name the name
@@ -80,47 +92,53 @@ public class PDFDictionary extends PDFObject {
return this.entries.get(name);
}
/**
* {@inheritDoc}
*/
public String toPDFString() {
StringBuffer p = new StringBuffer(64);
/** {@inheritDoc} */
protected int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
Writer writer = PDFDocument.getWriterFor(cout);
if (hasObjectNumber()) {
p.append(getObjectID());
writer.write(getObjectID());
}
writeDictionary(p);
writeDictionary(cout, writer);

if (hasObjectNumber()) {
p.append("endobj\n");
writer.write("\nendobj\n");
}
return p.toString();
writer.flush();
return cout.getCount();
}

/**
* Writes the contents of the dictionary to a StringBuffer.
* @param sb the target StringBuffer
* @param out the OutputStream (for binary content)
* @param writer the Writer (for text content, wraps the above OutputStream)
* @throws IOException if an I/O error occurs
*/
protected void writeDictionary(StringBuffer sb) {
sb.append("<<");
protected void writeDictionary(OutputStream out, Writer writer) throws IOException {
writer.write("<<");
boolean compact = (this.order.size() <= 2);
Iterator iter = this.order.iterator();
while (iter.hasNext()) {
String key = (String)iter.next();
if (compact) {
sb.append(' ');
writer.write(' ');
} else {
sb.append("\n ");
writer.write("\n ");
}
sb.append('/').append(key);
sb.append(' ');
writer.write('/');
writer.write(key);
writer.write(' ');
Object obj = this.entries.get(key);
formatObject(obj, sb);
formatObject(obj, out, writer);
}
if (compact) {
sb.append(' ');
writer.write(' ');
} else {
sb.append('\n');
writer.write('\n');
}
sb.append(">>\n");
writer.write(">>\n");
}

}

+ 18
- 1
src/java/org/apache/fop/pdf/PDFDocument.java 파일 보기

@@ -24,15 +24,16 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Iterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -316,6 +317,22 @@ public class PDFDocument {
}
}

/**
* Creates and returns a Writer object wrapping the given OutputStream. The Writer is
* buffered to reduce the number of calls to the encoding converter so don't forget
* to <code>flush()</code> the Writer after use or before writing directly to the
* underlying OutputStream.
* @param out the OutputStream to write to
* @return the requested Writer
*/
public static Writer getWriterFor(OutputStream out) {
try {
return new java.io.BufferedWriter(new java.io.OutputStreamWriter(out, ENCODING));
} catch (UnsupportedEncodingException uee) {
throw new Error("JVM doesn't support " + ENCODING + " encoding!");
}
}
/**
* set the producer of the document
*

+ 15
- 12
src/java/org/apache/fop/pdf/PDFEncryptionJCE.java 파일 보기

@@ -20,20 +20,20 @@
package org.apache.fop.pdf;

// Java
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.BadPaddingException;
import javax.crypto.NoSuchPaddingException;

import java.util.Random;
import javax.crypto.spec.SecretKeySpec;

/**
* class representing a /Filter /Standard object.
@@ -358,17 +358,20 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
if (this.encryptionKey == null) {
throw new IllegalStateException("PDF Encryption has not been initialized");
}
log.debug("encrypting with for " + number + " " + generation);

byte[] hash = calcHash(number, generation);
return encryptWithHash(data, hash, hash.length);
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public byte[] encrypt(byte[] data, PDFObject refObj) {
return encryptData(data, refObj.getObjectNumber(), refObj.getGeneration());
PDFObject o = refObj;
while (o != null && !o.hasObjectNumber()) {
o = o.getParent();
}
if (o == null) {
throw new IllegalStateException("No object number could be obtained for a PDF object");
}
return encryptData(data, o.getObjectNumber(), o.getGeneration());
}

private byte[] calcHash(int number, int generation) {

+ 8
- 5
src/java/org/apache/fop/pdf/PDFFactory.java 파일 보기

@@ -39,6 +39,9 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.xmp.Metadata;

import org.apache.fop.fonts.CIDFont;
import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.FontDescriptor;
@@ -51,7 +54,6 @@ import org.apache.fop.fonts.truetype.FontFileReader;
import org.apache.fop.fonts.truetype.TTFSubSetFile;
import org.apache.fop.fonts.type1.PFBData;
import org.apache.fop.fonts.type1.PFBParser;
import org.apache.xmlgraphics.xmp.Metadata;

/**
* This class provides method to create and register PDF objects.
@@ -872,7 +874,7 @@ public class PDFFactory {
//true for a "deep" structure (one node per entry), true for a "flat" structure
if (deep) {
dests = new PDFDests();
PDFArray kids = new PDFArray();
PDFArray kids = new PDFArray(dests);
Iterator iter = destinationList.iterator();
while (iter.hasNext()) {
PDFDestination dest = (PDFDestination)iter.next();
@@ -880,8 +882,9 @@ public class PDFFactory {
getDocument().registerObject(node);
node.setLowerLimit(dest.getIDRef());
node.setUpperLimit(dest.getIDRef());
node.setNames(new PDFArray());
node.getNames().add(dest);
node.setNames(new PDFArray(node));
PDFArray names = node.getNames();
names.add(dest);
kids.add(node);
}
dests.setLowerLimit(((PDFNameTreeNode)kids.get(0)).getLowerLimit());
@@ -1527,7 +1530,7 @@ public class PDFFactory {
* @return the PDF Array with the int values
*/
public PDFArray makeArray(int[] values) {
PDFArray array = new PDFArray(values);
PDFArray array = new PDFArray(null, values);

getDocument().registerObject(array);
return array;

+ 2
- 2
src/java/org/apache/fop/pdf/PDFFilterList.java 파일 보기

@@ -277,7 +277,7 @@ public class PDFFilterList {
}

private void putFilterEntries(PDFDictionary dict, List names) {
PDFArray array = new PDFArray();
PDFArray array = new PDFArray(dict);
for (int i = 0, c = names.size(); i < c; i++) {
final String name = (String)names.get(i);
if (name.length() > 0) {
@@ -323,7 +323,7 @@ public class PDFFilterList {

private void putDecodeParams(PDFDictionary dict, List parms) {
boolean needParmsEntry = false;
PDFArray array = new PDFArray();
PDFArray array = new PDFArray(dict);
for (int i = 0, c = parms.size(); i < c; i++) {
Object obj = parms.get(i);
if (obj != null) {

+ 3
- 3
src/java/org/apache/fop/pdf/PDFFormXObject.java 파일 보기

@@ -63,7 +63,7 @@ public class PDFFormXObject extends PDFXObject {
public void setBBox(Rectangle2D bbox) {
PDFArray array = (PDFArray)get("BBox");
if (array == null) {
array = new PDFArray();
array = new PDFArray(this);
array.add(bbox.getX());
array.add(bbox.getY());
array.add(bbox.getWidth());
@@ -105,7 +105,7 @@ public class PDFFormXObject extends PDFXObject {
double[] m = new double[6];
at.getMatrix(m);
if (array == null) {
array = new PDFArray();
array = new PDFArray(this);
array.add(m[0]);
array.add(m[1]);
array.add(m[2]);
@@ -170,7 +170,7 @@ public class PDFFormXObject extends PDFXObject {
/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
if (get("Matrix") == null) {
put("Matrix", new PDFArray(new int[] {1, 0, 0, 1, 0, 0}));
put("Matrix", new PDFArray(this, new int[] {1, 0, 0, 1, 0, 0}));
}
put("Resources", resRef);
super.populateStreamDict(lengthEntry);

+ 1
- 4
src/java/org/apache/fop/pdf/PDFImage.java 파일 보기

@@ -105,11 +105,8 @@ public interface PDFImage {

/**
* Get the PDF reference for a soft mask.
*
* @return the PDF reference for a soft mask image
* @return the PDF reference for a soft mask image (or null if there's no soft mask)
*/
String getSoftMask();
PDFReference getSoftMaskReference();

/** @return true for CMYK images generated by Adobe Photoshop */

+ 4
- 3
src/java/org/apache/fop/pdf/PDFImageXObject.java 파일 보기

@@ -94,7 +94,8 @@ public class PDFImageXObject extends PDFXObject {

PDFICCStream pdfICCStream = pdfimage.getICCStream();
if (pdfICCStream != null) {
put("ColorSpace", new PDFArray(new Object[] {new PDFName("ICCBased"), pdfICCStream}));
put("ColorSpace", new PDFArray(this,
new Object[] {new PDFName("ICCBased"), pdfICCStream}));
} else {
PDFDeviceColorSpace cs = pdfimage.getColorSpace();
put("ColorSpace", new PDFName(cs.getName()));
@@ -107,7 +108,7 @@ public class PDFImageXObject extends PDFXObject {
*/
final Float zero = new Float(0.0f);
final Float one = new Float(1.0f);
PDFArray decode = new PDFArray();
PDFArray decode = new PDFArray(this);
for (int i = 0, c = pdfimage.getColorSpace().getNumComponents(); i < c; i++) {
decode.add(one);
decode.add(zero);
@@ -117,7 +118,7 @@ public class PDFImageXObject extends PDFXObject {

if (pdfimage.isTransparent()) {
PDFColor transp = pdfimage.getTransparentColor();
PDFArray mask = new PDFArray();
PDFArray mask = new PDFArray(this);
mask.add(new Integer(transp.red255()));
mask.add(new Integer(transp.red255()));
mask.add(new Integer(transp.green255()));

+ 8
- 5
src/java/org/apache/fop/pdf/PDFName.java 파일 보기

@@ -19,6 +19,10 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

/**
* Class representing a PDF name object.
*/
@@ -65,15 +69,14 @@ public class PDFName implements PDFWritable {
sb.append(DIGITS[ch & 0x0F]);
}
/** {@inheritDoc} */
public String toInlinePDFString() {
public String toString() {
return this.name;
}
/** {@inheritDoc} */
public String toString() {
return toInlinePDFString();
public void outputInline(OutputStream out, Writer writer) throws IOException {
writer.write(toString());
}
}

+ 1
- 1
src/java/org/apache/fop/pdf/PDFNameTreeNode.java 파일 보기

@@ -108,7 +108,7 @@ public class PDFNameTreeNode extends PDFDictionary {
private PDFArray prepareLimitsArray() {
PDFArray limits = (PDFArray)get(LIMITS);
if (limits == null) {
limits = new PDFArray(new Object[2]);
limits = new PDFArray(this, new Object[2]);
put(LIMITS, limits);
}
if (limits.length() != 2) {

+ 7
- 3
src/java/org/apache/fop/pdf/PDFNull.java 파일 보기

@@ -19,6 +19,10 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

/**
* Class representing a PDF name object.
*/
@@ -35,13 +39,13 @@ public final class PDFNull implements PDFWritable {
}

/** {@inheritDoc} */
public String toInlinePDFString() {
public String toString() {
return "null";
}
/** {@inheritDoc} */
public String toString() {
return toInlinePDFString();
public void outputInline(OutputStream out, Writer writer) throws IOException {
writer.write(toString());
}
}

+ 121
- 121
src/java/org/apache/fop/pdf/PDFNumberTreeNode.java 파일 보기

@@ -1,121 +1,121 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id$ */
package org.apache.fop.pdf;
/**
* Class representing a PDF number tree node.
*/
public class PDFNumberTreeNode extends PDFDictionary {
private static final String KIDS = "Kids";
private static final String NUMS = "Nums";
private static final String LIMITS = "Limits";
/**
* create a named destination
*/
public PDFNumberTreeNode() {
/* generic creation of PDF object */
super();
}
/**
* Sets the Kids array.
* @param kids the Kids array
*/
public void setKids(PDFArray kids) {
put(KIDS, kids);
}
/**
* Returns the Kids array.
* @return the Kids array
*/
public PDFArray getKids() {
return (PDFArray)get(KIDS);
}
/**
* Sets the Nums array.
* @param nums the Nums array
*/
public void setNums(PDFNumsArray nums) {
put(NUMS, nums);
}
/**
* Returns the Nums array.
* @return the Nums array
*/
public PDFNumsArray getNums() {
return (PDFNumsArray)get(NUMS);
}
/**
* Sets the lower limit value of the Limits array.
* @param key the lower limit value
*/
public void setLowerLimit(Integer key) {
PDFArray limits = prepareLimitsArray();
limits.set(0, key);
}
/**
* Returns the lower limit value of the Limits array.
* @return the lower limit value
*/
public Integer getLowerLimit() {
PDFArray limits = prepareLimitsArray();
return (Integer)limits.get(0);
}
/**
* Sets the upper limit value of the Limits array.
* @param key the upper limit value
*/
public void setUpperLimit(Integer key) {
PDFArray limits = prepareLimitsArray();
limits.set(1, key);
}
/**
* Returns the upper limit value of the Limits array.
* @return the upper limit value
*/
public Integer getUpperLimit() {
PDFArray limits = prepareLimitsArray();
return (Integer)limits.get(1);
}
private PDFArray prepareLimitsArray() {
PDFArray limits = (PDFArray)get(LIMITS);
if (limits == null) {
limits = new PDFArray(new Object[2]);
put(LIMITS, limits);
}
if (limits.length() != 2) {
throw new IllegalStateException("Limits array must have 2 entries");
}
return limits;
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id$ */
package org.apache.fop.pdf;
/**
* Class representing a PDF number tree node.
*/
public class PDFNumberTreeNode extends PDFDictionary {
private static final String KIDS = "Kids";
private static final String NUMS = "Nums";
private static final String LIMITS = "Limits";
/**
* create a named destination
*/
public PDFNumberTreeNode() {
/* generic creation of PDF object */
super();
}
/**
* Sets the Kids array.
* @param kids the Kids array
*/
public void setKids(PDFArray kids) {
put(KIDS, kids);
}
/**
* Returns the Kids array.
* @return the Kids array
*/
public PDFArray getKids() {
return (PDFArray)get(KIDS);
}
/**
* Sets the Nums array.
* @param nums the Nums array
*/
public void setNums(PDFNumsArray nums) {
put(NUMS, nums);
}
/**
* Returns the Nums array.
* @return the Nums array
*/
public PDFNumsArray getNums() {
return (PDFNumsArray)get(NUMS);
}
/**
* Sets the lower limit value of the Limits array.
* @param key the lower limit value
*/
public void setLowerLimit(Integer key) {
PDFArray limits = prepareLimitsArray();
limits.set(0, key);
}
/**
* Returns the lower limit value of the Limits array.
* @return the lower limit value
*/
public Integer getLowerLimit() {
PDFArray limits = prepareLimitsArray();
return (Integer)limits.get(0);
}
/**
* Sets the upper limit value of the Limits array.
* @param key the upper limit value
*/
public void setUpperLimit(Integer key) {
PDFArray limits = prepareLimitsArray();
limits.set(1, key);
}
/**
* Returns the upper limit value of the Limits array.
* @return the upper limit value
*/
public Integer getUpperLimit() {
PDFArray limits = prepareLimitsArray();
return (Integer)limits.get(1);
}
private PDFArray prepareLimitsArray() {
PDFArray limits = (PDFArray)get(LIMITS);
if (limits == null) {
limits = new PDFArray(this, new Object[2]);
put(LIMITS, limits);
}
if (limits.length() != 2) {
throw new IllegalStateException("Limits array must have 2 entries");
}
return limits;
}
}

+ 104
- 94
src/java/org/apache/fop/pdf/PDFNumsArray.java 파일 보기

@@ -1,94 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id: PDFArray.java 588547 2007-10-26 07:48:14Z jeremias $ */
package org.apache.fop.pdf;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
/**
* Class representing an "Nums" array object (for Number Trees).
*/
public class PDFNumsArray extends PDFObject {
/** Sorted Map holding the values of this array. */
protected SortedMap map = new java.util.TreeMap();
/**
* Create a new, empty array object
*/
public PDFNumsArray() {
/* generic creation of PDF object */
super();
}
/**
* Returns the length of the array
* @return the length of the array
*/
public int length() {
return this.map.size();
}
/**
* Sets an entry.
* @param key the key of the value to set
* @param obj the new value
*/
public void put(int key, Object obj) {
this.map.put(new Integer(key), obj);
}
/**
* Gets an entry.
* @param key the key of requested value
* @return the requested value
*/
public Object get(int key) {
return this.map.get(new Integer(key));
}
/** {@inheritDoc} */
public String toPDFString() {
StringBuffer p = new StringBuffer(64);
if (hasObjectNumber()) {
p.append(getObjectID());
}
p.append("[");
boolean first = true;
Iterator iter = this.map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
if (!first) {
p.append(" ");
}
first = false;
formatObject(entry.getKey(), p);
p.append(" ");
formatObject(entry.getValue(), p);
}
p.append("]");
if (hasObjectNumber()) {
p.append("\nendobj\n");
}
return p.toString();
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;

import org.apache.commons.io.output.CountingOutputStream;

/**
* Class representing an "Nums" array object (for Number Trees).
*/
public class PDFNumsArray extends PDFObject {
/** Sorted Map holding the values of this array. */
protected SortedMap map = new java.util.TreeMap();

/**
* Create a new, empty array object.
* @param parent the object's parent if any
*/
public PDFNumsArray(PDFObject parent) {
super(parent);
}

/**
* Returns the length of the array
* @return the length of the array
*/
public int length() {
return this.map.size();
}
/**
* Sets an entry.
* @param key the key of the value to set
* @param obj the new value
*/
public void put(int key, Object obj) {
this.map.put(new Integer(key), obj);
}
/**
* Gets an entry.
* @param key the key of requested value
* @return the requested value
*/
public Object get(int key) {
return this.map.get(new Integer(key));
}
/** {@inheritDoc} */
protected int output(OutputStream stream) throws IOException {
CountingOutputStream cout = new CountingOutputStream(stream);
Writer writer = PDFDocument.getWriterFor(cout);
if (hasObjectNumber()) {
writer.write(getObjectID());
}
writer.write('[');
boolean first = true;
Iterator iter = this.map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
if (!first) {
writer.write(" ");
}
first = false;
formatObject(entry.getKey(), cout, writer);
writer.write(" ");
formatObject(entry.getValue(), cout, writer);
}
writer.write(']');
if (hasObjectNumber()) {
writer.write("\nendobj\n");
}
writer.flush();
return cout.getCount();
}
}

+ 67
- 24
src/java/org/apache/fop/pdf/PDFObject.java 파일 보기

@@ -22,6 +22,7 @@ package org.apache.fop.pdf;
// Java
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
@@ -57,6 +58,9 @@ public abstract class PDFObject implements PDFWritable {
*/
private PDFDocument document;

/** the parent PDFObject (may be null and may not always be set, needed for encryption) */
private PDFObject parent;
/**
* Returns the object's number.
* @return the PDF Object number
@@ -68,6 +72,21 @@ public abstract class PDFObject implements PDFWritable {
return this.objnum;
}
/**
* Default constructor.
*/
public PDFObject() {
//nop
}
/**
* Constructor for direct objects.
* @param parent the containing PDFObject instance
*/
public PDFObject(PDFObject parent) {
setParent(parent);
}
/**
* Indicates whether this PDFObject has already been assigned an
* object number.
@@ -102,7 +121,13 @@ public abstract class PDFObject implements PDFWritable {
* has not been assigned)
*/
public final PDFDocument getDocument() {
return this.document;
if (this.document != null) {
return this.document;
} else if (getParent() != null) {
return getParent().getDocument();
} else {
return null;
}
}

/**
@@ -127,6 +152,22 @@ public abstract class PDFObject implements PDFWritable {
this.document = doc;
}

/**
* Returns this objects's parent. The parent is null if it is a "direct object".
* @return the parent or null if there's no parent (or it hasn't been set)
*/
public PDFObject getParent() {
return this.parent;
}
/**
* Sets the direct parent object.
* @param parent the direct parent
*/
public void setParent(PDFObject parent) {
this.parent = parent;
}

/**
* Returns the PDF representation of the Object ID.
* @return the Object ID
@@ -169,6 +210,16 @@ public abstract class PDFObject implements PDFWritable {
return pdf.length;
}

/** {@inheritDoc} */
public void outputInline(OutputStream out, Writer writer) throws IOException {
if (hasObjectNumber()) {
writer.write(referencePDF());
} else {
writer.flush();
output(out);
}
}
/**
* Encodes the object as a byte array for output to a PDF file.
*
@@ -184,7 +235,9 @@ public abstract class PDFObject implements PDFWritable {
* is normally converted/encoded to a byte array by toPDF(). Only use
* this method to implement the serialization if the object can be fully
* represented as text. If the PDF representation of the object contains
* binary content use toPDF() or output(OutputStream) instead.
* binary content use toPDF() or output(OutputStream) instead. This applies
* to any object potentially containing a string object because string object
* are encrypted and therefore need to be binary.
* @return String the String representation
*/
protected String toPDFString() {
@@ -192,20 +245,6 @@ public abstract class PDFObject implements PDFWritable {
+ "Use output(OutputStream) instead.");
}
/**
* Returns a representation of this object for in-object placement, i.e. if the object
* has an object number its reference is returned. Otherwise, its PDF representation is
* returned.
* @return the String representation
*/
public String toInlinePDFString() {
if (hasObjectNumber()) {
return referencePDF();
} else {
return toPDFString();
}
}
/**
* Converts text to a byte array for writing to a PDF file.
* @param text text to convert/encode
@@ -250,23 +289,27 @@ public abstract class PDFObject implements PDFWritable {
/**
* Formats an object for serialization to PDF.
* @param obj the object
* @param sb the StringBuffer to write to
* @param out the OutputStream to write to
* @param writer a Writer for text content (will always be a wrapper around the above
* OutputStream. Make sure <code>flush</code> is called when mixing calls)
* @throws IOException If an I/O error occurs
*/
protected void formatObject(Object obj, StringBuffer sb) {
protected void formatObject(Object obj, OutputStream out, Writer writer) throws IOException {
if (obj == null) {
sb.append("null");
writer.write("null");
} else if (obj instanceof PDFWritable) {
sb.append(((PDFWritable)obj).toInlinePDFString());
((PDFWritable)obj).outputInline(out, writer);
} else if (obj instanceof Number) {
if (obj instanceof Double || obj instanceof Float) {
sb.append(PDFNumber.doubleOut(((Number)obj).doubleValue()));
writer.write(PDFNumber.doubleOut(((Number)obj).doubleValue()));
} else {
sb.append(obj);
writer.write(obj.toString());
}
} else if (obj instanceof Boolean) {
sb.append(obj);
writer.write(obj.toString());
} else {
sb.append("(").append(obj).append(")");
writer.flush();
out.write(encodeText(obj.toString()));
}
}

+ 48
- 48
src/java/org/apache/fop/pdf/PDFPageLabels.java 파일 보기

@@ -1,48 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id$ */
package org.apache.fop.pdf;
/**
* Class representing a PDF /PageLabels dictionary.
*/
public class PDFPageLabels extends PDFNumberTreeNode {
/**
* Create the /PageLabels dictionary
*/
public PDFPageLabels() {
super();
}
/**
* Returns the Nums object
* @return the Nums object (an empty PDFNumsArray for the "/Nums" entry is created
* if it doesn't exist)
*/
public PDFNumsArray getNums() {
PDFNumsArray nums = super.getNums();
if (nums == null) {
nums = new PDFNumsArray();
setNums(nums);
}
return nums;
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id$ */
package org.apache.fop.pdf;
/**
* Class representing a PDF /PageLabels dictionary.
*/
public class PDFPageLabels extends PDFNumberTreeNode {
/**
* Create the /PageLabels dictionary
*/
public PDFPageLabels() {
super();
}
/**
* Returns the Nums object
* @return the Nums object (an empty PDFNumsArray for the "/Nums" entry is created
* if it doesn't exist)
*/
public PDFNumsArray getNums() {
PDFNumsArray nums = super.getNums();
if (nums == null) {
nums = new PDFNumsArray(this);
setNums(nums);
}
return nums;
}
}

+ 6
- 3
src/java/org/apache/fop/pdf/PDFReference.java 파일 보기

@@ -19,6 +19,9 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;

@@ -68,13 +71,13 @@ public class PDFReference implements PDFWritable {
}
/** {@inheritDoc} */
public String toInlinePDFString() {
public String toString() {
return this.indirectReference;
}
/** {@inheritDoc} */
public String toString() {
return toInlinePDFString();
public void outputInline(OutputStream out, Writer writer) throws IOException {
writer.write(toString());
}
}

+ 1
- 1
src/java/org/apache/fop/pdf/PDFRoot.java 파일 보기

@@ -225,7 +225,7 @@ public class PDFRoot extends PDFDictionary {
if (getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
PDFArray outputIntents = getOutputIntents();
if (outputIntents == null) {
outputIntents = new PDFArray();
outputIntents = new PDFArray(this);
put("OutputIntents", outputIntents);
}
outputIntents.add(outputIntent);

+ 11
- 5
src/java/org/apache/fop/pdf/PDFWritable.java 파일 보기

@@ -19,6 +19,10 @@
package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;

/**
* This interface is implemented by classes that can be serialized to a PDF file either by
* serializing the object or by writing a indirect reference to the actual object.
@@ -26,11 +30,13 @@ package org.apache.fop.pdf;
public interface PDFWritable {
/**
* Returns a representation of this object for in-object placement, i.e. if the object
* has an object number its reference is returned. Otherwise, its PDF representation is
* returned.
* @return the String representation
* Writes a "direct object" (inline object) representation to the stream. A Writer is given
* for optimized encoding of text content. Since the Writer is buffered, make sure
* <code>flush()</code> is called before any direct calls to <code>out</code> are made.
* @param out the OutputStream (for binary content)
* @param writer the Writer (for text content, wraps the above OutputStream)
* @throws IOException if an I/O error occurs
*/
String toInlinePDFString();
void outputInline(OutputStream out, Writer writer) throws IOException;
}

+ 1
- 5
src/java/org/apache/fop/render/pdf/FopPDFImage.java 파일 보기

@@ -25,6 +25,7 @@ import java.io.OutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.image.EPSImage;
import org.apache.fop.image.FopImage;
import org.apache.fop.image.TIFFImage;
@@ -237,11 +238,6 @@ public class FopPDFImage implements PDFImage {
return maskRef;
}

/** {@inheritDoc} */
public String getSoftMask() {
return softMask.toInlinePDFString();
}

/** {@inheritDoc} */
public PDFReference getSoftMaskReference() {
return softMask;

+ 13
- 7
src/java/org/apache/fop/render/pdf/PDFRenderer.java 파일 보기

@@ -37,7 +37,15 @@ import java.util.Map;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.CountingOutputStream;

import org.apache.xmlgraphics.xmp.Metadata;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
@@ -86,6 +94,7 @@ import org.apache.fop.pdf.PDFInfo;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFMetadata;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFNumsArray;
import org.apache.fop.pdf.PDFOutline;
import org.apache.fop.pdf.PDFOutputIntent;
import org.apache.fop.pdf.PDFPage;
@@ -102,10 +111,6 @@ import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.RendererContext;
import org.apache.fop.util.CharUtilities;
import org.apache.fop.util.ColorProfileUtil;
import org.apache.xmlgraphics.xmp.Metadata;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
import org.w3c.dom.Document;

/**
* Renderer that renders areas to PDF.
@@ -357,7 +362,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
this.pdfDoc.getInfo().setTitle(userAgent.getTitle());
this.pdfDoc.getInfo().setKeywords(userAgent.getKeywords());
this.pdfDoc.setFilterMap(filterMap);
this.pdfDoc.outputHeader(stream);
this.pdfDoc.outputHeader(ostream);

//Setup encryption if necessary
PDFEncryptionManager.setupPDFEncryption(encryptionParams, this.pdfDoc);
@@ -725,11 +730,12 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
pageLabels = this.pdfDoc.getFactory().makePageLabels();
this.pdfDoc.getRoot().setPageLabels(pageLabels);
}
PDFDictionary dict = new PDFDictionary();
PDFNumsArray nums = pageLabels.getNums();
PDFDictionary dict = new PDFDictionary(nums);
dict.put("P", page.getPageNumberString());
//TODO If the sequence of generated page numbers were inspected, this could be
//expressed in a more space-efficient way
pageLabels.getNums().put(page.getPageIndex(), dict);
nums.put(page.getPageIndex(), dict);
}
/**

+ 3
- 0
status.xml 파일 보기

@@ -28,6 +28,9 @@

<changes>
<release version="FOP Trunk">
<action context="Code" dev="JM" type="fix">
Fixed generation of named destinations so it works when the PDF document is encrypted.
</action>
<action context="Code" dev="JM" type="add">
PostScript output now generates the bounding box DSC comments for the whole document.
</action>

Loading…
취소
저장