Exemplo n.º 1
0
 public String getDigestMethod() {
   COSName cosDigestMethod = cosGetField(DK_DigestMethod).asName();
   if (cosDigestMethod == null) {
     return DEFAULT_DIGESTMETHOD;
   }
   return cosDigestMethod.stringValue();
 }
Exemplo n.º 2
0
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$
  }
}
Exemplo n.º 5
0
 public void setDigestMethod(String digestMethod) {
   COSName cosDigestMethod = null;
   if (digestMethod != null) {
     cosDigestMethod = COSName.create(digestMethod);
   }
   cosSetField(DK_DigestMethod, cosDigestMethod);
 }
Exemplo n.º 6
0
    /*
     * (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");
    }
Exemplo n.º 7
0
/** 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]));
    }
  }
}
Exemplo n.º 9
0
/** 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);
  }
}
Exemplo n.º 10
0
/**
 * 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);
  }
}
Exemplo n.º 11
0
/** 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$
  }
}
Exemplo n.º 12
0
/** 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()
        + ")";
  }
}
Exemplo n.º 13
0
/**
 * 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;
  }
}