de.intarsys.pdf.cos.COSStream Maven / Gradle / Ivy
/*
* Copyright (c) 2007, intarsys consulting GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of intarsys nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package de.intarsys.pdf.cos;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import de.intarsys.pdf.filter.FilterFactory;
import de.intarsys.pdf.filter.IFilter;
import de.intarsys.tools.collection.SingleObjectIterator;
import de.intarsys.tools.file.FileTools;
/**
* An object representing stream data in a PDF document. Unlike a string, stream
* data is not restricted in length. Stream data may be encoded with the filter
* implementation.
*/
public class COSStream extends COSCompositeObject {
public static final COSName DK_DecodeParms = COSName
.constant("DecodeParms"); //$NON-NLS-1$
public static final COSName DK_DP = COSName.constant("DP"); //$NON-NLS-1$
public static final COSName DK_F = COSName.constant("F"); //$NON-NLS-1$
public static final COSName DK_FDecodeParams = COSName
.constant("FDecodeParams"); //$NON-NLS-1$
public static final COSName DK_FFilter = COSName.constant("FFilter"); //$NON-NLS-1$
public static final COSName DK_Filter = COSName.constant("Filter"); //$NON-NLS-1$
public static final COSName DK_Length = COSName.constant("Length"); //$NON-NLS-1$
public static final COSName DK_Resources = COSName.constant("Resources"); //$NON-NLS-1$
public static final Object SLOT_BYTES = new Object();
/**
* Create a new {@link COSStream}.
*
* @param dict
* An optional dictionary to be used as the streams dictionary.
* @return Create a new {@link COSStream}.
*/
public static COSStream create(COSDictionary dict) {
COSStream result = new COSStream(dict);
result.beIndirect();
return result;
}
/**
* The options or an array of options for filtering.
*
* @return The options or an array of options for filtering.
*/
static public COSObject getDecodeParams(COSDictionary dict) {
if (isExternal(dict)) {
return dict.get(DK_FDecodeParams);
}
COSObject result = dict.get(DK_DP);
if (!result.isNull()) {
return result;
}
return dict.get(DK_DecodeParms);
}
/**
* The options corresponding to the first occurence of the filter
* name
.
*
* @return The options corresponding to the first occurence of the filter
* name
.
*/
static public COSDictionary getDecodeParams(COSDictionary dict, COSName name) {
COSObject basicFilters = getFilters(dict);
if (basicFilters instanceof COSName) {
COSName filter = basicFilters.asName();
if (filter.equals(name)) {
return dict.get(COSStream.DK_DecodeParms).asDictionary();
}
} else if (basicFilters instanceof COSArray) {
COSArray filters = basicFilters.asArray();
int i = 0;
Iterator it = filters.iterator();
while (it.hasNext()) {
COSName filter = ((COSObject) it.next()).asName();
if (filter != null && filter.equals(name)) {
COSArray decodeParamsArray = dict.get(
COSStream.DK_DecodeParms).asArray();
if (decodeParamsArray != null) {
return decodeParamsArray.get(i).asDictionary();
}
}
i++;
}
}
return null;
}
/**
* Return the filter or the collection of filters for the stream.
*
* @return The filter or the collection of filters for the stream.
*/
static public COSObject getFilters(COSDictionary dict) {
if (isExternal(dict)) {
return dict.get(DK_FFilter);
}
COSObject result = dict.get(DK_F);
if (!result.isNull()) {
return result;
}
return dict.get(DK_Filter);
}
/**
* true
if the stream hs declared a filter name
.
*
* @param name
* The name of the filter.
* @return true
if the stream hs declared a filter
* name
.
*/
static public boolean hasFilter(COSDictionary dict, COSName name) {
COSObject filters = getFilters(dict);
if (filters.isNull()) {
return false;
}
if (filters instanceof COSName) {
return filters.equals(name);
}
if (filters instanceof COSArray) {
for (Iterator i = ((COSArray) filters).iterator(); i.hasNext();) {
COSName filterName = ((COSObject) i.next()).asName();
if (filterName != null && filterName.equals(name)) {
return true;
}
}
}
return false;
}
/**
* true
if the stream dictionary contains the F key.
*
* @return true
if the stream dictionary contains the F key.
*/
static public boolean isExternal(COSDictionary dict) {
// check for F key
// if it is a Array or Name, it is used as an abbreviation for Filter
COSObject result = dict.get(DK_F);
if (!result.isNull()) {
if (result instanceof COSName || result instanceof COSArray) {
return false;
}
return true;
}
return false;
}
/** The logical byte stream */
private byte[] decodedBytes;
/** the dictionary describing the stream */
private COSDictionary dict;
/** The physical byte stream */
private byte[] encodedBytes;
protected COSStream() {
super();
}
/**
* COSStream constructor.
*
* @param newDict
* The stream dictionary for the new stream. Can be null, a new
* dictionary will be created.
*/
protected COSStream(COSDictionary newDict) {
super();
if (newDict == null) {
newDict = COSDictionary.create();
}
setDict(newDict);
}
/*
* (non-Javadoc)
*
* @see
* de.intarsys.pdf.cos.COSObject#accept(de.intarsys.pdf.cos.ICOSObjectVisitor
* )
*/
@Override
public java.lang.Object accept(ICOSObjectVisitor visitor)
throws COSVisitorException {
return visitor.visitFromStream(this);
}
/**
* Add a new filter declaration to the filters collection. If necessary
* convert the Filter entry to a collection first.
*
* @param name
* The logical name of the filter.
*/
public void addFilter(COSName name) {
addFilter(getFilterSize(), name, null);
}
/**
* Add a new filter declaration to the filters collection. If necessary
* convert the Filter entry to a collection first.
*
* @param name
* The logical name of the filter.
* @param dictionary
* The corresponding decode parameters
*/
public void addFilter(COSName name, COSDictionary dictionary) {
addFilter(getFilterSize(), name, dictionary);
}
/**
* Add a new filter declaration to the filters collection at the specified
* index. If necessary convert the Filter entry to a collection first.
*
* @param index
* The index to add the filter at.
* @param name
* The logical name of the filter.
*/
public void addFilter(int index, COSName name) {
addFilter(index, name, null);
}
/**
* Add a new filter declaration to the filters collection at the specified
* index. If necessary convert the Filter entry to a collection first.
*
* @param index
* The index to add the filter at.
* @param name
* The logical name of the filter.
* @param dictionary
* The corresponding decode parameters
*/
public void addFilter(int index, COSName name, COSDictionary dictionary) {
// be sure decoded stream is available
getDecodedBytes();
encodedBytes = null;
COSObject filters = getFilters();
if (filters.isNull()) {
getDict().put(DK_Filter, name);
getDict().put(DK_DecodeParms, dictionary);
} else {
COSName filterName;
COSArray newFilterArray;
COSObject decodeParms;
COSArray newDecodeParmsArray;
filterName = filters.asName();
if (filterName != null) {
getDict().remove(DK_Filter);
newFilterArray = COSArray.create(2);
newFilterArray.add(filterName);
} else {
newFilterArray = filters.asArray();
}
newFilterArray.add(index, name);
getDict().put(DK_Filter, newFilterArray);
decodeParms = getDecodeParams();
newDecodeParmsArray = null;
if (decodeParms.isNull() && dictionary != null) {
newDecodeParmsArray = COSArray.create(newFilterArray.size());
// add one less
for (int count = 0; count < newFilterArray.size() - 1; count++) {
newDecodeParmsArray.add(COSNull.NULL);
}
} else {
COSDictionary decodeParmsDictionary;
decodeParmsDictionary = decodeParms.asDictionary();
if (decodeParmsDictionary != null) {
getDict().remove(DK_DecodeParms);
newDecodeParmsArray = COSArray
.create(newFilterArray.size());
newDecodeParmsArray.add(decodeParmsDictionary);
} else {
newDecodeParmsArray = decodeParms.asArray();
}
}
if (newDecodeParmsArray != null) {
if (dictionary == null) {
newDecodeParmsArray.add(index, COSNull.NULL);
} else {
newDecodeParmsArray.add(index, dictionary);
}
}
getDict().put(DK_DecodeParms, newDecodeParmsArray);
}
}
/*
* (non-Javadoc)
*
* @see
* de.intarsys.pdf.cos.COSCompositeObject#addObjectListener(de.intarsys.
* pdf.cos.ICOSObjectListener)
*/
@Override
public void addObjectListener(ICOSObjectListener listener) {
super.addObjectListener(listener);
if (dict != null) {
dict.addObjectListener(listener);
}
}
/*
* (non-Javadoc)
*
* @see de.intarsys.pdf.cos.COSObject#asStream()
*/
@Override
public COSStream asStream() {
return this;
}
/*
* (non-Javadoc)
*
* @see de.intarsys.pdf.cos.COSObject#basicIterator()
*/
@Override
public Iterator basicIterator() {
return new SingleObjectIterator(getDict());
}
/**
* Set the streams logical content.
*
* @param newBytes
* the logical content for the stream
*/
public void basicSetDecodedBytes(byte[] newBytes) {
decodedBytes = newBytes;
encodedBytes = null;
// no update propagation, please!!
getDict().basicRemoveSilent(DK_Length);
}
/**
* Set the streams physical content.
*
* @param newBytes
* the physical content for the stream
*/
public void basicSetEncodedBytes(byte[] newBytes) {
encodedBytes = newBytes;
decodedBytes = null;
int length = (encodedBytes == null) ? 0 : encodedBytes.length;
// no update propagation, please!!
getDict().basicPutSilent(DK_Length, COSInteger.create(length));
}
/*
* (non-Javadoc)
*
* @see de.intarsys.pdf.cos.COSObject#basicToString()
*/
@Override
protected String basicToString() {
byte[] decoded = getDecodedBytes();
if (decoded == null) {
return null;
}
return new String(decoded);
}
/*
* (non-Javadoc)
*
* @see de.intarsys.pdf.cos.COSObject#copyBasic()
*/
@Override
protected COSObject copyBasic() {
COSStream result = new COSStream();
result.beIndirect();
// aggregated dictionary takes care of itself
result.encodedBytes = this.encodedBytes;
result.decodedBytes = this.decodedBytes;
return result;
}
/**
* A copy of this, bytes decoded.
*
* @return A copy of this, bytes decoded.
* @throws IOException
*/
public COSStream copyDecodeFirst() throws IOException {
COSStream newStream;
COSName filter;
COSArray filters;
COSArray decodeParmss;
byte[] bytes;
// prepare new stream
newStream = (COSStream) copyShallow();
if (getFilters().isNull()) {
return newStream;
}
newStream.basicSetDecodedBytes(null);
newStream.getDict().remove(DK_DecodeParms);
newStream.getDict().remove(DK_Filter);
newStream.getDict().remove(DK_Length);
// prepare content
bytes = getEncodedBytes();
if ((filter = getFirstFilter()) != null) {
bytes = doDecode(filter, getFirstDecodeParam(), bytes, 0,
getAnyLength());
}
filters = getFilters().asArray();
if (filters != null) {
decodeParmss = getDecodeParams().asArray();
for (int index = filters.size() - 1; index > 0; index--) {
if (decodeParmss != null) {
COSDictionary dictionary;
dictionary = decodeParmss.get(index).asDictionary();
if (dictionary != null) {
dictionary = (COSDictionary) dictionary.copyShallow();
}
newStream.filter(
(COSName) filters.get(index).copyShallow(),
dictionary);
} else {
newStream
.filter((COSName) filters.get(index).copyShallow());
}
}
}
newStream.setEncodedBytes(bytes);
return newStream;
}
/*
* (non-Javadoc)
*
* @see de.intarsys.pdf.cos.COSCompositeObject#copyDeep(java.util.Map)
*/
@Override
public COSObject copyDeep(Map copied) {
COSStream result = (COSStream) super.copyDeep(copied);
result.setDict((COSDictionary) getDict().copyDeep(copied));
if (encodedBytes != null) {
result.setEncodedBytes(encodedBytes);
} else {
result.setDecodedBytes(decodedBytes);
}
return result;
}
/*
* (non-Javadoc)
*
* @see de.intarsys.pdf.cos.COSObject#copyShallow()
*/
@Override
public COSObject copyShallow() {
COSStream result = (COSStream) super.copyShallow();
result.setDict((COSDictionary) getDict().copyShallow());
if (encodedBytes != null) {
result.setEncodedBytes(encodedBytes);
} else {
result.setDecodedBytes(decodedBytes);
}
return result;
}
/*
* (non-Javadoc)
*
* @see de.intarsys.pdf.cos.COSObject#copySubGraph(java.util.Map)
*/
@Override
protected COSObject copySubGraph(Map copied) {
COSStream result = (COSStream) super.copySubGraph(copied);
result.setDict((COSDictionary) getDict().copySubGraph(copied));
if (encodedBytes != null) {
result.setEncodedBytes(encodedBytes);
} else {
result.setDecodedBytes(decodedBytes);
}
return result;
}
/**
* Decode the filtered stream content using the filters defined in the
* /Filter entry in the stream dictionary
*
* @return The decoded bytes.
* @throws IOException
*/
protected byte[] doDecode() throws IOException {
byte[] newBytes;
if (isExternal() && isBytesArrayEmpty(encodedBytes)) {
// reset the encodedbytes because of later null checks
encodedBytes = null;
parseFKeyedFile();
}
if (encodedBytes == null) {
return null;
}
// get the filters
COSObject filters = getFilters();
if (filters.isNull()) {
int length = getLength();
if ((length != -1) && (encodedBytes.length > length)) {
newBytes = new byte[length];
System.arraycopy(encodedBytes, 0, newBytes, 0, length);
} else {
newBytes = encodedBytes;
}
return newBytes;
}
// get the options
COSObject options = getDecodeParams();
// decode
if (filters instanceof COSName) {
newBytes = doDecode((COSName) filters, options.asDictionary(),
encodedBytes, 0, getAnyLength());
} else {
byte[] temp = encodedBytes;
int length = getAnyLength();
for (int i = 0; i < ((COSArray) filters).size(); i++) {
COSObject option = COSNull.NULL;
if (!options.isNull()) {
option = ((COSArray) options).get(i);
}
COSName filter = ((COSArray) filters).get(i).asName();
temp = doDecode(filter, option.asDictionary(), temp, 0, length);
if (temp != null) {
length = temp.length;
}
}
newBytes = temp;
}
return newBytes;
}
/**
* Perform the decoding process of the underlying byte stream.
*
* @param filterName
* The name of a filter to use for this step.
* @param options
* The options to use for the filter.
* @param bytes
* The bytes to decode.
* @param offset
* The offset to start.
* @param length
* The length to be decoded.
*
* @return The decoded bytes.
*
* @throws IOException
*/
protected byte[] doDecode(COSName filterName, COSDictionary options,
byte[] bytes, int offset, int length) throws IOException {
if (bytes == null) {
return new byte[0];
}
IFilter filter = FilterFactory.get().createFilter(filterName, options);
filter.setStream(this);
return filter.decode(bytes, offset, length);
}
/**
* encode the filtered stream content using the filters defined in the
* /Filter entry in the stream dictionary in reverse order
*
* @throws IOException
*/
protected void doEncode() throws IOException {
if (decodedBytes == null) {
return;
}
// get the filters
COSObject filters = getFilters();
if (filters.isNull()) {
encodedBytes = decodedBytes;
return;
}
// get the options
COSObject options = getDecodeParams();
// encode
if (filters instanceof COSName) {
encodedBytes = doEncode((COSName) filters, options.asDictionary(),
decodedBytes, 0, decodedBytes.length);
} else {
byte[] temp = decodedBytes;
int length = decodedBytes.length;
for (int i = ((COSArray) filters).size() - 1; i >= 0; i--) {
COSDictionary option = null;
if (!options.isNull()) {
option = ((COSArray) options).get(i).asDictionary();
}
COSName filter = ((COSArray) filters).get(i).asName();
temp = doEncode(filter, option, temp, 0, length);
length = temp.length;
}
encodedBytes = temp;
}
}
/**
* Perform the encoding process of the underlying byte stream.
*
* @param filterName
* The name of a filter to use for this step.
* @param options
* The options to use for the filter.
* @param bytes
* The bytes to encode .
* @param offset
* The offset to start.
* @param length
* The length to be encoded.
*
* @return The encoded bytes.
*
* @throws IOException
*/
protected byte[] doEncode(COSName filterName, COSDictionary options,
byte[] bytes, int offset, int length) throws IOException {
if (bytes == null) {
return new byte[0];
}
IFilter filter = FilterFactory.get().createFilter(filterName, options);
filter.setStream(this);
return filter.encode(bytes, offset, length);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
return this.equals(o, new HashSet());
}
@Override
protected boolean equals(Object o, Set visited) {
if (isIndirect()) {
if (visited.contains(getIndirectObject())) {
return true;
}
visited.add(getIndirectObject());
}
if (this == o) {
return true;
}
if (!(o instanceof COSStream)) {
return false;
}
COSStream other = (COSStream) o;
if (!getDict().equals(other.getDict())) {
return false;
}
if (getLength() != other.getLength()) {
return false;
}
if (!Arrays.equals(getEncodedBytes(), other.getEncodedBytes())) {
return false;
}
return true;
}
/**
* Add a new filter. If the stream is already filtered, the new filter will
* be applied to the current encoded bytes.
*
* @param name
* The logical name of the filter.
*/
public void filter(COSName name) {
addFilter(0, name, null);
}
/**
* Add a new filter. If the stream is already filtered, the new filter will
* be applied to the current encoded bytes.
*
* @param name
* The logical name of the filter.
* @param dictionary
* The corresponding decode parameters
*/
public void filter(COSName name, COSDictionary dictionary) {
addFilter(0, name, dictionary);
}
/**
* The declared or real length for this.
*
* @return The declared or real length for this.
*/
public int getAnyLength() {
int result = getLength();
if (result == -1) {
return encodedBytes.length;
}
return result;
}
/**
* The unfiltered (logical) stream content. It is not intended to manipulate
* the byte array directly.
*
* @return The unfiltered (logical) stream content
*
* @throws IOException
*/
public byte[] getDecodedBytes() {
if (decodedBytes == null) {
try {
decodedBytes = doDecode();
} catch (IOException e) {
handleException(new COSRuntimeException(
"error decoding stream", e)); //$NON-NLS-1$
}
}
return decodedBytes;
}
/**
* The unfiltered content as in getDecodedBytes, but allow the caller to
* manipulate the result by copying/not caching the returned bytes
*
* @return The unfiltered content as in getDecodedBytes
*/
public byte[] getDecodedBytesWritable() {
byte[] bytes;
byte[] copiedBytes;
try {
bytes = doDecode();
// take care; doDecode does not always create a new array
if (bytes != encodedBytes) {
return bytes;
}
} catch (IOException e) {
handleException(new COSRuntimeException("error decoding stream", e)); //$NON-NLS-1$
return new byte[0];
}
copiedBytes = new byte[bytes.length];
System.arraycopy(bytes, 0, copiedBytes, 0, bytes.length);
return copiedBytes;
}
/**
* The options or an array of options for filtering.
*
* @return The options or an array of options for filtering.
*/
public COSObject getDecodeParams() {
return getDecodeParams(getDict());
}
/**
* The options corresponding to the first occurrence of the filter
* name
.
*
* @return The options corresponding to the first occurrence of the filter
* name
.
*/
public COSDictionary getDecodeParams(COSName name) {
return getDecodeParams(getDict(), name);
}
/**
* The stream dictionary
*
* @return The stream dictionary
*/
public COSDictionary getDict() {
return dict;
}
/**
* The filtered (physical) stream content. If it must be generated first,
* then the content length is adjusted as a side effect. It is not intended
* to manipulate the byte array directly.
*
* @return The filtered (physical) stream content
*/
public byte[] getEncodedBytes() {
if (encodedBytes == null) {
try {
doEncode();
} catch (IOException e) {
handleException(new COSRuntimeException(
"error encoding stream", e)); //$NON-NLS-1$
}
int length = (encodedBytes == null) ? 0 : encodedBytes.length;
getDict().basicPutSilent(DK_Length, COSInteger.create(length));
}
return encodedBytes;
}
/**
* Return the filter or the collection of filters for the stream.
*
* @return The filter or the collection of filters for the stream.
*/
public COSObject getFilters() {
return getFilters(getDict());
}
/**
* Return the number of filters.
*
* @return The number of filters.
*/
public int getFilterSize() {
COSObject filter;
filter = getFilters();
if (filter.isNull()) {
return 0;
}
if (filter.asName() != null) {
return 1;
}
return filter.asArray().size();
}
/**
* A dictionary with filter options or the first element of an array of such
* dictionaries for each filter.
*
* @return A dictionary with filter options or the first element of an array
* of such dictionaries for each filter.
*/
public COSDictionary getFirstDecodeParam() {
COSObject dictionaryOrArray;
dictionaryOrArray = getDecodeParams();
if (dictionaryOrArray.isNull()) {
return null;
}
if (dictionaryOrArray instanceof COSDictionary) {
return (COSDictionary) dictionaryOrArray;
}
if (dictionaryOrArray instanceof COSArray) {
return ((COSArray) dictionaryOrArray).get(0).asDictionary();
}
return null;
}
/**
* The filter or the first element of the collection of filters for the
* stream.
*
* @return The filter or the first element of the collection of filters for
* the stream.
*/
public COSName getFirstFilter() {
COSObject nameOrArray;
nameOrArray = getFilters();
if (nameOrArray.isNull()) {
return null;
}
if (nameOrArray instanceof COSName) {
return (COSName) nameOrArray;
}
if (nameOrArray instanceof COSArray) {
return ((COSArray) nameOrArray).get(0).asName();
}
return null;
}
/**
* The length of the encoded content. Be aware that this is the /Length
* written in the stream dictionary, which is not necessarily a meaningful
* value...
*
* @return The length of the encoded content
*/
public int getLength() {
COSNumber length = dict.get(DK_Length).asInteger();
if (length != null) {
return length.intValue();
}
return -1;
}
/**
* true
if the stream hs declared a filter name
.
*
* @param name
* The name of the filter.
* @return true
if the stream hs declared a filter
* name
.
*/
public boolean hasFilter(COSName name) {
return hasFilter(getDict(), name);
}
/**
* tests a byte array for null, length=0 or crlf emptiness
*
* @param toTest
* @return
*/
private boolean isBytesArrayEmpty(byte[] toTest) {
if ((toTest == null) || (toTest.length == 0)) {
return true;
}
if ((toTest.length == 2) && (toTest[0] == 13) && (toTest[1] == 10)) {
return true;
}
return false;
}
/**
* true
if the stream dictionary contains the F key.
*
* @return true
if the stream dictionary contains the F key.
*/
public boolean isExternal() {
return isExternal(getDict());
}
/*
* (non-Javadoc)
*
* @see de.intarsys.pdf.cos.COSObject#iterator()
*/
@Override
public Iterator iterator() {
return new SingleObjectIterator(getDict());
}
/**
* Parse the file referenced by the F key in this stream and set as the
* filtered content.
*/
protected void parseFKeyedFile() {
COSObject fileSpec = dict.get(DK_F);
String filepath = ""; //$NON-NLS-1$
if (fileSpec instanceof COSString) {
filepath = ((COSString) fileSpec).stringValue();
} else {
// todo 2 implement PDF fileSpecification logic
return;
}
File externalFile = new File(filepath);
if (!externalFile.exists()) {
return;
}
byte[] content;
try {
content = FileTools.toBytes(externalFile);
} catch (IOException e) {
return;
}
if (content != null) {
encodedBytes = content;
}
}
/**
* Remove all filters from this.
*/
public void removeFilters() {
// be sure decoded stream is available
getDecodedBytes();
encodedBytes = null;
getDict().remove(DK_Filter);
}
/*
* (non-Javadoc)
*
* @see
* de.intarsys.pdf.cos.COSCompositeObject#removeObjectListener(de.intarsys
* .pdf.cos.ICOSObjectListener)
*/
@Override
public void removeObjectListener(ICOSObjectListener listener) {
super.removeObjectListener(listener);
if (dict != null) {
dict.removeObjectListener(listener);
}
}
/*
* (non-Javadoc)
*
* @see de.intarsys.pdf.cos.COSObject#restoreState(java.lang.Object)
*/
@Override
public void restoreState(Object object) {
super.restoreState(object);
COSStream stream = (COSStream) object;
encodedBytes = stream.encodedBytes;
decodedBytes = stream.decodedBytes;
triggerChanged(null, null, null);
}
/*
* (non-Javadoc)
*
* @see de.intarsys.tools.objectsession.ISaveStateSupport#saveState()
*/
public Object saveState() {
COSStream result = new COSStream();
// aggregated dictionary takes care of itself
result.encodedBytes = this.encodedBytes;
result.decodedBytes = this.decodedBytes;
result.container = this.container.saveStateContainer();
return result;
}
/**
* Set the streams logical content
*
* @param newBytes
* The logical content for the stream
*/
public void setDecodedBytes(byte[] newBytes) {
willChange(this);
basicSetDecodedBytes(newBytes);
if (objectListeners != null) {
triggerChanged(SLOT_BYTES, null, null);
}
}
/**
* Give private access to dictionary to ease copying.
*
* @param dictionary
* dictionary part of the stream
*
* @throws IllegalArgumentException
* if the stream is indirect
*/
private void setDict(COSDictionary dictionary) {
if (dictionary.isIndirect()) {
throw new IllegalArgumentException(
"stream dictionary cannot be indirect"); //$NON-NLS-1$
}
dict = dictionary;
dict.addContainer(this);
}
/**
* Set the stream physical content.
*
* @param newBytes
* the physical content for the stream
*/
public void setEncodedBytes(byte[] newBytes) {
willChange(this);
basicSetEncodedBytes(newBytes);
if (objectListeners != null) {
triggerChanged(SLOT_BYTES, null, null);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy