public String getDigestMethod() { COSName cosDigestMethod = cosGetField(DK_DigestMethod).asName(); if (cosDigestMethod == null) { return DEFAULT_DIGESTMETHOD; } return cosDigestMethod.stringValue(); }
public class CIDSystemInfo extends COSBasedObject { /** The meta class implementation */ public static class MetaClass extends COSBasedObject.MetaClass { protected MetaClass(Class instanceClass) { super(instanceClass); } @Override protected COSBasedObject doCreateCOSBasedObject(COSObject object) { return new CIDSystemInfo(object); } } /** The meta class instance */ public static final MetaClass META = new MetaClass(MetaClass.class.getDeclaringClass()); public static final COSName DK_Registry = COSName.constant("Registry"); public static final COSName DK_Ordering = COSName.constant("Ordering"); public static final COSName DK_Supplement = COSName.constant("Supplement"); protected CIDSystemInfo(COSObject object) { super(object); } @Override protected void initializeFromScratch() { super.initializeFromScratch(); cosSetField(DK_Registry, COSString.create("Adobe")); cosSetField(DK_Ordering, COSString.create("Identity")); cosSetField(DK_Supplement, COSInteger.create(0)); } }
@Override public ISecurityHandler getSecurityHandler(COSEncryption encryption) throws COSSecurityException { COSName name = encryption.getFilter(); if (name == null) { throw new COSSecurityException("security handler not specified"); // $NON-NLS-1$ } if (name.equals(CN_Standard)) { int revision = encryption.getFieldInt(DK_R, 0); if (revision == 2) { return new StandardSecurityHandlerR2(); } else if (revision == 3) { return new StandardSecurityHandlerR3(); } else if (revision == 4) { return new StandardSecurityHandlerR4(); } else { return new StandardSecurityHandlerR2(); } } // maybe provide a registry some day throw new COSSecurityException( "no security handler '" //$NON-NLS-1$ + name.stringValue() + "'"); //$NON-NLS-1$ }
/** A standard implementation for the {@link ISecurityHandlerFactory}. */ public class StandardSecurityHandlerFactory implements ISecurityHandlerFactory { public static final COSName CN_Standard = COSName.constant("Standard"); // $NON-NLS-1$ protected StandardSecurityHandlerFactory() { super(); } public static final COSName DK_R = COSName.constant("R"); // $NON-NLS-1$ @Override public ISecurityHandler getSecurityHandler(COSEncryption encryption) throws COSSecurityException { COSName name = encryption.getFilter(); if (name == null) { throw new COSSecurityException("security handler not specified"); // $NON-NLS-1$ } if (name.equals(CN_Standard)) { int revision = encryption.getFieldInt(DK_R, 0); if (revision == 2) { return new StandardSecurityHandlerR2(); } else if (revision == 3) { return new StandardSecurityHandlerR3(); } else if (revision == 4) { return new StandardSecurityHandlerR4(); } else { return new StandardSecurityHandlerR2(); } } // maybe provide a registry some day throw new COSSecurityException( "no security handler '" //$NON-NLS-1$ + name.stringValue() + "'"); //$NON-NLS-1$ } }
public void setDigestMethod(String digestMethod) { COSName cosDigestMethod = null; if (digestMethod != null) { cosDigestMethod = COSName.create(digestMethod); } cosSetField(DK_DigestMethod, cosDigestMethod); }
/* * (non-Javadoc) * * @see * de.intarsys.pdf.cos.COSBasedObject.MetaClass#doDetermineClass(de. * intarsys.pdf.cos.COSObject) */ @Override protected COSBasedObject.MetaClass doDetermineClass(COSObject object) { COSDictionary dict; dict = object.asDictionary(); if (dict == null) { throw new IllegalArgumentException("font object is not a COSDictionary as required"); } COSName type = dict.get(DK_Type).asName(); if (type == null) { throw new IllegalArgumentException("Dictionary has no type"); } if (!type.equals(CN_Type_Font)) { throw new IllegalArgumentException("type <" + type + "> is not a valid font type"); } COSName subtype = dict.get(DK_Subtype).asName(); if (subtype == null) { throw new IllegalArgumentException("font not identified by subtype"); } if (subtype.equals(CN_Subtype_Type1)) { return PDFontType1.META; } else if (subtype.equals(CN_Subtype_TrueType)) { if (dict.get(DK_FontDescriptor).isNull()) { /* * treat as if Type1 was specified, because that's probably * what the creator meant; further processing would yield * wrong results anyway as FontDescriptor is a required * entry for TrueType fonts */ return PDFontType1.META; } return PDFontTrueType.META; } else if (subtype.equals(CN_Subtype_MMType1)) { return PDFontMMType1.META; } else if (subtype.equals(CN_Subtype_Type0)) { return PDFontType0.META; } else if (subtype.equals(CN_Subtype_Type3)) { return PDFontType3.META; } else if (subtype.equals(CN_Subtype_CIDFontType0)) { return CIDFontType0.META; } else if (subtype.equals(CN_Subtype_CIDFontType2)) { return CIDFontType2.META; } throw new IllegalArgumentException("font subtype <" + subtype + "> not supported"); }
/** This object specifies details on the signature. */ public class PDSignatureReference extends PDObject { /** The meta class implementation */ public static class MetaClass extends PDObject.MetaClass { protected MetaClass(Class instanceClass) { super(instanceClass); } @Override protected COSBasedObject doCreateCOSBasedObject(COSObject object) { return new PDSignatureReference(object); } } /** The meta class instance */ public static final MetaClass META = new MetaClass(MetaClass.class.getDeclaringClass()); public static final COSName CN_Type_SigRef = COSName.constant("SigRef"); // $NON-NLS-1$ public static final COSName DK_TransformMethod = COSName.constant("TransformMethod"); // $NON-NLS-1$ public static final COSName DK_TransformParams = COSName.constant("TransformParams"); // $NON-NLS-1$ public static final COSName DK_Data = COSName.constant("Data"); // $NON-NLS-1$ public static final COSName DK_DigestMethod = COSName.constant("DigestMethod"); // $NON-NLS-1$ public static final COSName DK_DigestValue = COSName.constant("DigestValue"); // $NON-NLS-1$ public static final COSName DK_DigestLocation = COSName.constant("DigestLocation"); // $NON-NLS-1$ public static final String DIGESTMETHOD_MD5 = "MD5"; // $NON-NLS-1$ public static final String DIGESTMETHOD_SHA1 = "SHA1"; // $NON-NLS-1$ private static final String DEFAULT_DIGESTMETHOD = DIGESTMETHOD_MD5; // $NON-NLS-1$ protected PDSignatureReference(COSObject object) { super(object); } public COSObject cosGetData() { COSObject data = cosGetField(DK_Data); return data.isNull() ? null : data; } public COSArray cosGetDigestLocation() { return cosGetField(DK_DigestLocation).asArray(); } /* * (non-Javadoc) * * @see de.intarsys.pdf.pd.PDObject#cosGetExpectedType() */ @Override protected COSName cosGetExpectedType() { return CN_Type_SigRef; } public void cosSetData(COSObject data) { cosSetField(DK_Data, data); } public String getDigestMethod() { COSName cosDigestMethod = cosGetField(DK_DigestMethod).asName(); if (cosDigestMethod == null) { return DEFAULT_DIGESTMETHOD; } return cosDigestMethod.stringValue(); } public byte[] getDigestValue() { COSString cosDigestValue = cosGetField(DK_DigestValue).asString(); if (cosDigestValue == null) { return null; } return cosDigestValue.byteValue(); } public PDTransformMethod getTransformMethod() { return (PDTransformMethod) PDTransformMethod.META.createFromCos(cosGetField(DK_TransformMethod)); } public PDTransformParams getTransformParams() { return (PDTransformParams) PDTransformParams.META.createFromCos(cosGetField(DK_TransformParams)); } public void setDigestMethod(String digestMethod) { COSName cosDigestMethod = null; if (digestMethod != null) { cosDigestMethod = COSName.create(digestMethod); } cosSetField(DK_DigestMethod, cosDigestMethod); } public void setDigestValue(byte[] digest) { COSString cosDigestValue = null; if (digest != null) { cosDigestValue = COSString.create(digest); } cosSetField(DK_DigestValue, cosDigestValue); } public void setTransformMethod(PDTransformMethod method) { COSObject cosMethod = null; if (method != null) { cosMethod = method.cosGetObject(); } cosSetField(DK_TransformMethod, cosMethod); } public void setTransformParams(PDTransformParams params) { COSObject cosParams = null; if (params != null) { cosParams = params.cosGetObject(); } cosSetField(DK_TransformParams, cosParams); } }
/** * The explicit reference to a destination in a PDF document, consisting of a page and a definition * of the rectangle to be displayed. */ public class PDExplicitDestination extends PDDestination { /** The meta class implementation */ public static class MetaClass extends PDDestination.MetaClass { protected MetaClass(Class instanceClass) { super(instanceClass); } } /** The meta class instance */ public static final MetaClass META = new MetaClass(MetaClass.class.getDeclaringClass()); public static final COSName CN_DISPLAY_MODE_XYZ = COSName.constant("XYZ"); public static final COSName CN_DISPLAY_MODE_Fit = COSName.constant("Fit"); public static final COSName CN_DISPLAY_MODE_FitH = COSName.constant("FitH"); public static final COSName CN_DISPLAY_MODE_FitV = COSName.constant("FitV"); public static final COSName CN_DISPLAY_MODE_FitR = COSName.constant("FitR"); public static final COSName CN_DISPLAY_MODE_FitB = COSName.constant("FitB"); public static final COSName CN_DISPLAY_MODE_FitBH = COSName.constant("FitBH"); public static final COSName CN_DISPLAY_MODE_FitBV = COSName.constant("FitBV"); protected PDExplicitDestination(COSObject object) { super(object); } public COSName getDisplayMode() { COSArray definition = cosGetArray(); if (definition.size() < 2) { return null; } return definition.get(1).asName(); } /** * The destination page. ATTENTION: it is common have dangling destinations to invalid (null) * pages around! * * @return The destination page. Be sure to handle null return values. */ public PDPage getPage(PDDocument doc) { COSArray definition = cosGetArray(); COSObject page = definition.get(0); if (page.asNumber() != null) { int pageIndex = page.asNumber().intValue(); return doc.getPageTree().getPageAt(pageIndex); } if (page.asDictionary() != null) { return (PDPage) PDPageNode.META.createFromCos(page.asDictionary()); } return null; } public float[] getParameters() { COSArray definition = cosGetArray(); int size = definition.size() - 2; if (size < 0) { return new float[0]; } float[] result = new float[size]; for (int i = 0; i < size; i++) { COSNumber param = definition.get(i + 2).asNumber(); if (param == null) { result[i] = 0; } else { result[i] = param.floatValue(); } } return result; } /* * (non-Javadoc) * * @see de.intarsys.pdf.pd.PDDestination#getResolvedDestination(de.intarsys.pdf.pd.PDDoc) */ @Override public PDExplicitDestination getResolvedDestination(PDDocument doc) { return this; } public void setDisplayMode(COSName mode) { COSArray definition = cosGetArray(); if (definition.size() == 0) { definition.add(COSNull.NULL); definition.add(mode); } else if (definition.size() == 1) { definition.add(mode); } else { definition.set(1, mode); } } public void setPage(PDPage page) { COSArray definition = cosGetArray(); if (definition.size() == 0) { definition.add(page.cosGetObject()); } else { definition.set(0, page.cosGetObject()); } } public void setParameters(double[] parameters) { COSArray definition = cosGetArray(); while (definition.size() < (2 + parameters.length)) { definition.add(COSNull.NULL); } for (int i = 0; i < parameters.length; i++) { definition.set(i + 2, COSFixed.create(parameters[i])); } } public void setParameters(float[] parameters) { COSArray definition = cosGetArray(); while (definition.size() < (2 + parameters.length)) { definition.add(COSNull.NULL); } for (int i = 2; i < (2 + parameters.length); i++) { definition.set(i, COSFixed.create(parameters[i])); } } }
/** The definition of a border style for an annotation. */ public class PDBorderStyle extends PDObject { /** The meta class implementation */ public static class MetaClass extends PDObject.MetaClass { protected MetaClass(Class instanceClass) { super(instanceClass); } protected COSBasedObject doCreateCOSBasedObject(COSObject object) { return new PDBorderStyle(object); } } /** The meta class instance */ public static final MetaClass META = new MetaClass(MetaClass.class.getDeclaringClass()); /** The width type. */ public static final COSName DK_W = COSName.constant("W"); /** The Style type. */ public static final COSName DK_S = COSName.constant("S"); /** Style S: solid */ public static final COSName CN_S_S = COSName.constant("S"); /** Style D: dashed */ public static final COSName CN_S_D = COSName.constant("D"); /** Style B: beveled */ public static final COSName CN_S_B = COSName.constant("B"); /** Style D: Inset */ public static final COSName CN_S_I = COSName.constant("I"); /** Style D: underlined */ public static final COSName CN_S_U = COSName.constant("U"); /** The DashArray type. */ public static final COSName DK_D = COSName.constant("D"); // /** The border type name */ public static final COSName CN_Type_Border = COSName.constant("Border"); // protected PDBorderStyle(COSObject object) { super(object); } public void setDashArray(int[] newDashArray) { if ((newDashArray == null) || ((newDashArray.length == 1) && (newDashArray[0] == 3))) { cosRemoveField(DK_D); return; } COSArray a = COSArray.create(newDashArray.length); cosSetField(DK_D, a); // overwrite existing array for (int i = 0; i < newDashArray.length; i++) { a.add(COSInteger.create(newDashArray[i])); } } public int[] getDashArray() { COSArray array = cosGetField(DK_D).asArray(); if (array != null) { int[] result = new int[array.size()]; for (int i = 0; i < array.size(); i++) { COSInteger value = array.get(i).asInteger(); if (value != null) { result[i] = value.intValue(); } else { // TODO 3 wrong default, maybe restrict result[i] = 0; } } return result; } return new int[] {3}; // default } public void setStyle(COSName newStyle) { cosSetField(DK_S, newStyle); } public COSName getStyle() { COSName style = cosGetField(DK_S).asName(); if (style != null) { return style; } return CN_S_S; } /* * (non-Javadoc) * * @see de.intarsys.pdf.pd.PDObject#cosGetExpectedType() */ protected COSName cosGetExpectedType() { return CN_Type_Border; } /** * Set the style. If newWidth = 0, no border is drawn. * * @param newWidth The new width. */ public void setWidth(float newWidth) { if (newWidth != 1) { setFieldFixed(DK_W, newWidth); } else { cosRemoveField(DK_W); } } public float getWidth() { return getFieldFixed(DK_W, 1); } }
/** * A stream based mapping from character codes to CID's. * * <p>The data in the stream defines the mapping from character codes to a font number and a * character selector. The data must follow the syntax defined in Adobe Technical Note #5014, Adobe * CMap and CIDFont Files Specification. */ public abstract class StreamBasedCMap extends CMap { /** The meta class implementation */ public static class MetaClass extends CMap.MetaClass { protected MetaClass(Class instanceClass) { super(instanceClass); } } public static final COSName DK_CIDSystemInfo = COSName.constant("CIDSystemInfo"); public static final COSName DK_CMapName = COSName.constant("CMapName"); public static final COSName DK_UseCMap = COSName.constant("UseCMap"); public static final COSName DK_WMode = COSName.constant("WMode"); /** The meta class instance */ public static final MetaClass META = new MetaClass(MetaClass.class.getDeclaringClass()); private Map<COSName, COSObject> definitions = new HashMap<COSName, COSObject>(); /** The maps from bytes to CID's */ private List maps = new ArrayList(); /** The notdef maps */ private List notdefs = new ArrayList(); /** The codespace ranges */ private CMapRange[][] ranges = new CMapRange[4][0]; /** @param object */ protected StreamBasedCMap(COSObject object) { super(object); } protected void addDefinition(COSName key, COSObject value) { definitions.put(key, value); } protected void addMap(CMapMap map) { maps.add(map); } protected void addNotdef(CMapMap notdef) { notdefs.add(notdef); } protected void addRange(CMapRange range) { int count = range.getByteCount(); CMapRange[] rangeArray = ranges[count]; CMapRange[] tempArray = new CMapRange[rangeArray.length + 1]; System.arraycopy(rangeArray, 0, tempArray, 0, rangeArray.length); tempArray[rangeArray.length] = range; ranges[count] = tempArray; } protected boolean checkPrefix(byte[] bytes, int count) { for (int k = 0; k < ranges.length; k++) { CMapRange[] rangeArray = ranges[k]; for (int i = 0; i < rangeArray.length; i++) { CMapRange range = rangeArray[i]; if (range.checkPrefix(bytes, count)) { return true; } } } return false; } protected boolean checkRange(byte[] bytes, int count) { if (count >= ranges.length) { return false; } CMapRange[] rangeArray = ranges[count]; for (int i = 0; i < rangeArray.length; i++) { CMapRange range = rangeArray[i]; if (range.checkRange(bytes, count)) { return true; } } return false; } protected void do_beginbfchar(CSOperation operation) { // no op, ignore size } protected void do_beginbfrange(CSOperation operation) { // no op, ignore size } protected void do_begincidchar(CSOperation operation) { // no op, ignore size } protected void do_begincidrange(CSOperation operation) { // no op, ignore size } /** */ protected void do_begincmap(CSOperation operation) { // this is a no op } /** */ protected void do_begincodespacerange(CSOperation operation) { // no op, ignore size } /** */ protected void do_beginnotdefchar(CSOperation operation) { // no op, ignore size } /** */ protected void do_beginnotdefrange(CSOperation operation) { // no op, ignore size } protected void do_def(CSOperation operation) { // define key / value association Iterator it = operation.getOperands(); COSObject operand = COSNull.NULL; if (it.hasNext()) { operand = (COSObject) it.next(); } COSDictionary dict = operand.asDictionary(); if (dict == null) { COSName key = operand.asName(); if (key == null) { return; } COSObject value = COSNull.NULL; if (it.hasNext()) { value = (COSObject) it.next(); } addDefinition(key, value); } else { Iterator<Map.Entry<COSName, COSObject>> eit = dict.entryIterator(); while (eit.hasNext()) { Map.Entry<COSName, COSObject> entry = eit.next(); COSName key = entry.getKey(); COSObject value = entry.getValue(); addDefinition(key, value); } } } /** */ protected void do_endbfchar(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSObject destination = (COSObject) it.next(); CMapCharMap map; if (destination instanceof COSString) { byte[] destBytes = ((COSString) destination).byteValue(); if (destBytes.length > 2) { // this is special to /ToUnicode maps map = new CMapBFCharStringMap(start.byteValue(), destBytes); } else { map = new CMapBFCharCodeMap(start.byteValue(), destBytes); } } else { map = new CMapBFCharNameMap(start.byteValue(), (COSName) destination); } addMap(map); } } /** */ protected void do_endbfrange(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSString end = (COSString) it.next(); COSObject destination = (COSObject) it.next(); CMapRangeMap map; if (destination instanceof COSString) { byte[] destBytes = ((COSString) destination).byteValue(); if (destBytes.length > 2) { // this is special to /ToUnicode maps map = new CMapBFRangeStringMap( start.byteValue(), end.byteValue(), ((COSString) destination).byteValue()); } else { map = new CMapBFRangeCodeMap( start.byteValue(), end.byteValue(), ((COSString) destination).byteValue()); } } else { COSArray array = destination.asArray(); if (array.get(0) instanceof COSString) { // this is special to /ToUnicode maps map = new CMapBFRangeStringArrayMap( start.byteValue(), end.byteValue(), (COSArray) destination); } else { map = new CMapBFRangeNameArrayMap( start.byteValue(), end.byteValue(), (COSArray) destination); } } addMap(map); } } /** */ protected void do_endcidchar(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSInteger destination = (COSInteger) it.next(); CMapCharMap map = new CMapCIDCharCodeMap(start.byteValue(), destination.intValue()); addMap(map); } } /** */ protected void do_endcidrange(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSString end = (COSString) it.next(); COSInteger destination = (COSInteger) it.next(); CMapRangeMap map = new CMapCIDRangeCodeMap(start.byteValue(), end.byteValue(), destination.intValue()); addMap(map); } } /** */ protected void do_endcmap(CSOperation operation) { // this is a no op } /** */ protected void do_endcodespacerange(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString startString = (COSString) it.next(); if (!it.hasNext()) { break; } COSString endString = (COSString) it.next(); CMapRange range = new CMapRange(startString.byteValue(), endString.byteValue()); addRange(range); } } /** */ protected void do_endnotdefchar(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSInteger destination = (COSInteger) it.next(); CMapCharMap map = new CMapCIDCharCodeMap(start.byteValue(), destination.intValue()); addNotdef(map); } } /** */ protected void do_endnotdefrange(CSOperation operation) { Iterator it = operation.getOperands(); while (it.hasNext()) { COSString start = (COSString) it.next(); COSString end = (COSString) it.next(); COSInteger destination = (COSInteger) it.next(); CMapRangeMap map = new CMapNotDefRangeMap(start.byteValue(), end.byteValue(), destination.intValue()); addNotdef(map); } } /** */ protected void do_usecmap(CSOperation operation) { // todo 2 cmap not yet supported } /** */ protected void do_usefont(CSOperation operation) { // not needed and not yet supported } @Override public char[] getChars(int codepoint) { for (Iterator it = maps.iterator(); it.hasNext(); ) { CMapMap map = (CMapMap) it.next(); char[] result = map.toChars(codepoint); if (result != null) { return result; } } return null; } @Override public int getDecoded(int codepoint) { for (Iterator it = maps.iterator(); it.hasNext(); ) { CMapMap map = (CMapMap) it.next(); int result = map.toCID(codepoint); if (result != 0) { return result; } } return CharacterSelector.NotdefCID; } public COSObject getDefinition(COSName key) { COSObject result = definitions.get(key); if (result == null) { return COSNull.NULL; } return result; } @Override public int getEncoded(int character) { for (Iterator it = maps.iterator(); it.hasNext(); ) { CMapMap map = (CMapMap) it.next(); int result = map.toCodepoint(character); if (result != 0) { return result; } } return CharacterSelector.NotdefCID; } @Override public int getNextDecoded(InputStream is) throws IOException { return getDecoded(getNextEncoded(is)); } @Override public int getNextEncoded(InputStream is) throws IOException { is.mark(4); byte[] bytes = new byte[4]; int count = 0; while (count < 4) { int nextByte = is.read(); if (nextByte == -1) { return -1; } bytes[count++] = (byte) nextByte; if (checkRange(bytes, count)) { return toInt(bytes, 0, count); } } is.reset(); // invalid code, try to determine number of bytes to consume bytes = new byte[4]; count = 0; while (count < 4) { is.mark(1); int nextByte = is.read(); if (nextByte == -1) { return -1; } bytes[count++] = (byte) nextByte; if (!checkPrefix(bytes, count)) { // todo 1 this is not correct - must pad to next range size is.reset(); count--; return toInt(bytes, 0, count); } } return -1; } /* * (non-Javadoc) * * @see * de.intarsys.pdf.content.IContentStreamVisitor#visitFromContentStream( * de.intarsys.pdf.content.CSContent) */ protected void initializeFromContent(CSContent content) { int len = content.size(); for (int i = 0; i < len; i++) { CSOperation operation = content.getOperation(i); initializeFromOperation(operation); } } protected void initializeFromOperation(CSOperation operation) { if (operation.matchesOperator(CMapOperator.CMO_beginbfchar)) { do_beginbfchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_beginbfrange)) { do_beginbfrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_begincidchar)) { do_begincidchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_begincidrange)) { do_begincidrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_begincmap)) { do_begincmap(operation); } else if (operation.matchesOperator(CMapOperator.CMO_begincodespacerange)) { do_begincodespacerange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_beginnotdefchar)) { do_beginnotdefchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_beginnotdefrange)) { do_beginnotdefrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endbfchar)) { do_endbfchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endbfrange)) { do_endbfrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endcidchar)) { do_endcidchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endcidrange)) { do_endcidrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endcmap)) { do_endcmap(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endcodespacerange)) { do_endcodespacerange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endnotdefchar)) { do_endnotdefchar(operation); } else if (operation.matchesOperator(CMapOperator.CMO_endnotdefrange)) { do_endnotdefrange(operation); } else if (operation.matchesOperator(CMapOperator.CMO_usecmap)) { do_usecmap(operation); } else if (operation.matchesOperator(CMapOperator.CMO_usefont)) { do_usefont(operation); } else if (operation.matchesOperator(CMapOperator.CMO_def)) { do_def(operation); } else { // unknown operator } } @Override public void putNextDecoded(OutputStream os, int character) throws IOException { // write cid value high byte first os.write((character >> 8) & 0xff); os.write(character & 0xff); } @Override public void putNextEncoded(OutputStream os, int codepoint) throws IOException { // write cid value high byte first os.write((codepoint >> 8) & 0xff); os.write(codepoint & 0xff); } }
/** The logical AcroForm hosted in a PDF document. */ public class PDAcroForm extends PDAcroFormNode { /** The meta class implementation */ public static class MetaClass extends PDAcroFormNode.MetaClass { protected MetaClass(Class instanceClass) { super(instanceClass); } @Override protected COSBasedObject doCreateCOSBasedObject(COSObject object) { return new PDAcroForm(object); } @Override protected MetaClass doDetermineClass(COSObject object) { if (!(object instanceof COSDictionary)) { return null; } return this; } } /** The name of the fields entry. */ public static final COSName DK_Fields = COSName.constant("Fields"); // //$NON-NLS-1$ /** The name of the NeedApperances entry. */ public static final COSName DK_NeedAppearances = COSName.constant("NeedAppearances"); // //$NON-NLS-1$ /** * The name of the SignatureFlags entry. * * <p>For a list of possible flags: * * @see de.intarsys.pdf.pd.AcroFormSigFlags */ public static final COSName DK_SigFlags = COSName.constant("SigFlags"); // $NON-NLS-1$ /** The name of the CalculationOrder entry. */ public static final COSName DK_CO = COSName.constant("CO"); // $NON-NLS-1$ /** The name of the XFAResources entry. */ public static final COSName DK_XFA = COSName.constant("XFA"); // //$NON-NLS-1$ /** The meta class instance */ public static final MetaClass META = new MetaClass(MetaClass.class.getDeclaringClass()); private AcroFormSigFlags sigFlags; private List cachedFields; private boolean fieldsChecked = false; protected PDAcroForm(COSObject object) { super(object); } /* * (non-Javadoc) * * @see de.intarsys.pdf.pd.PDAcroFormNode#addField(de.intarsys.pdf.pd.PDAcroFormField) */ @Override public void addField(PDAcroFormField field) { checkFields(); cosAddField(field.cosGetDict()); field.setParent(null); if (field.isTypeSig()) { getSigFlags().setSignatureExists(true); } } protected void checkFields() { // be careful not to propagate any changes -> deadlock prone synchronized (this) { if (fieldsChecked) { return; } fieldsChecked = true; // reconstruct form fields if there is an empty fields array COSArray fields = cosGetField(DK_Fields).asArray(); if ((fields != null) && (fields.size() == 0)) { COSArray cosFields = reconstruct(getDoc()); cosGetDict().basicPutSilent(DK_Fields, cosFields); } } } private void cosAddField(COSDictionary field) { COSArray cosFields = cosGetField(DK_Fields).asArray(); if (cosFields == null) { cosFields = COSArray.create(); cosFields.beIndirect(); cosSetField(DK_Fields, cosFields); } cosFields.add(field); } /** * The /XFA entry of this. * * @return The /XFA entry of this. */ public COSObject cosGetXfa() { return cosGetField(DK_XFA); } protected void cosSetSigFlags(int newFlags) { if (newFlags != 0) { // default cosSetField(DK_SigFlags, COSInteger.create(newFlags)); } else { cosRemoveField(DK_SigFlags); } } /* * (non-Javadoc) * * @see de.intarsys.pdf.pd.PDAcroFormNode#getAcroForm() */ @Override public PDAcroForm getAcroForm() { return this; } /** * A collection containing the PDAcroFormField objects in their calculation order or null if no /C * events are defined. * * @return A collection containing the PDAcroFormField objects in their calculation order or null * if no /C events are defined. */ public List getCalculationOrder() { return getPDObjects(DK_CO, PDAcroFormField.META, false); } /** * The default resource dictionary. * * <p>With 1.5 this is no longer supported as an entry in field dictionaries, only in the form * itself. * * @return The default resource dictionary. */ public PDResources getDefaultResources() { return (PDResources) PDResources.META.createFromCos(cosGetField(DK_DR)); } /** * A list of all direct {@link PDAcroFormField} instances associated with this object. * * @return A list of all direct {@link PDAcroFormField} instances associated with this object. */ public List getFields() { checkFields(); if (cachedFields == null) { cachedFields = getPDObjects(DK_Fields, PDAcroFormField.META, true); } return cachedFields; } /* * (non-Javadoc) * * @see de.intarsys.pdf.pd.PDObject#getGenericChildren() */ @Override public List getGenericChildren() { return getFields(); } /** * <code>true</code> if /NeedAppearances is set for this form. * * @return <code>true</code> if /NeedAppearances is set for this form. */ public boolean getNeedAppearances() { return getFieldBoolean(DK_NeedAppearances, false); } /** * The flags associated with an AcroForm. * * @return The flags associated with an AcroForm. */ public AcroFormSigFlags getSigFlags() { if (sigFlags == null) { sigFlags = new AcroFormSigFlags(this); } return sigFlags; } /* * (non-Javadoc) * * @see de.intarsys.pdf.pd.PDAcroFormNode#invalidateCaches() */ @Override public void invalidateCaches() { super.invalidateCaches(); COSArray cosFields = cosGetField(DK_Fields).asArray(); if (cosFields != null) { cosFields.removeObjectListener(this); } cachedFields = null; } /** * <code>true</code> if this form has a signature field. This is NOT the same as the flag in the * SigFlags entry but may be used to compute this entry. * * @return <code>true</code> if this form has a signature field. */ public boolean isSignatureExists() { for (Iterator i = collectLeafFields().iterator(); i.hasNext(); ) { PDAcroFormField field = (PDAcroFormField) i.next(); if (field.isTypeSig()) { return true; } } return false; } /** * <code>true</code> if this form has a signed signature field. * * @return <code>true</code> if this form has a signed signature field. */ public boolean isSigned() { for (Iterator i = collectLeafFields().iterator(); i.hasNext(); ) { PDAcroFormField field = (PDAcroFormField) i.next(); if (field.isTypeSig() && ((PDAFSignatureField) field).isSigned()) { return true; } } return false; } /** * This method scans the document for all WidgetAnnotation objects. * * <p>This is done because some writer do not create a correct list of all PDAcroFormField objects * in the AcroForm. In the case that the list of children is empty, we go and search ourselves for * candidates... * * @param doc The document to reconstruct. */ protected COSArray reconstruct(PDDocument doc) { COSArray result = COSArray.create(); if (doc == null) { return result; } PDPageTree pageTree = doc.getPageTree(); if (pageTree == null) { return result; } boolean signatureExists = false; for (PDPage page = pageTree.getFirstPage(); page != null; page = page.getNextPage()) { List annotations = page.getAnnotations(); if (annotations == null) { continue; } for (Iterator it = annotations.iterator(); it.hasNext(); ) { PDAnnotation annot = (PDAnnotation) it.next(); if (annot.isWidgetAnnotation()) { COSDictionary cosAnnot = annot.cosGetDict(); result.basicAddSilent(cosAnnot); cosAnnot.basicRemoveSilent(PDAcroFormField.DK_Parent); signatureExists |= cosAnnot.get(PDAcroFormField.DK_FT).equals(PDAcroFormField.CN_FT_Sig); } } } if (signatureExists) { int flags = getFieldInt(PDAcroForm.DK_SigFlags, 0); flags |= AcroFormSigFlags.Bit_AppendOnly | AcroFormSigFlags.Bit_SignatureExists; cosGetDict().basicPutSilent(PDAcroForm.DK_SigFlags, COSInteger.create(flags)); } return result; } /* * (non-Javadoc) * * @see de.intarsys.pdf.pd.PDAcroFormNode#removeField(de.intarsys.pdf.pd.PDAcroFormField) */ @Override public boolean removeField(PDAcroFormField field) { getFields().remove(field); COSArray cosFields = cosGetField(DK_Fields).asArray(); if (cosFields == null) { return false; } boolean removed = cosFields.remove(field.cosGetDict()); getSigFlags().setSignatureExists(isSignatureExists()); return removed; } protected void setCalculationOrder(List newCalculationOrder) { setPDObjects(DK_CO, newCalculationOrder); } /** * Assign the default resource dictionary to be used with the form. * * @param newResources The new default resource dictionary. */ public void setDefaultResources(PDResources newResources) { setFieldObject(DK_DR, newResources); } /* * (non-Javadoc) * * @see de.intarsys.pdf.pd.PDObject#setGenericParent(de.intarsys.pdf.pd.PDObject) */ @Override public void setGenericParent(PDObject parent) { throw new IllegalStateException("AcroForm may not have a parent"); // $NON-NLS-1$ } /** * Set the /NeedAppearances field for the form. When <code>true</code>, a viewer application is * required to re-create the visual appearances for the fields. * * @param newNeedAppearances The new state for /NewwdAppearances */ public void setNeedAppearances(boolean newNeedAppearances) { if (newNeedAppearances) { cosSetField(DK_NeedAppearances, COSTrue.create()); } else { // default cosRemoveField(DK_NeedAppearances); } } @Override public String toString() { return "AcroForm " + super.toString(); // $NON-NLS-1$ } }
/** A PDF font object. */ public abstract class PDFont extends PDObject { /** The meta class implementation */ public static class MetaClass extends PDObject.MetaClass { protected MetaClass(Class instanceClass) { super(instanceClass); } /* * (non-Javadoc) * * @see * de.intarsys.pdf.cos.COSBasedObject.MetaClass#doDetermineClass(de. * intarsys.pdf.cos.COSObject) */ @Override protected COSBasedObject.MetaClass doDetermineClass(COSObject object) { COSDictionary dict; dict = object.asDictionary(); if (dict == null) { throw new IllegalArgumentException("font object is not a COSDictionary as required"); } COSName type = dict.get(DK_Type).asName(); if (type == null) { throw new IllegalArgumentException("Dictionary has no type"); } if (!type.equals(CN_Type_Font)) { throw new IllegalArgumentException("type <" + type + "> is not a valid font type"); } COSName subtype = dict.get(DK_Subtype).asName(); if (subtype == null) { throw new IllegalArgumentException("font not identified by subtype"); } if (subtype.equals(CN_Subtype_Type1)) { return PDFontType1.META; } else if (subtype.equals(CN_Subtype_TrueType)) { if (dict.get(DK_FontDescriptor).isNull()) { /* * treat as if Type1 was specified, because that's probably * what the creator meant; further processing would yield * wrong results anyway as FontDescriptor is a required * entry for TrueType fonts */ return PDFontType1.META; } return PDFontTrueType.META; } else if (subtype.equals(CN_Subtype_MMType1)) { return PDFontMMType1.META; } else if (subtype.equals(CN_Subtype_Type0)) { return PDFontType0.META; } else if (subtype.equals(CN_Subtype_Type3)) { return PDFontType3.META; } else if (subtype.equals(CN_Subtype_CIDFontType0)) { return CIDFontType0.META; } else if (subtype.equals(CN_Subtype_CIDFontType2)) { return CIDFontType2.META; } throw new IllegalArgumentException("font subtype <" + subtype + "> not supported"); } @Override public Class getRootClass() { return PDFont.class; } } private static final Attribute ATTR_FONTFAMILY = new Attribute("fontfamily"); private static final Attribute ATTR_FONTNAME = new Attribute("fontname"); private static final Attribute ATTR_FONTSTYLE = new Attribute("fontstyle"); public static final COSName CN_Subtype_CIDFontType0 = COSName.constant("CIDFontType0"); // $NON-NLS-1$ public static final COSName CN_Subtype_CIDFontType2 = COSName.constant("CIDFontType2"); // $NON-NLS-1$ public static final COSName CN_Subtype_MMType1 = COSName.constant("MMType1"); // $NON-NLS-1$ public static final COSName CN_Subtype_TrueType = COSName.constant("TrueType"); // $NON-NLS-1$ public static final COSName CN_Subtype_Type0 = COSName.constant("Type0"); // $NON-NLS-1$ public static final COSName CN_Subtype_Type1 = COSName.constant("Type1"); // $NON-NLS-1$ public static final COSName CN_Subtype_Type3 = COSName.constant("Type3"); // $NON-NLS-1$ public static final COSName CN_Type_Font = COSName.constant("Font"); // $NON-NLS-1$ public static final COSName DK_BaseFont = COSName.constant("BaseFont"); // $NON-NLS-1$ public static final COSName DK_Encoding = COSName.constant("Encoding"); // $NON-NLS-1$ public static final COSName DK_FirstChar = COSName.constant("FirstChar"); // $NON-NLS-1$ public static final COSName DK_FontDescriptor = COSName.constant("FontDescriptor"); // $NON-NLS-1$ public static final COSName DK_LastChar = COSName.constant("LastChar"); // $NON-NLS-1$ public static final COSName DK_Name = COSName.constant("Name"); // $NON-NLS-1$ public static final COSName DK_ToUnicode = COSName.constant("ToUnicode"); // $NON-NLS-1$ public static final COSName DK_Widths = COSName.constant("Widths"); // $NON-NLS-1$ /** The meta class instance */ public static final MetaClass META = new MetaClass(MetaClass.class.getDeclaringClass()); private static CMap UNDEFINED = new IdentityCMap(); public static String getFontFamilyName(String name) { if (name == null) { return null; } int posPlus = name.indexOf('+'); if (posPlus > 0) { name = name.substring(posPlus + 1); } int posMinus = name.lastIndexOf('-'); if (posMinus > 0) { name = name.substring(0, posMinus); } int posComma = name.indexOf(','); if (posComma > 0) { name = name.substring(0, posComma); } return name; } /** * extracts the "name" portion from the given font name string * * @param name a font name * @return font name's "name" portion */ public static String getFontName(String name) { if (name == null) { return null; } int posPlus = name.indexOf('+'); if (posPlus > 0) { name = name.substring(posPlus + 1); } return name; } /** * extracts the "style" portion from the given font name * * @param name a font name * @return font name's "style" portion */ public static PDFontStyle getFontStyle(String name) { if (name == null) { return PDFontStyle.REGULAR; } int posMinus = name.lastIndexOf('-'); if (posMinus > 0) { name = name.substring(posMinus + 1); } int posComma = name.indexOf(','); if (posComma > 0) { name = name.substring(posComma + 1).trim(); } return PDFontStyle.getFontStyle(name); } // the encoding used for this font private Encoding cachedEncoding; // some detail information about the font private PDFontDescriptor cachedFontDescriptor; private CMap cachedToUnicode = UNDEFINED; /** * Create the receiver class from an already defined {@link COSDictionary}. NEVER use the * constructor directly. * * @param object the PDDocument containing the new object */ protected PDFont(COSObject object) { super(object); } /* * (non-Javadoc) * * @see de.intarsys.pdf.pd.PDObject#cosGetExpectedType() */ @Override protected COSName cosGetExpectedType() { return CN_Type_Font; } /** * The font descriptor for a builtin font. * * @return The font descriptor for a builtin font * @throws IllegalStateException */ protected PDFontDescriptor createBuiltinFontDescriptor() { // this may happen, there are strange documents around that depend on // certain TrueTypes to be present. // Note from EHK: I'm treating some strange TrueTypes as Type1 now, so // maybe doesn't happen anymore return null; } /** * Fill the correct width values into an array of glyph widths for a builtin font. This is a valid * implementation for type1 builtin fonts only. * * @param result The array to hold the glyph widths. * @return The array of widths for the defined range of chars in the font */ protected int[] createBuiltInWidths(int[] result) { return result; } /** * Fill an array of glyph widths from the definition prepared by the font dictionary. The widths * in the font are declared in the range from the first supported code point to the last code * point. The code point selects a glyph out of the font depending on the encoding by the font, * the corresponding entry in the width array defines its width. * * @param result The array to hold the correct widths. * @param array The COSArray defining the widths. * @return The array of widths for the defined range of chars in the font */ protected int[] createDeclaredWidths(int[] result, COSArray array) { int i = getFirstChar(); for (Iterator it = array.iterator(); it.hasNext(); ) { COSNumber width = ((COSObject) it.next()).asNumber(); if (width != null) { result[i] = width.intValue(); } i++; } return result; } /** * get an encoding object that describes this fonts NATIVE encoding (if any) * * @return an encoding */ protected Encoding createDefaultEncoding() { return StandardEncoding.UNIQUE; } /** * Create the encoding for the font. The encoding is specified either "by default", as a known * encoding name or a completely user defined difference encoding. * * <p>This is redefined for composite fonts, which use a different implementation. * * @return The encoding object for the font. * @throws IllegalArgumentException When the encoding defined in the font is not supported. */ protected Encoding createEncoding() { COSObject encoding = cosGetField(PDFont.DK_Encoding); if (encoding.isNull()) { return createDefaultEncoding(); } if (encoding instanceof COSName) { try { return Encoding.createNamed((COSName) encoding); } catch (Exception e) { // found PDF where the base name was /NULL... return createDefaultEncoding(); } } if (encoding instanceof COSDictionary) { return DifferenceEncoding.create((COSDictionary) encoding, this); } throw new IllegalArgumentException("encoding not supported"); } protected int createFirstChar() { return 0; } /** @return the lazily created font descriptor of this font */ protected PDFontDescriptor createFontDescriptor() { COSObject base = cosGetField(DK_FontDescriptor); if (base.isNull()) { return createBuiltinFontDescriptor(); } return (PDFontDescriptorEmbedded) PDFontDescriptorEmbedded.META.createFromCos(base); } protected int createLastChar() { return 255; } /** * construct a array of glyph widths for the current font the widths may be defined in the /Widths * entry of the pdf font or in the font metric (afm) of a builtin font * * @return the array of widths for the defined range of chars in the font */ protected int[] createWidths() { int[] result = new int[256]; int missing = getMissingWidth(); for (int i = 0; i < 256; i++) { result[i] = missing; } COSArray base = cosGetField(DK_Widths).asArray(); if (base == null) { return createBuiltInWidths(result); } return createDeclaredWidths(result, base); } public void dumpFontFile(File file) { PDFontDescriptorEmbedded fd = (PDFontDescriptorEmbedded) getFontDescriptor(); if (fd == null) { return; } byte[] data = fd.getFontFile(); if (data == null) { data = fd.getFontFile2(); } if (data == null) { data = fd.getFontFile3(); } if (data == null) { return; } FileOutputStream os = null; try { os = new FileOutputStream(file); os.write(data); } catch (Exception e) { // ignore } finally { StreamTools.close(os); } } /** @return the base font for this font dictionary */ public COSName getBaseFont() { return cosGetField(DK_BaseFont).asName(); } /** * The encoding of the glyphs in the font * * @return The encoding of the glyphs in the font */ public Encoding getEncoding() { if (cachedEncoding == null) { cachedEncoding = createEncoding(); } return cachedEncoding; } /** * The first (encoded) codepoint defined in the font. * * @return The first (encoded) codepoint defined in the font */ public int getFirstChar() { COSNumber base = cosGetField(DK_FirstChar).asInteger(); if (base == null) { return createFirstChar(); } return base.intValue(); } /** * The {@link PDFontDescriptor} object for this font. * * @return The {@link PDFontDescriptor} object for this font */ public PDFontDescriptor getFontDescriptor() { if (cachedFontDescriptor == null) { cachedFontDescriptor = createFontDescriptor(); } return cachedFontDescriptor; } public String getFontFamilyName() { try { PDFontDescriptor fontDescriptor = getFontDescriptor(); if (fontDescriptor != null) { String result = fontDescriptor.getFontFamily(); if (result != null) { return result; } } } catch (Exception e) { // } return PDFont.getFontFamilyName(getBaseFont().stringValue()); } public String getFontName() { return getBaseFont().stringValue(); } public String getFontNameNormalized() { return PDFont.getFontName(getFontName()); } public PDFontStyle getFontStyle() { return getFontStyle(getBaseFont().stringValue()); } public abstract String getFontType(); /** * The {@link PDGlyphs} instance for the encoded codepoint. * * @param codepoint * @return The {@link PDGlyphs} instance for the encoded codepoint. */ public abstract PDGlyphs getGlyphsEncoded(int codepoint); /** * The glyph width of an encoded codepoint in the font. * * <p>In the standard case for single byte encoded fonts, the codepoint is the index in the * /Widths array, holding the glyph width. * * <p>For multibyte fonts, see {@link PDFontType0}. * * @param codepoint The codepoint * @return The glyph width of an encoded codepoint in the font */ public abstract int getGlyphWidthEncoded(int codepoint); /** @return the last (encoded) codepoint defined in the font */ public int getLastChar() { COSNumber base = cosGetField(DK_LastChar).asInteger(); if (base == null) { return createLastChar(); } return base.intValue(); } public String getLookupFontFamilyName() { String result = (String) getAttribute(ATTR_FONTFAMILY); if (result == null) { result = getFontFamilyName(); setAttribute(ATTR_FONTFAMILY, result); } return result; } public String getLookupFontName() { String result = (String) getAttribute(ATTR_FONTNAME); if (result == null) { result = getFontNameNormalized(); setAttribute(ATTR_FONTNAME, result); } return result; } public PDFontStyle getLookupFontStyle() { PDFontStyle result = (PDFontStyle) getAttribute(ATTR_FONTSTYLE); if (result == null) { result = getFontStyle(); setAttribute(ATTR_FONTSTYLE, result); } return result; } /** * This is a special mapping that is used if we have a font on the physical device using a * Macintosh Roman encoding character map. * * <p>See PDF docs, "Encodings for True Type fonts". * * @param codePoint * @return The unicode value for <code>codePoint</code> */ public int getMacintoshRomanCode(int codePoint) { String glyphName = getEncoding().getGlyphName(codePoint); return MacOSRomanEncoding.UNIQUE.getEncoded(glyphName); } /** @return the width we should use for a missing/undefined glyph width */ public int getMissingWidth() { if (getFontDescriptor() == null) { return 0; } return getFontDescriptor().getMissingWidth(); } /** * The {@link PDGlyphs} denoted by the next byte or bytes in the input stream. * * <p>For single byte encoded fonts a single byte is read and the associated {@link PDGlyphs} is * returned. For CID fonts, the appropriate number of bytes is read form the input stream to * select the {@link PDGlyphs}. * * @param is The input stream on the {@link COSString} bytes * @return The next {@link PDGlyphs} referenced by the input stream. * @throws IOException */ public abstract PDGlyphs getNextGlyphsEncoded(ByteArrayInputStream is) throws IOException; public CMap getToUnicode() { if (cachedToUnicode == UNDEFINED) { try { cachedToUnicode = (CMap) CMap.META.createFromCos(cosGetField(DK_ToUnicode)); } catch (RuntimeException e) { cachedToUnicode = null; throw e; } } return cachedToUnicode; } @Override public void invalidateCaches() { super.invalidateCaches(); cachedEncoding = null; cachedFontDescriptor = null; cachedToUnicode = UNDEFINED; } /** * Answer true if this font's program is embedded within the document. * * @return Answer true if this font's program is embedded within the document. */ public boolean isEmbedded() { // shortcut for builtin fonts COSObject base = cosGetField(DK_FontDescriptor); if (base.isNull() && !(this instanceof PDFontType0)) { return false; } if (getFontDescriptor() == null) { return false; } if (getFontDescriptor().getFontFile() != null) { return true; } if (getFontDescriptor().getFontFile2() != null) { return true; } if (getFontDescriptor().getFontFile3() != null) { return true; } return false; } /** * Answer true if this is one of the 14 standard fonts. TODO 2 implement * * @return Answer true if this is one of the 14 standard fonts. */ public boolean isStandardFont() { return false; } /** * Answer true if this font is partially embedded in the document. * * @return Answer true if this font is partially embedded in the document. */ public boolean isSubset() { byte[] name = getBaseFont().byteValue(); if (name.length > 7) { return name[6] == '+'; } // filter some more ill defined fonts if (getFirstChar() > 32) { return true; } if (getLastChar() < 128) { return true; } return false; } public void setBaseFont(String name) { setFieldName(DK_BaseFont, name); } /** * set an encoding for the font * * @param newFontEncoding the new encoding to use */ public void setEncoding(Encoding newFontEncoding) { cachedEncoding = newFontEncoding; if (newFontEncoding != null) { COSObject ref = cachedEncoding.cosGetObject(); if (ref == null || ref.isNull()) { cosRemoveField(DK_Encoding); } else { cosSetField(DK_Encoding, ref); } } else { cosRemoveField(DK_Encoding); } } public void setFontDescriptor(PDFontDescriptor descriptor) { cachedFontDescriptor = descriptor; setFieldObject(DK_FontDescriptor, cachedFontDescriptor); } public void setLookupFontFamilyName(String name) { if (name == null) { return; } setAttribute(ATTR_FONTFAMILY, name); } public void setLookupFontName(String name) { if (name == null) { return; } setAttribute(ATTR_FONTNAME, name); } public void setLookupFontStyle(PDFontStyle newStyle) { if (newStyle == null) { return; } setAttribute(ATTR_FONTSTYLE, newStyle); } /** * set the to unicode mapping * * @param newToUnicode the new to unicode to use */ public void setToUnicode(CMap newToUnicode) { cachedToUnicode = UNDEFINED; setFieldObject(DK_ToUnicode, newToUnicode); } @Override public String toString() { return cosGetSubtype().stringValue() + "-Font " + getBaseFont().toString() + " (" + getEncoding() + ")"; } }
/** * The GoToR action. * * <p>When executed the action focuses a viewer to a new destination. */ public class PDActionGoToR extends PDAction { /** The meta class implementation */ public static class MetaClass extends PDAction.MetaClass { protected MetaClass(Class instanceClass) { super(instanceClass); } @Override protected COSBasedObject doCreateCOSBasedObject(COSObject object) { return new PDActionGoToR(object); } @Override protected COSBasedObject.MetaClass doDetermineClass(COSObject object) { return PDActionGoToR.META; } } /** The meta class instance */ public static final MetaClass META = new MetaClass(MetaClass.class.getDeclaringClass()); public static final COSName CN_ActionType_GoToR = COSName.constant("GoToR"); public static final COSName DK_D = COSName.constant("D"); public static final COSName DK_F = COSName.constant("F"); public static final COSName DK_NewWindow = COSName.constant("NewWindow"); // $NON-NLS-1$ private PDDestination destination; protected PDActionGoToR(COSObject object) { super(object); } @Override public COSName cosGetExpectedActionType() { return CN_ActionType_GoToR; } public PDDestination getDestination() { if (destination == null) { COSObject destObject; if (cosGetObject() instanceof COSDictionary) { destObject = cosGetField(DK_D); } else { destObject = cosGetObject(); } destination = (PDDestination) PDDestination.META.createFromCos(destObject); } return destination; } public File getFile() { File file = null; COSObject cosFileSpec = cosGetField(DK_F); if (cosFileSpec instanceof COSString) { String fileSpec = cosFileSpec.stringValue(); file = new File(PDFFileTools.toOSPath(fileSpec)); } else if (cosFileSpec instanceof COSDictionary) { PDFileSpecification fileSpec = (PDFileSpecification) PDFileSpecification.META.createFromCos(cosFileSpec); String fileString = fileSpec.getFile(); if (fileString != null) { file = new File(PDFFileTools.toOSPath(fileString)); } } return file; } @Override protected void initializeFromCos() { super.initializeFromCos(); } @Override public void invalidateCaches() { destination = null; super.invalidateCaches(); } public boolean isNewWindow() { COSBoolean value = cosGetField(DK_NewWindow).asBoolean(); if (value == null) { return false; } return value.booleanValue(); } }
/** * The standard security handler as specified in the PDF reference. * * <p>Be aware that there is no internal check for permissions. The reason is simply that on the API * level there's nothing that really keeps you from manipulating a PDF document. * * <p>On one hand, changing simply the security relevant parameters won't work as the crypt key is * cached. It is necessary to create and associate a new security handler. Here we could check and * abandon the request if no owner permissions are set. But this is no real problem, as you could * read the complete document with user permissions and as such simply copy the root. * * <p>So we didn't even care as this would pollute the implementation while providing only * superficial benefits. */ public abstract class StandardSecurityHandler extends AbstractSecurityHandler implements IAccessPermissionsSupport { /** * The default value for the access permission flags. * * <p>Everything is allowed, only the reserved flags are zero. */ public static final int DEFAULT_ACCESS_PERMISSIONS = 0xFFFFFFFC; public static final COSName DK_EncryptMetadata = COSName.constant("EncryptMetadata"); // $NON-NLS-1$ public static final COSName DK_O = COSName.constant("O"); // $NON-NLS-1$ public static final COSName DK_P = COSName.constant("P"); // $NON-NLS-1$ public static final COSName DK_R = COSName.constant("R"); // $NON-NLS-1$ public static final COSName DK_U = COSName.constant("U"); // $NON-NLS-1$ /** The padding sequence as defined in the spec. */ protected static byte[] PADDING = new byte[] { (byte) 0x28, (byte) 0xBF, (byte) 0x4E, (byte) 0x5E, (byte) 0x4E, (byte) 0x75, (byte) 0x8A, (byte) 0x41, (byte) 0x64, (byte) 0x00, (byte) 0x4E, (byte) 0x56, (byte) 0xFF, (byte) 0xFA, (byte) 0x01, (byte) 0x08, (byte) 0x2E, (byte) 0x2E, (byte) 0x00, (byte) 0xB6, (byte) 0xD0, (byte) 0x68, (byte) 0x3E, (byte) 0x80, (byte) 0x2F, (byte) 0x0C, (byte) 0xA9, (byte) 0xFE, (byte) 0x64, (byte) 0x53, (byte) 0x69, (byte) 0x7A }; /** A dummy padding sequence for the revision 3 variant. */ protected static byte[] USER_R3_PADDING = new byte[] { (byte) 0x28, (byte) 0xBF, (byte) 0x4E, (byte) 0x5E, (byte) 0x4E, (byte) 0x75, (byte) 0x8A, (byte) 0x41, (byte) 0x64, (byte) 0x00, (byte) 0x28, (byte) 0xBF, (byte) 0x4E, (byte) 0x5E, (byte) 0x4E, (byte) 0x4E }; /** The access permissions currently active */ private IAccessPermissions accessPermissions = AccessPermissionsFull.get(); private IAuthenticationHandler authenticationHandler; /** The key that was computed for the security handler upon authentication. */ private byte[] cryptKey; private byte[] owner; private byte[] user; public StandardSecurityHandler() { super(); } public void apply() throws COSSecurityException { // byte[] oPwd = createOwnerPassword(owner, user); COSString o = COSString.create(oPwd); getEncryption().cosSetField(StandardSecurityHandler.DK_O, o); byte[] uPwd = createUserPassword(user); COSString u = COSString.create(uPwd); getEncryption().cosSetField(StandardSecurityHandler.DK_U, u); // create new crypt key setCryptKey(createCryptKey(getUser())); } @Override public void attach(STDocument doc) { super.attach(doc); if (doc == null) { return; } COSEncryption encryption = getEncryption(); encryption.cosSetField(COSEncryption.DK_Filter, StandardSecurityHandlerFactory.CN_Standard); encryption.cosSetField(StandardSecurityHandler.DK_R, COSInteger.create(getRevision())); // apply default permissions getEncryption().setFieldInt(StandardSecurityHandler.DK_P, DEFAULT_ACCESS_PERMISSIONS); } /* * (non-Javadoc) * * @see de.intarsys.pdf.encryption.ISecurityHandler#authenticate() */ public final void authenticate() throws COSSecurityException { // reset permissions setActiveAccessPermissions(AccessPermissionsNone.get()); if (authenticationHandler == null) { authenticationHandler = AuthenticationHandlerFactory.get().createAuthenticationHandler(this); } authenticationHandler.authenticate(this); } public abstract boolean authenticateOwner(byte[] owner) throws COSSecurityException; public abstract boolean authenticateUser(byte[] user) throws COSSecurityException; public int basicGetPermissionFlags() { return getEncryption().getFieldInt(StandardSecurityHandler.DK_P, DEFAULT_ACCESS_PERMISSIONS); } public void basicSetPermissionFlags(int newValue) throws COSSecurityException { if (getEncryption().cosGetDoc() == null) { throw new COSSecurityException("document missing"); } getEncryption().setFieldInt(StandardSecurityHandler.DK_P, newValue); } protected abstract IAccessPermissions createAccessPermissions(); protected abstract byte[] createCryptKey(byte[] password) throws COSSecurityException; protected abstract byte[] createOwnerPassword(byte[] owner, byte[] user) throws COSSecurityException; protected abstract byte[] createUserPassword(byte[] user) throws COSSecurityException; public byte[] decrypt(COSObjectKey key, byte[] bytes) throws COSSecurityException { throw new COSSecurityException("pluggable encryption not supported"); // $NON-NLS-1$ } @Override public void detach(STDocument doc) throws COSSecurityException { if (doc == null) { return; } COSEncryption encryption = getEncryption(); encryption.cosRemoveField(COSEncryption.DK_Filter); encryption.cosRemoveField(StandardSecurityHandler.DK_R); encryption.cosRemoveField(StandardSecurityHandler.DK_P); super.detach(doc); } public byte[] encrypt(COSObjectKey key, byte[] bytes) throws COSSecurityException { throw new COSSecurityException("pluggable encryption not supported"); // $NON-NLS-1$ } /* * (non-Javadoc) * * @see de.intarsys.pdf.encryption.ISecurityHandler#getAccessPermissions() */ public final IAccessPermissions getAccessPermissions() { return accessPermissions; } public IAuthenticationHandler getAuthenticationHandler() { return authenticationHandler; } /* * (non-Javadoc) * * @see de.intarsys.pdf.encryption.ISecurityHandler#getCryptKey() */ public byte[] getCryptKey() { return cryptKey; } protected byte[] getO() { COSString o = getEncryption().cosGetField(DK_O).asString(); if (o != null) { return o.byteValue(); } return null; } protected byte[] getOwner() { return owner; } protected byte[] getPBytes() { int pint = basicGetPermissionFlags(); byte[] result = new byte[4]; result[0] = (byte) (pint & 0xff); pint = pint >> 8; result[1] = (byte) (pint & 0xff); pint = pint >> 8; result[2] = (byte) (pint & 0xff); pint = pint >> 8; result[3] = (byte) (pint & 0xff); return result; } protected byte[] getPermanentFileID() throws COSSecurityException { STDocument stDoc = stGetDoc(); if (stDoc == null) { throw new COSSecurityException("document missing"); } // force creation of file id if (stDoc.getTrailer().cosGetPermanentFileID() == null) { stDoc.getTrailer().updateFileID(); } COSString permanentId = stDoc.getTrailer().cosGetPermanentFileID(); if (permanentId != null) { return permanentId.byteValue(); } return null; } public PermissionFlags getPermissionFlags() { return new PermissionFlags(this); } public abstract int getRevision(); protected byte[] getU() { COSString u = getEncryption().cosGetField(DK_U).asString(); if (u == null) { return null; } return u.byteValue(); } protected byte[] getUser() { return user; } @Override public void initialize(STDocument doc) { super.initialize(doc); setActiveAccessPermissions(AccessPermissionsNone.get()); } public boolean isEncryptMetadata() { return getEncryption().getFieldBoolean(DK_EncryptMetadata, true); } protected byte[] prepareBytes(byte[] bytes) { byte[] padded = new byte[32]; if (bytes == null) { System.arraycopy(PADDING, 0, padded, 0, 32); } else { if (bytes.length > 32) { System.arraycopy(bytes, 0, padded, 0, 32); } else { System.arraycopy(bytes, 0, padded, 0, bytes.length); System.arraycopy(PADDING, 0, padded, bytes.length, 32 - bytes.length); } } return padded; } protected void setActiveAccessPermissions(IAccessPermissions accessPermissions) { this.accessPermissions = accessPermissions; } public void setAuthenticationHandler(IAuthenticationHandler authenticationHandler) { this.authenticationHandler = authenticationHandler; } protected void setCryptKey(byte[] key) throws COSSecurityException { this.cryptKey = key; } public void setEncryptMetadata(boolean value) { getEncryption().setFieldBoolean(DK_EncryptMetadata, value); } protected void setOwner(byte[] owner) { this.owner = owner; } /** * Set new owner password for the {@link ISecurityHandler}. * * @param owner The new owner password. * @throws COSSecurityException */ public void setOwnerPassword(byte[] pOwner) throws COSSecurityException { if (getEncryption().cosGetDoc() == null) { throw new COSSecurityException("document missing"); } owner = pOwner; } protected void setUser(byte[] user) { this.user = user; } /** * Set new user password for the {@link ISecurityHandler}. * * @param user The new user password * @throws COSSecurityException */ public void setUserPassword(byte[] pUser) throws COSSecurityException { if (getEncryption().cosGetDoc() == null) { throw new COSSecurityException("document missing"); } user = pUser; } }