diff options
Diffstat (limited to 'src/main/java/at/gv')
71 files changed, 5868 insertions, 0 deletions
| diff --git a/src/main/java/at/gv/egiz/pdfas/commandline/CommandlineConnectorChooser.java b/src/main/java/at/gv/egiz/pdfas/commandline/CommandlineConnectorChooser.java new file mode 100644 index 0000000..2bc6a58 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/commandline/CommandlineConnectorChooser.java @@ -0,0 +1,167 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.commandline;
 +
 +import at.gv.egiz.pdfas.framework.ConnectorFactory;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
 +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
 +import at.knowcenter.wag.egov.egiz.sig.sigid.HotfixIdFormatter;
 +
 +/**
 + * Encapsulates the logic of choosing the correct connector for the commandline
 + * that can later be created using the ConnectorFactory.
 + * 
 + * @author wprinz
 + */
 +public class CommandlineConnectorChooser
 +{
 +  /**
 +   * The log.
 +   */
 +  private static Log log = LogFactory.getLog(CommandlineConnectorChooser.class);
 +
 +  protected static final String BKU = "bku"; //$NON-NLS-1$
 +
 +  protected static final String MOA = "moa"; //$NON-NLS-1$
 +  
 +  public static boolean needsSigId (String connectorId)
 +  {
 +    return !ConnectorFactory.isMOA(connectorId);
 +  }
 +
 +  public static String chooseCommandlineConnectorForSign(String connectorType) throws ConnectorException
 +  {
 +    log.debug("Choosing Connector for commandline signation...");
 +
 +    log.debug("connector type = " + connectorType);
 +
 +    if (connectorType.equals(BKU))
 +    {
 +      log.debug("sig_app is BKU ==> DetachedMultipartBKUConnector"); //$NON-NLS-1$
 +
 +      return ConnectorFactory.DETACHED_MULTIPART_BKU_CONNECTOR;
 +    }
 +    if (connectorType.equals(MOA))
 +    {
 +      // TODO MOA detached signing is not allowed at the commandline
 +      log.warn("Detached MOA is not supported on the commandline. -> choosing Base64 temporarily.");
 +      return ConnectorFactory.ENVELOPING_BASE64_MOA_CONNECTOR;
 +    }
 +
 +    throw new ConnectorException(300, "Unknown connector type '" + connectorType + "' specified.");
 +  }
 +
 +  public static String chooseCommandlineConnectorForVerify(String connectorType, PdfASID sig_kz, String sig_id, String profile) throws ConnectorException
 +  {
 +    log.debug("Choosing Connector for Commandline verification...");
 +
 +    log.debug("connector type = " + connectorType);
 +    log.debug("sig_kz = " + sig_kz); //$NON-NLS-1$
 +    log.debug("sig_id = " + sig_id); //$NON-NLS-1$
 +
 +    if (sig_kz == null)
 +    {
 +      log.debug("sig_kz is null -> chose an old enveloped base64 connector"); //$NON-NLS-1$
 +
 +      return chooseEnvelopingBase64ConnectorOld(connectorType);
 +    }
 +
 +    log.debug("sig_kz is not null -> one of the newer signatures");
 +
 +    if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0))
 +    {
 +      log.debug("Version is 1.0.0 -> Base64 Signatur (old or Hotfix).");
 +
 +      if (sig_id == null)
 +      {
 +        log.debug("sig_id is null, which means that it is a MOA signature -> choose a hotfix base64 connector (thus it is moa - it doesn't matter).");
 +
 +        return chooseEnvelopingBase64ConnectorHotfix(connectorType);
 +      }
 +
 +      String[] sig_id_parts = sig_id.split("@");
 +      if (sig_id_parts.length == 2)
 +      {
 +        log.debug("sig_id has 2 @-separated parts -> choosing old base64 connector");
 +
 +        return chooseEnvelopingBase64ConnectorOld(connectorType);
 +      }
 +      if (sig_id_parts[0].equals(HotfixIdFormatter.SIG_ID_PREFIX))
 +      {
 +        log.debug("sig_id prefix is hotfix -> choosing hotfix base64 connector");
 +
 +        return chooseEnvelopingBase64ConnectorHotfix(connectorType);
 +      }
 +
 +      throw new ConnectorException(300, "The SIG_KZ version is 1.0.0, but SIG_ID is neither MOA nor Old base64 nor Hotfix base64 ???'");
 +    }
 +    if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_1_0))
 +    {
 +      log.debug("Version is 1.1.0 -> chose a detached connector.");
 +
 +      return chooseDetachedMultipartConnector(connectorType);
 +    }
 +
 +    throw new ConnectorException(310, "The SIG_KZ version '" + sig_kz.getVersion() + "' is unknown.");
 +  }
 +
 +  protected static String chooseEnvelopingBase64ConnectorOld(String sig_app) throws ConnectorException
 +  {
 +    if (sig_app.equals(BKU))
 +    {
 +      log.debug("sig_app is BKU ==> OldEnvelopingBase64BKUConnector"); //$NON-NLS-1$
 +
 +      return ConnectorFactory.OLD_ENVELOPING_BASE64_BKU_CONNECTOR;
 +    }
 +    if (sig_app.equals(MOA))
 +    {
 +      log.debug("sig_app is MOA ==> EnvelopingBase64MOAConnector"); //$NON-NLS-1$
 +
 +      return ConnectorFactory.ENVELOPING_BASE64_MOA_CONNECTOR;
 +    }
 +    throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$
 +
 +  }
 +
 +  protected static String chooseEnvelopingBase64ConnectorHotfix(String sig_app) throws ConnectorException
 +  {
 +    if (sig_app.equals(BKU))
 +    {
 +      log.debug("sig_app is BKU ==> EnvelopingBase64BKUConnector"); //$NON-NLS-1$
 +
 +      return ConnectorFactory.ENVELOPING_BASE64_BKU_CONNECTOR;
 +    }
 +    if (sig_app.equals(MOA))
 +    {
 +      log.debug("sig_app is MOA ==> EnvelopingBase64MOAConnector"); //$NON-NLS-1$
 +
 +      return ConnectorFactory.ENVELOPING_BASE64_MOA_CONNECTOR;
 +    }
 +    throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$
 +  }
 +
 +  protected static String chooseDetachedMultipartConnector(String sig_app) throws ConnectorException
 +  {
 +    if (sig_app.equals(BKU))
 +    {
 +      log.debug("sig_app is BKU ==> DetachedMultipartBKUConnector"); //$NON-NLS-1$
 +
 +      return ConnectorFactory.DETACHED_MULTIPART_BKU_CONNECTOR;
 +    }
 +    if (sig_app.equals(MOA))
 +    {
 +      log.debug("sig_app is MOA ==> DetachedMOAConnector"); //$NON-NLS-1$
 +
 +      String msg = "A Detached signature cannot be verified with the MOA connector (yet)."; //$NON-NLS-1$
 +      log.error(msg);
 +      throw new ConnectorException(370, msg);
 +    }
 +    throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java b/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java new file mode 100644 index 0000000..dda4919 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java @@ -0,0 +1,49 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.exceptions;
 +
 +/**
 + * Contains constants for the error codes.
 + * 
 + * <p>
 + * In Java 1.5 this would be an enum.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public final class ErrorCode
 +{
 +  public static final int EXTERNAL_ERROR = 0;
 +
 +  public static final int SETTING_NOT_FOUND = 100;
 +  public static final int SETTINGS_EXCEPTION = 101;
 +  public static final int KZ_SETTING_NOT_FOUND = 102;
 +
 +  public static final int DOCUMENT_CANNOT_BE_READ = 201;
 +  public static final int TEXT_EXTRACTION_EXCEPTION = 202;
 +  public static final int CANNOT_WRITE_PDF = 205;
 +  public static final int DOCUMENT_NOT_SIGNED = 206;
 +  public static final int SIGNATURE_TYPES_EXCEPTION = 223;
 +  
 +  public static final int SIGNATURE_COULDNT_BE_CREATED = 300;
 +  public static final int SIGNED_TEXT_EMPTY = 301;
 +  public static final int PROFILE_NOT_DEFINED = 302;
 +  public static final int SERIAL_NUMBER_INVALID = 303;
 +  public static final int SIG_CERTIFICATE_CANNOT_BE_READ = 304;
 +  
 +  public static final int COULDNT_VERIFY = 310;
 +  
 +  public static final int NOT_SEMANTICALLY_EQUAL = 314;
 +  
 +  public static final int WEB_EXCEPTION = 330;
 +
 +  
 +  public static final int NORMALIZER_EXCEPTION = 400;
 +  
 +  public static final int SESSION_EXPIRED = 600;
 +  
 +  public static final int PLACEHOLDER_EXCEPTION = 700;
 +  
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCodeHelper.java b/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCodeHelper.java new file mode 100644 index 0000000..4144a10 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCodeHelper.java @@ -0,0 +1,43 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.exceptions;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
 +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException;
 +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class ErrorCodeHelper
 +{
 +  /**
 +   * The log.
 +   */
 +  private static final Log log = LogFactory.getLog(ErrorCodeHelper.class);
 +
 +  public static String getMessageForErrorCode(int errorCode)
 +  {
 +    try
 +    {
 +      SettingsReader settings = SettingsReader.getInstance();
 +      String message = settings.getSetting("error.code." + errorCode);
 +      return message;
 +    }
 +    catch (SettingsException e)
 +    {
 +      log.warn(e);
 +    }
 +    catch (SettingNotFoundException e)
 +    {
 +      log.warn(e);
 +    }
 +    return null;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/exceptions/external/ExternalErrorException.java b/src/main/java/at/gv/egiz/pdfas/exceptions/external/ExternalErrorException.java new file mode 100644 index 0000000..4e12ced --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/exceptions/external/ExternalErrorException.java @@ -0,0 +1,43 @@ +package at.gv.egiz.pdfas.exceptions.external;
 +
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
 +
 +public class ExternalErrorException extends ConnectorException
 +{
 +
 +  /**
 +   * SVUID.
 +   */
 +  private static final long serialVersionUID = 2108427722915583885L;
 +
 +  protected String externalErrorCode;
 +
 +  protected String externalErrorMessage;
 +
 +  public ExternalErrorException(String externalErrorCode, String externalErrorMessage)
 +  {
 +    super(ErrorCode.EXTERNAL_ERROR, "External Error " + externalErrorCode + ": " + externalErrorMessage);
 +
 +    this.externalErrorCode = externalErrorCode;
 +    this.externalErrorMessage = externalErrorMessage;
 +  }
 +
 +  /**
 +   * @return the externalErrorCode
 +   */
 +  public String getExternalErrorCode()
 +  {
 +    return externalErrorCode;
 +  }
 +
 +  /**
 +   * @return the externalErrorMessage
 +   */
 +  public String getExternalErrorMessage()
 +  {
 +    return externalErrorMessage;
 +  }
 +
 +  
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/exceptions/framework/SignatorException.java b/src/main/java/at/gv/egiz/pdfas/exceptions/framework/SignatorException.java new file mode 100644 index 0000000..84868d8 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/exceptions/framework/SignatorException.java @@ -0,0 +1,40 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.exceptions.framework;
 +
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +
 +
 +/**
 + * Exception thrown by the Signators.
 + * @author wprinz
 + */
 +public class SignatorException extends PresentableException
 +{
 +
 +  /**
 +   * SVUID.
 +   */
 +  private static final long serialVersionUID = 5051232904560832089L;
 +
 +  public SignatorException(int error_code, String message, Throwable cause)
 +  {
 +    super(error_code, message, cause);
 +  }
 +
 +  public SignatorException(int error_code, String message)
 +  {
 +    super(error_code, message);
 +  }
 +
 +  public SignatorException(int error_code, Throwable cause)
 +  {
 +    super(error_code, cause);
 +  }
 +  
 +  public SignatorException(PresentableException pe)
 +  {
 +    super(pe.getErrorCode(), pe);
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificationFilterException.java b/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificationFilterException.java new file mode 100644 index 0000000..5569e5d --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificationFilterException.java @@ -0,0 +1,40 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.exceptions.framework;
 +
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +
 +/**
 + * Wrapper exception for the VerificationFilter.
 + * 
 + * @author wprinz
 + */
 +public class VerificationFilterException extends PresentableException
 +{
 +  /**
 +   * SVUID.
 +   */
 +  private static final long serialVersionUID = -3863253910537746742L;
 +
 +  public VerificationFilterException(int errorCode, String message, Throwable cause)
 +  {
 +    super(errorCode, message, cause);
 +  }
 +
 +  public VerificationFilterException(int errorCode, String message)
 +  {
 +    super(errorCode, message);
 +  }
 +
 +  public VerificationFilterException(int errorCode, Throwable cause)
 +  {
 +    super(errorCode, cause);
 +  }
 +  
 +  public VerificationFilterException(PresentableException cause)
 +  {
 +    super(cause.getErrorCode(), cause);
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificatorFactoryException.java b/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificatorFactoryException.java new file mode 100644 index 0000000..4721cdb --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificatorFactoryException.java @@ -0,0 +1,49 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.exceptions.framework;
 +
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class VerificatorFactoryException extends PresentableException
 +{
 +
 +  /**
 +   * 
 +   */
 +  private static final long serialVersionUID = 8765156531863056335L;
 +
 +  /**
 +   * @param errorCode
 +   * @param message
 +   */
 +  public VerificatorFactoryException(String message)
 +  {
 +    super(ErrorCode.COULDNT_VERIFY, message);
 +  }
 +
 +  /**
 +   * @param errorCode
 +   * @param message
 +   * @param cause
 +   */
 +  public VerificatorFactoryException(String message, Throwable cause)
 +  {
 +    super(ErrorCode.COULDNT_VERIFY, message, cause);
 +  }
 +
 +  /**
 +   * @param errorCode
 +   * @param cause
 +   */
 +  public VerificatorFactoryException(Throwable cause)
 +  {
 +    super(ErrorCode.COULDNT_VERIFY, cause);
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/KZSettingNotFoundException.java b/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/KZSettingNotFoundException.java new file mode 100644 index 0000000..816a2c1 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/KZSettingNotFoundException.java @@ -0,0 +1,27 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.exceptions.pdf;
 +
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class KZSettingNotFoundException extends SettingNotFoundException
 +{
 +
 +  /**
 +   * SVUID.
 +   */
 +  private static final long serialVersionUID = 2516636821733440462L;
 +
 +  public KZSettingNotFoundException(String message)
 +  {
 +    super(ErrorCode.KZ_SETTING_NOT_FOUND, message);
 +  }
 +
 +  
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/TextExtractionException.java b/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/TextExtractionException.java new file mode 100644 index 0000000..1f54bb5 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/TextExtractionException.java @@ -0,0 +1,18 @@ +package at.gv.egiz.pdfas.exceptions.pdf;
 +
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +
 +public class TextExtractionException extends PresentableException
 +{
 +  /**
 +   * SVUID.
 +   */
 +  private static final long serialVersionUID = 2798763345488999563L;
 +
 +  public TextExtractionException(Throwable cause)
 +  {
 +    super(ErrorCode.TEXT_EXTRACTION_EXCEPTION, cause);
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/exceptions/web/SessionExpiredException.java b/src/main/java/at/gv/egiz/pdfas/exceptions/web/SessionExpiredException.java new file mode 100644 index 0000000..bb55293 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/exceptions/web/SessionExpiredException.java @@ -0,0 +1,48 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.exceptions.web;
 +
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class SessionExpiredException extends PresentableException
 +{
 +  /**
 +   * SVUID.
 +   */
 +  private static final long serialVersionUID = -1877790545371341233L;
 +  
 +  /**
 +   * @param errorCode
 +   * @param message
 +   */
 +  public SessionExpiredException(String message)
 +  {
 +    super(ErrorCode.SESSION_EXPIRED, message);
 +  }
 +
 +  /**
 +   * @param errorCode
 +   * @param message
 +   * @param cause
 +   */
 +  public SessionExpiredException(String message, Throwable cause)
 +  {
 +    super(ErrorCode.SESSION_EXPIRED, message, cause);
 +  }
 +
 +  /**
 +   * @param errorCode
 +   * @param cause
 +   */
 +  public SessionExpiredException(Throwable cause)
 +  {
 +    super(ErrorCode.SESSION_EXPIRED, cause);
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java b/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java new file mode 100644 index 0000000..65c5af7 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java @@ -0,0 +1,83 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework;
 +
 +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException;
 +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.EnvelopedBase64BKUConnector;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.MultipartDetachedBKUConnector;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.OldEnvelopingBase64BKUConnector;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.DetachedLocRefMOAConnector;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.EnvelopingBase64MOAConnector;
 +
 +/**
 + * @author wprinz
 + */
 +public class ConnectorFactory
 +{
 +  // TODO the functionality of the connector should be split into template
 +  // handling and the actualy hardware access
 +  
 +  public static String DETACHED_MULTIPART_BKU_CONNECTOR = "DetachedMultipartBKUConnector";
 +
 +  public static String ENVELOPING_BASE64_BKU_CONNECTOR = "EnvelopingBase64BKUConnector";
 +
 +  public static String OLD_ENVELOPING_BASE64_BKU_CONNECTOR = "OldEnvelopingBase64BKUConnector";
 +
 +  public static String DETACHED_LOCREF_MOA_CONNECTOR = "DetachedLocRefMOAConnector";
 +  
 +  public static String ENVELOPING_BASE64_MOA_CONNECTOR = "EnvelopingBase64MOAConnector";
 +   
 +
 +  
 +  public static Connector createConnector (String connectorId, String profile, String locRef) throws ConnectorFactoryException, ConnectorException
 +  {
 +    if (connectorId.equals(DETACHED_MULTIPART_BKU_CONNECTOR))
 +    {
 +      return new MultipartDetachedBKUConnector(profile);
 +    }
 +    
 +    if (connectorId.equals(ENVELOPING_BASE64_BKU_CONNECTOR))
 +    {
 +      return new EnvelopedBase64BKUConnector(profile);
 +    }
 +
 +    if (connectorId.equals(OLD_ENVELOPING_BASE64_BKU_CONNECTOR))
 +    {
 +      return new OldEnvelopingBase64BKUConnector(profile);
 +    }
 +
 +    if (connectorId.equals(DETACHED_LOCREF_MOA_CONNECTOR))
 +    {
 +      return new DetachedLocRefMOAConnector(profile, locRef);
 +    }
 +    
 +    if (connectorId.equals(ENVELOPING_BASE64_MOA_CONNECTOR))
 +    {
 +      return new EnvelopingBase64MOAConnector(profile);
 +    }
 +
 +    throw new ConnectorFactoryException("The connector Id " + connectorId + " couldn't be found by the ConnectorFactory.");
 +  }
 +  
 +  public static boolean isMOA (String connectorId)
 +  {
 +    if (connectorId.equals(DETACHED_LOCREF_MOA_CONNECTOR) || connectorId.equals(ENVELOPING_BASE64_MOA_CONNECTOR))
 +    {
 +      return true;
 +    }
 +    
 +    return false;
 +  }
 +  
 +//  public static Connector createConnectorForCommandline (String connectorId) throws ConnectorFactoryException
 +//  {
 +//  }
 +//  
 +//  public static Connector createConnectorForCommandline (String connectorId) throws ConnectorFactoryException
 +//  {
 +//  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/DataManager.java b/src/main/java/at/gv/egiz/pdfas/framework/DataManager.java new file mode 100644 index 0000000..1640b07 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/DataManager.java @@ -0,0 +1,35 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework;
 +
 +/**
 + * The DataManager is a mediator for all components that need to allocate large
 + * data elements.
 + * 
 + * <p>
 + * The DataManager uses a certain DataStrategy to perform the actual tasks. The
 + * strategy may be different in different environments. E.g. The commandline may
 + * implement a strategy to keep all data in memory, whereas the web might
 + * implement one that puts as many data onto the disk as possible to save
 + * memory.
 + * </p>
 + * 
 + * @author wprinz
 + * 
 + */
 +public class DataManager
 +{
 +  protected static DataStrategy dataStrategy = null;
 +
 +  public static void initialize(DataStrategy ds)
 +  {
 +    dataStrategy = ds;
 +  }
 +
 +  public static DataStrategy getDataStrategy()
 +  {
 +    return dataStrategy;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/DataStrategy.java b/src/main/java/at/gv/egiz/pdfas/framework/DataStrategy.java new file mode 100644 index 0000000..22f9676 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/DataStrategy.java @@ -0,0 +1,37 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework;
 +
 +import java.io.InputStream;
 +
 +import at.gv.egiz.pdfas.framework.input.DataSource;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.gv.egiz.pdfas.framework.input.TextDataSource;
 +import at.gv.egiz.pdfas.framework.output.DataSink;
 +
 +/**
 + * Factory for creating DataSources.
 + * 
 + * @author wprinz
 + */
 +public interface DataStrategy
 +{
 +  
 +  public TextDataSource createTextDataSource (String text);
 +  
 +  public PdfDataSource createPdfDataSource (InputStream is);
 +  
 +  public PdfDataSource createPdfDataSource (DataSource other, int length);
 +  
 +  /**
 +   * @deprecated - use streaming.
 +   * @param pdf
 +   * @return
 +   */
 +  public PdfDataSource createPdfDataSource (byte [] pdf);
 +
 +  public void destroyDataSource (DataSource dataSource);
 +  
 +  public DataSink createDataSink ();
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/SignatorFactory.java b/src/main/java/at/gv/egiz/pdfas/framework/SignatorFactory.java new file mode 100644 index 0000000..d4ecc26 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/SignatorFactory.java @@ -0,0 +1,100 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework;
 +
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.exceptions.SignatorFactoryException;
 +import at.gv.egiz.pdfas.impl.signator.binary.BinarySignator_1_0_0;
 +import at.gv.egiz.pdfas.impl.signator.binary.BinarySignator_1_1_0;
 +import at.gv.egiz.pdfas.impl.signator.detached.DetachedTextualSignator_1_0_0;
 +import at.gv.egiz.pdfas.impl.signator.textual.TextualSignator_1_0_0;
 +import at.gv.egiz.pdfas.impl.signator.textual.TextualSignator_1_1_0;
 +import at.gv.egiz.pdfas.framework.signator.Signator;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class SignatorFactory
 +{
 +  /**
 +   * The Vendor.
 +   */
 +  public static final String VENDOR = "bka.gv.at"; //$NON-NLS-1$
 +
 +  /**
 +   * The binary Signator algorithm.
 +   */
 +  public static final String TYPE_BINARY = "binaer"; //$NON-NLS-1$
 +
 +  /**
 +   * The textual Signator algorithm.
 +   */
 +  public static final String TYPE_TEXTUAL = "text"; //$NON-NLS-1$
 +  
 +  /**
 +   * Detached Signator.
 +   */
 +  public static final String TYPE_DETACHED_TEXTUAL = "detachedtext"; //$NON-NLS-1$
 +
 +  /**
 +   * This application's current algorithm versions.
 +   */
 +  public static final String VERSION_1_0_0 = "v1.0.0"; //$NON-NLS-1$
 +
 +  /**
 +   * This application's current algorithm versions.
 +   */
 +  public static final String VERSION_1_1_0 = "v1.1.0"; //$NON-NLS-1$
 +
 +  
 +  public static Signator createSignator (PdfASID id) throws SignatorFactoryException
 +  {
 +    if (!id.getVendor().equals(VENDOR))
 +    {
 +      throw new SignatorFactoryException("The vendor '" + id.getVendor() + "' is unrecognized by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 +    }
 +
 +    if (id.getType().equals(TYPE_BINARY))
 +    {
 +      if (id.getVersion().equals(VERSION_1_0_0))
 +      {
 +        return new BinarySignator_1_0_0();
 +      }
 +      if (id.getVersion().equals(VERSION_1_1_0))
 +      {
 +        return new BinarySignator_1_1_0();
 +      }
 +
 +      throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 +    }
 +
 +    if (id.getType().equals(TYPE_TEXTUAL))
 +    {
 +      if (id.getVersion().equals(VERSION_1_0_0))
 +      {
 +        return new TextualSignator_1_0_0();
 +      }
 +      if (id.getVersion().equals(VERSION_1_1_0))
 +      {
 +        return new TextualSignator_1_1_0();
 +      }
 +
 +      throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 +    }
 +
 +    if (id.getType().equals(TYPE_DETACHED_TEXTUAL))
 +    {
 +      if (id.getVersion().equals(VERSION_1_0_0))
 +      {
 +        return new DetachedTextualSignator_1_0_0();
 +      }
 +      
 +      throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 +    }
 +
 +    throw new SignatorFactoryException("The type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/SignatureHolderHelper.java b/src/main/java/at/gv/egiz/pdfas/framework/SignatureHolderHelper.java new file mode 100644 index 0000000..ab77092 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/SignatureHolderHelper.java @@ -0,0 +1,34 @@ +package at.gv.egiz.pdfas.framework;
 +
 +import java.util.Collections;
 +import java.util.Comparator;
 +import java.util.List;
 +
 +import at.knowcenter.wag.egov.egiz.pdf.EGIZDate;
 +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder;
 +
 +public final class SignatureHolderHelper
 +{
 +
 +  /**
 +   * Sorts the List of SignatureHolders by date.
 +   * 
 +   * @param signatureHolders
 +   *          The List of SignatureHolders.
 +   */
 +  public static void sortByDate(List signatureHolders)
 +  {
 +    Collections.sort(signatureHolders, new Comparator() {
 +      public int compare(Object o1, Object o2)
 +      {
 +        SignatureHolder sh1 = (SignatureHolder) o1;
 +        SignatureHolder sh2 = (SignatureHolder) o2;
 +
 +        EGIZDate date1 = EGIZDate.parseFromString(sh1.getSignatureObject().getSignationDate());
 +        EGIZDate date2 = EGIZDate.parseFromString(sh2.getSignatureObject().getSignationDate());
 +
 +        return date1.compareTo(date2);
 +      }
 +    });
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/VerificatorFactory.java b/src/main/java/at/gv/egiz/pdfas/framework/VerificatorFactory.java new file mode 100644 index 0000000..f77ca23 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/VerificatorFactory.java @@ -0,0 +1,45 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework;
 +
 +import at.gv.egiz.pdfas.exceptions.framework.VerificatorFactoryException;
 +import at.gv.egiz.pdfas.framework.verificator.Verificator;
 +import at.gv.egiz.pdfas.impl.verificator.binary.BinaryVerificator_1_0_0;
 +import at.gv.egiz.pdfas.impl.verificator.binary.BinaryVerificator_1_1_0;
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class VerificatorFactory
 +{
 +
 +  public static Verificator createVerificator(PdfASID kz) throws VerificatorFactoryException
 +  {
 +    if (kz.getType().equals(SignatorFactory.TYPE_BINARY))
 +    {
 +      return createBinaryVerificator(kz);
 +    }
 +    
 +    return null;
 +  }
 +  
 +  public static Verificator createBinaryVerificator(PdfASID kz) throws VerificatorFactoryException
 +  {
 +    assert kz.getType().equals(SignatorFactory.TYPE_BINARY);
 +
 +    if (kz.equals(BinaryVerificator_1_0_0.MY_ID))
 +    {
 +      return new BinaryVerificator_1_0_0();
 +    }
 +    if (kz.equals(BinaryVerificator_1_1_0.MY_ID))
 +    {
 +      return new BinaryVerificator_1_1_0();
 +    }
 +
 +    throw new VerificatorFactoryException("kz is not a known binary signator " + kz);
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/config/SettingsHelper.java b/src/main/java/at/gv/egiz/pdfas/framework/config/SettingsHelper.java new file mode 100644 index 0000000..6f67d1d --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/config/SettingsHelper.java @@ -0,0 +1,37 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework.config;
 +
 +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters;
 +import at.gv.egiz.pdfas.impl.vfilter.VerificationFilterParametersImpl;
 +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
 +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException;
 +
 +/**
 + * Contains helpful Settings functions.
 + * @author wprinz
 + */
 +public final class SettingsHelper
 +{
 +  public static VerificationFilterParameters readVerificationFilterParametersFromSettings() throws SettingsException
 +  { 
 +    boolean binaryOnly = getFlag("binary_only");
 +    boolean assumeOnlySB = getFlag("assume_only_signauture_blocks");
 +    boolean checkOld = getFlag("check_old_textual_sigs");
 +    
 +    VerificationFilterParameters vfp = new VerificationFilterParametersImpl(binaryOnly, assumeOnlySB, checkOld);
 +    return vfp;
 +  }
 +
 +  protected static boolean getFlag (String settingsKey) throws SettingsException
 +  {
 +    String flag = SettingsReader.getInstance().getSetting(settingsKey, "false");
 +    boolean b = true;
 +    if (flag.equals("false"))
 +    {
 +      b = false;
 +    }
 +    return b;
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/input/DataSource.java b/src/main/java/at/gv/egiz/pdfas/framework/input/DataSource.java new file mode 100644 index 0000000..265cb0c --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/input/DataSource.java @@ -0,0 +1,35 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework.input;
 +
 +import java.io.InputStream;
 +
 +/**
 + * The input document data source.
 + * 
 + * <p>
 + * Usually this is a PdfDataSource, but it may be a TextDataSource as well.
 + * </p>
 + * 
 + * @author wprinz
 + * 
 + */
 +public interface DataSource
 +{
 +  /**
 +   * Creates a new InputStream that allows to read out the document's binary
 +   * data from the beginning.
 +   * 
 +   * @return Returns the InputStream with the binary data.
 +   */
 +  public InputStream createInputStream();
 +
 +  /**
 +   * Returns the length (number of bytes) of the stream.
 +   * 
 +   * @return Returns the length (number of bytes) of the stream.
 +   */
 +  public int getLength();
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/input/ExtractionStage.java b/src/main/java/at/gv/egiz/pdfas/framework/input/ExtractionStage.java new file mode 100644 index 0000000..36d9bd8 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/input/ExtractionStage.java @@ -0,0 +1,66 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework.input;
 +
 +import java.util.List;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +import at.gv.egiz.pdfas.exceptions.framework.VerificationFilterException;
 +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilter;
 +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters;
 +import at.gv.egiz.pdfas.impl.input.IncrementalUpdateParser;
 +import at.gv.egiz.pdfas.impl.vfilter.VerificationFilterImpl;
 +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +
 +/**
 + * Extracts all signatures from a given input DataSource.
 + * 
 + * @author wprinz
 + */
 +public class ExtractionStage
 +{
 +  /**
 +   * The log.
 +   */
 +  private static final Log log = LogFactory.getLog(ExtractionStage.class);
 +
 +  public List extractSignatureHolders(final DataSource dataSource, VerificationFilterParameters parameters) throws PresentableException
 +  {
 +    if (dataSource instanceof PdfDataSource)
 +    {
 +      PdfDataSource pdfDataSource = (PdfDataSource) dataSource;
 +
 +      List blocks = parsePdfIntoBlocks(pdfDataSource);
 +
 +      VerificationFilter vf = new VerificationFilterImpl();
 +      List signatures = vf.extractSignatureHolders(pdfDataSource, blocks, parameters);
 +
 +      return signatures;
 +    }
 +
 +    if (dataSource instanceof TextDataSource)
 +    {
 +      TextDataSource textDataSource = (TextDataSource) dataSource;
 +
 +      VerificationFilter vf = new VerificationFilterImpl();
 +      List signatures = vf.extractSignaturHolders(textDataSource, parameters);
 +
 +      return signatures;
 +    }
 +
 +    String msg = "The input DataSource is neither pdf nor text. class.name = " + dataSource.getClass().getName();
 +    log.error(msg);
 +    throw new VerificationFilterException(ErrorCode.DOCUMENT_CANNOT_BE_READ, msg);
 +  }
 +
 +  protected List parsePdfIntoBlocks(PdfDataSource pdfDataSource) throws PDFDocumentException
 +  {
 +    List blocks = IncrementalUpdateParser.parsePdfIntoIUBlocks(pdfDataSource);
 +    return blocks;
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSource.java b/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSource.java new file mode 100644 index 0000000..b03a67e --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSource.java @@ -0,0 +1,21 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework.input;
 +
 +
 +/**
 + * Represents the binary data of a PDF document.
 + * 
 + * <p>
 + * This interface allows Pdf data to be handled in an abstract way so that the
 + * storage (byta array, disk etc.) of pdf documents can be separated from the
 + * algorithms.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public interface PdfDataSource extends DataSource
 +{
 +  // jsut a marker interface
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/input/TextDataSource.java b/src/main/java/at/gv/egiz/pdfas/framework/input/TextDataSource.java new file mode 100644 index 0000000..c5fd4b1 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/input/TextDataSource.java @@ -0,0 +1,19 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework.input;
 +
 +/**
 + * Represents a free-text input text to be processed.
 + *  
 + * @author wprinz
 + */
 +public interface TextDataSource extends DataSource
 +{
 +  /**
 +   * Returns the text to be processed.
 +   * @return Returns the text to be processed.
 +   */
 +  public String getText();
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/output/DataSink.java b/src/main/java/at/gv/egiz/pdfas/framework/output/DataSink.java new file mode 100644 index 0000000..d7d0cc4 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/output/DataSink.java @@ -0,0 +1,15 @@ +package at.gv.egiz.pdfas.framework.output;
 +
 +import java.io.OutputStream;
 +
 +/**
 + * Output document data sink.
 + * 
 + * @author wprinz
 + */
 +public interface DataSink
 +{
 +  public OutputStream createOutputStream(String mimeType);
 +
 +  public OutputStream createOutputStream(String mimeType, String characterEncoding);
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SequentialSignatureDevice.java b/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SequentialSignatureDevice.java new file mode 100644 index 0000000..70a28db --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SequentialSignatureDevice.java @@ -0,0 +1,25 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework.sigdevice;
 +
 +/**
 + * A SignatureDevice that can be accessed in a sequential manner.
 + * 
 + * <p>
 + * A sequential device handles all necessary steps in sequence. E.g. all the
 + * data is transformed into a http request and sent to a server. The server
 + * processes the request and answers. The response from the server is then
 + * analyzed and returned.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public interface SequentialSignatureDevice extends SignatureDevice
 +{
 +  // This is just a concept how it could be realized in future.
 +  public void sign();
 +
 +  public void verify();
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SignatureDevice.java b/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SignatureDevice.java new file mode 100644 index 0000000..735dd3c --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SignatureDevice.java @@ -0,0 +1,16 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework.sigdevice;
 +
 +/**
 + * Performs the task of passing the signature XML and data from the application
 + * to an external signature device and return the response in an form that the
 + * application can use.
 + * 
 + * @author wprinz
 + */
 +public interface SignatureDevice
 +{
 +  // Marker interface
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/signator/Signator.java b/src/main/java/at/gv/egiz/pdfas/framework/signator/Signator.java new file mode 100644 index 0000000..e77ed08 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/signator/Signator.java @@ -0,0 +1,56 @@ +/**
 + * <copyright> Copyright (c) 2006 by Know-Center, Graz, Austria </copyright>
 + * 
 + * This software is the confidential and proprietary information of Know-Center,
 + * Graz, Austria. You shall not disclose such Confidential Information and shall
 + * use it only in accordance with the terms of the license agreement you entered
 + * into with Know-Center.
 + * 
 + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 + * DERIVATIVES.
 + * 
 + * $Id: Signator.java,v 1.1 2006/08/25 17:07:21 wprinz Exp $
 + */
 +package at.gv.egiz.pdfas.framework.signator;
 +
 +import at.gv.egiz.pdfas.exceptions.framework.SignatorException;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.gv.egiz.pdfas.framework.output.DataSink;
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.framework.SignResult;
 +import at.knowcenter.wag.egov.egiz.pdf.TablePos;
 +
 +/**
 + * The basic interface for signator algorithms.
 + * 
 + * @author wprinz
 + */
 +public interface Signator
 +{
 +  /**
 +   * Returns the PdfASID of this Connector.
 +   * 
 +   * <p>
 +   * This should always return the MY_ID static field of the connector. Dont't
 +   * forget to override this.
 +   * </p>
 +   * <p>
 +   * Within connector code always use this method so that code reuse through
 +   * derivation can take place correctly.
 +   * </p>
 +   * 
 +   * @return Returns the PdfASID of this Connector.
 +   */
 +  public PdfASID getMyId();
 +
 +
 +  public SignatorInformation prepareSign(PdfDataSource pdfDataSource,
 +      String profile, TablePos pos, boolean has_SIG_ID) throws SignatorException;
 +
 +
 +  public void finishSign(SignatorInformation signatorInformation, DataSink dataSink) throws SignatorException;
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java b/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java new file mode 100644 index 0000000..da81e87 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java @@ -0,0 +1,43 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework.signator;
 +
 +import at.knowcenter.wag.egov.egiz.sig.SignatureData;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject;
 +
 +/**
 + * Encapsulates the Signator dependant information that needs to be passed from
 + * prepareSign to finishSign.
 + * 
 + * <p>
 + * This supersedes the IncrementalUpdateInformation.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public interface SignatorInformation
 +{
 +  /**
 +   * Returns the SignatureData to be signed.
 +   * <p>
 +   * This is passed on to the Connector and signature device for signing.
 +   * </p>
 +   * 
 +   * @return Returns the SignatureData to be signed.
 +   */
 +  public SignatureData getSignatureData();
 +
 +  /**
 +   * Sets the SignSignatureObject with the signature data.
 +   * 
 +   * <p>
 +   * This is called by the framework to provide the finishSign with the
 +   * signature data.
 +   * </p>
 +   * 
 +   * @param signSignatureObject
 +   *          The SignSignatureObject.
 +   */
 +  public void setSignSignatureObject(SignSignatureObject signSignatureObject);
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/verificator/Verificator.java b/src/main/java/at/gv/egiz/pdfas/framework/verificator/Verificator.java new file mode 100644 index 0000000..b134d64 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/verificator/Verificator.java @@ -0,0 +1,53 @@ +/**
 + * <copyright> Copyright (c) 2006 by Know-Center, Graz, Austria </copyright>
 + * 
 + * This software is the confidential and proprietary information of Know-Center,
 + * Graz, Austria. You shall not disclose such Confidential Information and shall
 + * use it only in accordance with the terms of the license agreement you entered
 + * into with Know-Center.
 + * 
 + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 + * DERIVATIVES.
 + * 
 + * $Id: Verificator.java,v 1.1 2006/08/25 17:07:21 wprinz Exp $
 + */
 +package at.gv.egiz.pdfas.framework.verificator;
 +
 +import java.util.List;
 +
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult;
 +
 +
 +/**
 + * Given an Incremental Update Block and the corresponding PDF, a verificator
 + * extracts all Signatures of its type and returns them as valitatable
 + * SignatureHolders.
 + * 
 + * @author wprinz
 + */
 +public interface Verificator
 +{
 +  /**
 +   * Parses the given document/Block for signatures of this type.
 +   * 
 +   * @param pdf
 +   *          The whole pdf document. A Verificator must only access the
 +   *          document up to its given block (block.next_index) and must not
 +   *          modify any byte in the pdf array.
 +   * @param block
 +   *          The incremental update block.
 +   * @param start_of_whole_block
 +   *          The start of the incremental update block (the end of the previous
 +   *          block) - If 0, this is the first block (the original Document).
 +   * @return Returns the List of SignatureHolder objects found for this block.
 +   */
 +  public List parseBlock(PdfDataSource pdfDataSource, byte [] pdf, final FooterParseResult block,
 +      int start_of_whole_block) throws PresentableException;
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilter.java b/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilter.java new file mode 100644 index 0000000..1633b09 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilter.java @@ -0,0 +1,52 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework.vfilter;
 +
 +import java.util.List;
 +
 +import at.gv.egiz.pdfas.exceptions.framework.VerificationFilterException;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.gv.egiz.pdfas.framework.input.TextDataSource;
 +
 +/**
 + * Extracts all signatures from a given PDF document or text.
 + * 
 + * @see VerificationFilterParameters
 + * 
 + * @author wprinz
 + */
 +public interface VerificationFilter
 +{
 +
 +  /**
 +   * Extracts the signatures from the given PDF.
 +   * 
 +   * @param pdf
 +   *          The PDF.
 +   * @param blocks
 +   *          The List of Incremental Update blocks. Usually this comes from a
 +   *          preprocessing step.
 +   * @param parameters
 +   *          The algorithm parameters.
 +   * @return Returns a List of SignatureHolders containing the signatures. May
 +   *         be empty in case no signatures have been found.
 +   * @throws VerificationFilterException
 +   *           Thrown if something goes wrong.
 +   */
 +  public List extractSignatureHolders(PdfDataSource pdf, List blocks, VerificationFilterParameters parameters) throws VerificationFilterException;
 +
 +  /**
 +   * Extracts the text signatures from the given free-text.
 +   * 
 +   * @param text
 +   *          The free-text.
 +   * @param parameters
 +   *          The algorithm parameters.
 +   * @return Returns a List of SignatureHolders containing the signatures. May
 +   *         be empty in case no signatures have been found.
 +   * @throws VerificationFilterException
 +   *           Thrown if something goes wrong.
 +   */
 +  public List extractSignaturHolders(TextDataSource text, VerificationFilterParameters parameters) throws VerificationFilterException;
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilterParameters.java b/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilterParameters.java new file mode 100644 index 0000000..c518fef --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilterParameters.java @@ -0,0 +1,76 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.framework.vfilter;
 +
 +/**
 + * The parameters of the VerificationFilter algorithm.
 + * 
 + * @author wprinz
 + */
 +public interface VerificationFilterParameters
 +{
 +
 +  /**
 +   * Tells the VerificationFilter to extract binary signatures only.
 +   * 
 +   * <p>
 +   * Not scanning for textual signatures allows the algorithm to skip text
 +   * extraction and signature extraction, which are both time and memory
 +   * intensive processes.
 +   * </p>
 +   * 
 +   * @return Returns true if the VerificationFilter should extract binary
 +   *         signatures only.
 +   */
 +  public boolean extractBinarySignaturesOnly();
 +
 +  /**
 +   * Tells the VerificationFilter to assume that there are only singatures (and
 +   * their Incremental Update blocks) younger than the original document.
 +   * 
 +   * <p>
 +   * This is equivalent to saying that the document was not updated using an
 +   * Incremental update block other than a signature after being singed. The
 +   * incremental update blocks after the original document contain only
 +   * signatures (either text or binary).
 +   * </p>
 +   * <p>
 +   * This is equivalent to saying that there exists no Incremental Update block
 +   * that would render a text signature before it invalid.
 +   * </p>
 +   * <p>
 +   * Under this assumption, the process of finding all text signatures
 +   * simplifies to one text extraction of the whole document and one signature
 +   * extraction. This is of course a massive performance gain.
 +   * </p>
 +   * <p>
 +   * Actually the algorithm performs a text extraction of the whole document not
 +   * including trailing binary signature Incremental Update blocks. This means
 +   * that if a the last n Incremental Update blocks of a document are binary,
 +   * there is no use extract text from them.
 +   * </p>
 +   * <p>
 +   * Note that if there are Incremental Update blocks with text after a
 +   * signature thus this assumption does not hold the signatures older than this
 +   * block will break.
 +   * </p>
 +   * 
 +   * @return Returns true if the Verification filter should assume that there
 +   *         are only signature blocks after the original document.
 +   */
 +  public boolean assumeOnlySignatureUpdateBlocks();
 +
 +  /**
 +   * Tells the VerificationFilter so scan for old signatures in the rest text.
 +   * 
 +   * <p>
 +   * The rest text is the text of the oldest text signature or the original
 +   * document text if there is no text signature.
 +   * </p>
 +   * 
 +   * @return Returns true if the VerificationFilter should scan for old text
 +   *         signatures in the rest text.
 +   */
 +  public boolean scanForOldSignatures();
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/ByteArrayPdfDataSourceImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/input/ByteArrayPdfDataSourceImpl.java new file mode 100644 index 0000000..0d27781 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/ByteArrayPdfDataSourceImpl.java @@ -0,0 +1,56 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.input;
 +
 +import java.io.ByteArrayInputStream;
 +import java.io.InputStream;
 +
 +import at.gv.egiz.pdfas.performance.PerformanceCounters;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +
 +/**
 + * Implements a PdfDataSource that holds the whole PDF document in a byte array.
 + * 
 + * <p>
 + * Note that holding the data in a byte array is very memory consuming for large
 + * documents.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public class ByteArrayPdfDataSourceImpl implements PdfDataSource
 +{
 +  protected byte[] pdf = null;
 +  
 +  protected int length = -1;
 +
 +  public ByteArrayPdfDataSourceImpl(byte[] pdf)
 +  {
 +    PerformanceCounters.byteArrays.increment();
 +
 +    this.pdf = pdf;
 +    this.length = pdf.length;
 +  }
 +
 +  public ByteArrayPdfDataSourceImpl(byte[] pdf, int length)
 +  {
 +    PerformanceCounters.byteArrays.increment();
 +
 +    this.pdf = pdf;
 +    this.length = length;
 +  }
 +
 +
 +  public InputStream createInputStream()
 +  {
 +    ByteArrayInputStream bais = new ByteArrayInputStream(this.pdf, 0, this.length);
 +    return bais;
 +  }
 +
 +  public int getLength()
 +  {
 +    return this.length;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/CompoundPdfDataSourceImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/input/CompoundPdfDataSourceImpl.java new file mode 100644 index 0000000..f77d6be --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/CompoundPdfDataSourceImpl.java @@ -0,0 +1,47 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.input;
 +
 +import java.io.ByteArrayInputStream;
 +import java.io.InputStream;
 +import java.io.SequenceInputStream;
 +
 +import at.gv.egiz.pdfas.framework.input.DataSource;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class CompoundPdfDataSourceImpl implements PdfDataSource
 +{
 +  protected DataSource originalDataSource = null;
 +  
 +  protected byte[] appendix = null;
 +  
 +  public CompoundPdfDataSourceImpl (PdfDataSource original, byte [] appendix)
 +  {
 +    this.originalDataSource = original;
 +    this.appendix = appendix;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.DataSource#createInputStream()
 +   */
 +  public InputStream createInputStream()
 +  {
 +    ByteArrayInputStream bais = new ByteArrayInputStream(this.appendix);
 +    SequenceInputStream sis = new SequenceInputStream(this.originalDataSource.createInputStream(), bais);
 +    return sis;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.DataSource#getLength()
 +   */
 +  public int getLength()
 +  {
 +    return this.originalDataSource.getLength() + this.appendix.length;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedInputStream.java b/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedInputStream.java new file mode 100644 index 0000000..4be9ec5 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedInputStream.java @@ -0,0 +1,105 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.input;
 +
 +import java.io.IOException;
 +import java.io.InputStream;
 +
 +/**
 + * An input stream that has a delimited length.
 + * 
 + * @author wprinz
 + */
 +public class DelimitedInputStream extends InputStream
 +{
 +  /**
 +   * The underlying InputStream.
 +   */
 +  protected InputStream is = null;
 +
 +  /**
 +   * The number of bytes that can be read from the stream.
 +   */
 +  protected int bytes_to_read = -1;
 +
 +  /**
 +   * Constructs the DelimitedInputStream from which a maximum of length bytes
 +   * can be read.
 +   */
 +  public DelimitedInputStream(InputStream is, int length)
 +  {
 +    this.is = is;
 +    this.bytes_to_read = length;
 +  }
 +
 +  /**
 +   * @see java.io.InputStream#read()
 +   */
 +  public int read() throws IOException
 +  {
 +    if (this.bytes_to_read <= 0)
 +    {
 +      return -1;
 +    }
 +    int read = this.is.read();
 +    if (read > 0)
 +    {
 +      this.bytes_to_read--;
 +    }
 +    return read;
 +  }
 +
 +  /**
 +   * @see java.io.InputStream#read(byte[], int, int)
 +   */
 +  public int read(byte[] b, int off, int len) throws IOException
 +  {
 +    int btr = Math.min(len, this.bytes_to_read);
 +    int read = this.is.read(b, off, btr);
 +    if (read > 0)
 +    {
 +      this.bytes_to_read -= read;
 +    }
 +    return read;
 +  }
 +
 +  /**
 +   * @see java.io.InputStream#read(byte[])
 +   */
 +  public int read(byte[] b) throws IOException
 +  {
 +    return read(b, 0, b.length);
 +  }
 +
 +  /**
 +   * @see java.io.InputStream#skip(long)
 +   */
 +  public long skip(long n) throws IOException
 +  {
 +    long bts = Math.min(n, this.bytes_to_read);
 +    long skipped = this.is.skip(bts);
 +    if (skipped > 0)
 +    {
 +      this.bytes_to_read -= skipped;
 +    }
 +    return skipped;
 +  }
 +
 +  /**
 +   * @see java.io.InputStream#close()
 +   */
 +  public void close() throws IOException
 +  {
 +    this.is.close();
 +  }
 +
 +  /**
 +   * @see java.io.InputStream#available()
 +   */
 +  public int available() throws IOException
 +  {
 +    int avail = this.is.available();
 +    return Math.min(this.bytes_to_read, avail);
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedPdfDataSource.java b/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedPdfDataSource.java new file mode 100644 index 0000000..6c67be2 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedPdfDataSource.java @@ -0,0 +1,44 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.input;
 +
 +import java.io.InputStream;
 +
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class DelimitedPdfDataSource implements PdfDataSource
 +{
 +  
 +  protected PdfDataSource dataSource = null;
 +  protected int len = -1;
 +
 +  public DelimitedPdfDataSource (PdfDataSource original, int length)
 +  {
 +    this.dataSource = original;
 +    this.len = length;
 +  }
 +  
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.DataSource#createInputStream()
 +   */
 +  public InputStream createInputStream()
 +  {
 +    InputStream originalIS = this.dataSource.createInputStream();
 +    DelimitedInputStream dis = new DelimitedInputStream(originalIS, this.len);
 +    return dis;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.DataSource#getLength()
 +   */
 +  public int getLength()
 +  {
 +    return this.len;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/FileBased.java b/src/main/java/at/gv/egiz/pdfas/impl/input/FileBased.java new file mode 100644 index 0000000..54f8842 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/FileBased.java @@ -0,0 +1,20 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.input;
 +
 +import java.io.File;
 +
 +/**
 + * Interface that reveals the underlying data file.
 + * 
 + * @author wprinz
 + */
 +public interface FileBased
 +{
 +  /**
 +   * Returns the underlying data file.
 +   * @return Returns the underlying data file.
 +   */
 +  public File getFile();
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedPdfDataSourceImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedPdfDataSourceImpl.java new file mode 100644 index 0000000..8453192 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedPdfDataSourceImpl.java @@ -0,0 +1,103 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.input;
 +
 +import java.io.File;
 +import java.io.FileInputStream;
 +import java.io.FileNotFoundException;
 +import java.io.IOException;
 +import java.io.InputStream;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +
 +/**
 + * @author wprinz
 + * 
 + */
 +public class FileBasedPdfDataSourceImpl implements PdfDataSource, FileBased
 +{
 +  /**
 +   * The log.
 +   */
 +  private static final Log log = LogFactory.getLog(FileBasedPdfDataSourceImpl.class);
 +
 +  /**
 +   * The underlying file.
 +   */
 +  protected File inputFile = null;
 +
 +  protected int length = -1;
 +
 +  /**
 +   * Constructor that creates this PdfDataSource backed by a file in the file
 +   * system.
 +   * 
 +   * @param file
 +   *          The input File.
 +   * @param length
 +   *          The length of the InputStream. The is the maximum number of bytes
 +   *          that can be read from the stream.
 +   * @throws IOException
 +   *           Thrown if the file cannot be read properly.
 +   */
 +  public FileBasedPdfDataSourceImpl(File file, int length) throws IOException
 +  {
 +
 +    if (!file.exists())
 +    {
 +      throw new FileNotFoundException("The file '" + file + "' does not exist.");
 +    }
 +    // for some reason the isFile is not always correct...
 +    // if (file.isFile())
 +    // {
 +    // throw new IOException("The file '" + file + "' is not a normal file.");
 +    // }
 +    if (!file.canRead())
 +    {
 +      throw new IOException("The file '" + file + "' cannot be read.");
 +    }
 +
 +    this.inputFile = file;
 +    this.length = length;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.impl.input.FileBased#getFile()
 +   */
 +  public File getFile()
 +  {
 +    return this.inputFile;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.PdfDataSource#createInputStream()
 +   */
 +  public InputStream createInputStream()
 +  {
 +    try
 +    {
 +      FileInputStream fis = new FileInputStream(getFile());
 +      DelimitedInputStream dis = new DelimitedInputStream(fis, getLength());
 +      return dis;
 +    }
 +    catch (IOException e)
 +    {
 +      log.error("Couldn't create InputStream for file " + getFile() + ". Returning null.");
 +      log.error(e);
 +
 +      return null;
 +    }
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.PdfDataSource#getLength()
 +   */
 +  public int getLength()
 +  {
 +    return this.length;
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedTextDataSourceImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedTextDataSourceImpl.java new file mode 100644 index 0000000..6f6c7b4 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedTextDataSourceImpl.java @@ -0,0 +1,124 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.input;
 +
 +import java.io.File;
 +import java.io.FileInputStream;
 +import java.io.FileNotFoundException;
 +import java.io.IOException;
 +import java.io.InputStream;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.gv.egiz.pdfas.framework.input.TextDataSource;
 +
 +/**
 + * @author wprinz
 + * 
 + */
 +public class FileBasedTextDataSourceImpl implements TextDataSource, FileBased
 +{
 +  /**
 +   * The log.
 +   */
 +  private static final Log log = LogFactory.getLog(FileBasedTextDataSourceImpl.class);
 +
 +  protected File file = null;
 +
 +  protected String characterEncoding = null;
 +
 +  public FileBasedTextDataSourceImpl(File file, String characterEncoding) throws IOException
 +  {
 +    if (!file.exists())
 +    {
 +      throw new FileNotFoundException("The file '" + file + "' does not exist.");
 +    }
 +    if (!file.canRead())
 +    {
 +      throw new IOException("The file '" + file + "' cannot be read.");
 +    }
 +
 +    this.file = file;
 +    this.characterEncoding = characterEncoding;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.impl.input.FileBased#getFile()
 +   */
 +  public File getFile()
 +  {
 +    return this.file;
 +  }
 +
 +  /**
 +   * Returns the character encoding.
 +   * 
 +   * @return Returns the character encoding.
 +   */
 +  public String getCharacterEncoding()
 +  {
 +    return this.characterEncoding;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.TextDataSource#getText()
 +   */
 +  public String getText()
 +  {
 +    try
 +    {
 +      InputStream is = createInputStream();
 +      byte[] data = new byte[getLength()];
 +      int read = 0;
 +      int n = 0;
 +      while ((n = is.read(data, read, data.length - read)) > 0)
 +      {
 +        read += n;
 +      }
 +      is.close();
 +
 +      String text = new String(data, getCharacterEncoding());
 +
 +      data = null;
 +
 +      return text;
 +    }
 +    catch (IOException e)
 +    {
 +      log.error("Couldn't read text for file " + getFile() + ". Returning null.");
 +      log.error(e);
 +
 +      return null;
 +    }
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.DataSource#createInputStream()
 +   */
 +  public InputStream createInputStream()
 +  {
 +    try
 +    {
 +      FileInputStream fis = new FileInputStream(getFile());
 +      return fis;
 +    }
 +    catch (IOException e)
 +    {
 +      log.error("Couldn't create InputStream for file " + getFile() + ". Returning null.");
 +      log.error(e);
 +
 +      return null;
 +    }
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.DataSource#getLength()
 +   */
 +  public int getLength()
 +  {
 +    return (int) getFile().length();
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/IncrementalUpdateParser.java b/src/main/java/at/gv/egiz/pdfas/impl/input/IncrementalUpdateParser.java new file mode 100644 index 0000000..b4c2bef --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/IncrementalUpdateParser.java @@ -0,0 +1,49 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.input;
 +
 +import java.util.List;
 +
 +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper;
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException;
 +import at.knowcenter.wag.exactparser.ParseDocument;
 +
 +/**
 + * Parses the given PDF document into a list of Incremental Update blocks.
 + * @author wprinz
 + */
 +public class IncrementalUpdateParser
 +{
 +  /**
 +   * The log.
 +   */
 +  private static final Log log = LogFactory.getLog(IncrementalUpdateParser.class);
 +  
 +  public static List parsePdfIntoIUBlocks (PdfDataSource pdfDataSource) throws PDFDocumentException
 +  {
 +    log.trace("parsePdfIntoIUBlocks:");
 +    
 +    List blocks = null;
 +    try
 +    {
 +      byte [] pdf = DataSourceHelper.convertDataSourceToByteArray(pdfDataSource);
 +      blocks = ParseDocument.parseDocument(pdf);
 +    }
 +    catch (Exception e)
 +    {
 +      log.error("Error while parsing Document into IU blocks.", e);
 +      throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e);
 +    }
 +
 +    log.trace("parsePdfIntoIUBlocks finished.");
 +    return blocks;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/TextDataSourceImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/input/TextDataSourceImpl.java new file mode 100644 index 0000000..b259a3e --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/TextDataSourceImpl.java @@ -0,0 +1,82 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.input;
 +
 +import java.io.ByteArrayInputStream;
 +import java.io.InputStream;
 +import java.io.UnsupportedEncodingException;
 +
 +import at.gv.egiz.pdfas.framework.input.TextDataSource;
 +
 +/**
 + * A TextDataSource that keeps the text in memory.
 + * 
 + * <p>
 + * Keeping the text in memory is fast as long as the text is short, but may
 + * result in bad memory performance when the text is longer. Use a FileBased
 + * TextDataSource instead if memory is an issue.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public class TextDataSourceImpl implements TextDataSource
 +{
 +  /**
 +   * The text.
 +   */
 +  protected String text = null;
 +
 +  /**
 +   * Constructor that sets the text.
 +   * 
 +   * @param text
 +   *          The text.
 +   */
 +  public TextDataSourceImpl(String text)
 +  {
 +    this.text = text;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.TextDataSource#getText()
 +   */
 +  public String getText()
 +  {
 +    return this.text;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.DataSource#createInputStream()
 +   */
 +  public InputStream createInputStream()
 +  {
 +    try
 +    {
 +      byte[] data = getText().getBytes("UTF-8");
 +      // PERF: if memory is an issue (e.g. in web), use a FileBased TextDataSource instead.
 +      return new ByteArrayInputStream(data);
 +    }
 +    catch (UnsupportedEncodingException e)
 +    {
 +      throw new RuntimeException(e);
 +    }
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.input.DataSource#getLength()
 +   */
 +  public int getLength()
 +  {
 +    try
 +    {
 +      byte[] data = getText().getBytes("UTF-8");
 +      return data.length;
 +    }
 +    catch (UnsupportedEncodingException e)
 +    {
 +      throw new RuntimeException(e);
 +    }
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java b/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java new file mode 100644 index 0000000..1e2ffdc --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java @@ -0,0 +1,92 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.input.helper;
 +
 +import java.io.File;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +import java.io.InputStream;
 +
 +import at.gv.egiz.pdfas.performance.PerformanceCounters;
 +import at.gv.egiz.pdfas.framework.input.DataSource;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +/**
 + * @author wprinz
 + * 
 + */
 +public class DataSourceHelper
 +{
 +  /**
 +   * The log.
 +   */
 +  private static final Log log = LogFactory.getLog(DataSourceHelper.class);
 +
 +  /**
 +   * Converts a PdfDataSource to a byte array.
 +   * 
 +   * <p>
 +   * Note that this function is very memory intensive. Use the Streams whereever
 +   * possible.
 +   * </p>
 +   * 
 +   * @deprecated
 +   * 
 +   * @param pdfDataSource
 +   * @return
 +   * @throws IOException
 +   */
 +  public static byte[] convertDataSourceToByteArray(DataSource pdfDataSource)
 +  {
 +    try
 +    {
 +      PerformanceCounters.byteArrays.increment();
 +
 +      byte[] data = new byte[pdfDataSource.getLength()];
 +
 +      int bytes_written = 0;
 +
 +      InputStream is = pdfDataSource.createInputStream();
 +      int n = 0;
 +      while ((n = is.read(data, bytes_written, data.length - bytes_written)) > 0)
 +      {
 +        bytes_written += n;
 +      }
 +      is.close();
 +
 +      assert bytes_written == data.length;
 +
 +      return data;
 +    }
 +    catch (IOException e)
 +    {
 +      log.error(e);
 +      throw new RuntimeException(e);
 +    }
 +  }
 +  
 +  public static void debugDataSourceToFile(DataSource dataSource, File file)
 +  {
 +    try
 +    {
 +      InputStream is = dataSource.createInputStream();
 +      FileOutputStream fos = new FileOutputStream(file);
 +      byte[] data = new byte[2048];
 +      int n = -1;
 +      while ((n = is.read(data)) > 0)
 +      {
 +        fos.write(data, 0, n);
 +      }
 +      is.close();
 +      fos.close();
 +    }
 +    catch (IOException e)
 +    {
 +      log.error(e);
 +    }
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/output/ByteArrayDataSink.java b/src/main/java/at/gv/egiz/pdfas/impl/output/ByteArrayDataSink.java new file mode 100644 index 0000000..f3d1283 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/output/ByteArrayDataSink.java @@ -0,0 +1,83 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.output;
 +
 +import java.io.ByteArrayOutputStream;
 +import java.io.OutputStream;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.gv.egiz.pdfas.framework.output.DataSink;
 +import at.gv.egiz.pdfas.performance.PerformanceCounters;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class ByteArrayDataSink implements DataSink
 +{
 +  /**
 +   * The log.
 +   */
 +  private static final Log log = LogFactory.getLog(ByteArrayDataSink.class);
 +
 +  protected String mimeType = null;
 +  protected String characterEncoding = null;
 +  
 +  protected ByteArrayOutputStream baos = null;
 +
 +  
 +  public ByteArrayDataSink()
 +  {
 +    PerformanceCounters.byteArrays.increment();
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.output.DataSink#createOutputStream(java.lang.String)
 +   */
 +  public OutputStream createOutputStream(String mimeType)
 +  {
 +    return createOutputStream(mimeType, null);
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.output.DataSink#createOutputStream(java.lang.String, java.lang.String)
 +   */
 +  public OutputStream createOutputStream(String mimeType, String characterEncoding)
 +  {
 +    if (this.baos != null)
 +    {
 +      log.warn("An output stream is created twice. The old one will be rendered useless.");
 +    }
 +    this.baos = new ByteArrayOutputStream(4096);
 +    return this.baos;
 +  }
 +  
 +  /**
 +   * Returns the byte array.
 +   * @return Returns the byte array.
 +   */
 +  public byte [] getByteArray ()
 +  {
 +    return this.baos.toByteArray();
 +  }
 +
 +  /**
 +   * @return the mimeType
 +   */
 +  public String getMimeType()
 +  {
 +    return this.mimeType;
 +  }
 +
 +  /**
 +   * @return the characterEncoding
 +   */
 +  public String getCharacterEncoding()
 +  {
 +    return this.characterEncoding;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/output/FileBasedDataSink.java b/src/main/java/at/gv/egiz/pdfas/impl/output/FileBasedDataSink.java new file mode 100644 index 0000000..4e1e3b7 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/output/FileBasedDataSink.java @@ -0,0 +1,126 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.output;
 +
 +import java.io.File;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +import java.io.OutputStream;
 +
 +import at.gv.egiz.pdfas.framework.output.DataSink;
 +import at.gv.egiz.pdfas.impl.input.FileBased;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +/**
 + * @author wprinz
 + * 
 + */
 +public class FileBasedDataSink implements DataSink, FileBased
 +{
 +  /**
 +   * The log.
 +   */
 +  private static final Log log = LogFactory.getLog(FileBasedDataSink.class);
 +
 +  protected String mimeType = null;
 +  protected String characterEncoding = null;
 +  
 +  /**
 +   * The output file.
 +   */
 +  protected File outputFile = null;
 +
 +  /**
 +   * Creates a file based PdfDataSink.
 +   * 
 +   * @param file
 +   *          The file.
 +   * @throws IOException
 +   *           F.e.
 +   */
 +  public FileBasedDataSink(File file) throws IOException
 +  {
 +    if (!file.exists())
 +    {
 +      file.createNewFile();
 +    }
 +    if (!file.isFile())
 +    {
 +      throw new IOException("The file '" + file + "' is not a normal file.");
 +    }
 +    if (!file.canWrite())
 +    {
 +      throw new IOException("The file '" + file + "' cannot be written.");
 +    }
 +
 +    this.outputFile = file;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.impl.input.FileBased#getFile()
 +   */
 +  public File getFile()
 +  {
 +    return this.outputFile;
 +  }
 +  
 +  
 +
 +  protected OutputStream createOutputStream()
 +  {
 +    try
 +    {
 +      FileOutputStream fos = new FileOutputStream(getFile());
 +      return fos;
 +    }
 +    catch (IOException e)
 +    {
 +      log.error("Couldn't create OutputStream for file " + getFile() + ". Returning null.");
 +      log.error(e);
 +
 +      return null;
 +
 +    }
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.output.DataSink#createOutputStream(java.lang.String)
 +   */
 +  public OutputStream createOutputStream(String mimeType)
 +  {
 +    return createOutputStream(mimeType, null);
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.output.DataSink#createOutputStream(java.lang.String, java.lang.String)
 +   */
 +  public OutputStream createOutputStream(String mimeType, String characterEncoding)
 +  {
 +    this.mimeType = mimeType;
 +    this.characterEncoding = characterEncoding;
 +    
 +    return createOutputStream();
 +  }
 +
 +  /**
 +   * @return the mimeType
 +   */
 +  public String getMimeType()
 +  {
 +    return mimeType;
 +  }
 +
 +  /**
 +   * @return the characterEncoding
 +   */
 +  public String getCharacterEncoding()
 +  {
 +    return characterEncoding;
 +  }
 +
 +
 +  
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java new file mode 100644 index 0000000..a95cdc6 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java @@ -0,0 +1,45 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.signator;
 +
 +import java.util.List;
 +
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.gv.egiz.pdfas.framework.output.DataSink;
 +import at.gv.egiz.pdfas.impl.output.ByteArrayDataSink;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature;
 +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation;
 +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction;
 +
 +import com.lowagie.text.pdf.PdfPTable;
 +
 +/**
 + * @author wprinz
 + */
 +public final class IncrementalUpdateHelper
 +{
 +  public static IncrementalUpdateInformation writeIncrementalUpdate(PdfDataSource pdfDataSource, PdfPTable pdf_table, PositioningInstruction pi, List variable_field_definitions,
 +      List all_field_definitions) throws PresentableException
 +  {
 +    // PERF: binary sig needs the signed_pdf as byte array
 +    ByteArrayDataSink bads = new ByteArrayDataSink();
 +    IncrementalUpdateInformation iui = BinarySignature.writeIncrementalUpdate(pdfDataSource, bads, pdf_table, pi, variable_field_definitions, all_field_definitions);
 +    iui.signed_pdf = bads.getByteArray();
 +    bads = null;
 +
 +    return iui;
 +  }
 +
 +  public static void writeIncrementalUpdateToDataSink(PdfDataSource pdfDataSource, DataSink dataSink, PdfPTable pdf_table, PositioningInstruction pi) throws PresentableException
 +  {
 +    writeIncrementalUpdateToDataSink(pdfDataSource, dataSink, pdf_table, pi, null, null);
 +  }
 +
 +  public static void writeIncrementalUpdateToDataSink(PdfDataSource pdfDataSource, DataSink dataSink, PdfPTable pdf_table, PositioningInstruction pi, List variable_field_definitions,
 +      List all_field_definitions) throws PresentableException
 +  {
 +    BinarySignature.writeIncrementalUpdate(pdfDataSource, dataSink, pdf_table, pi, variable_field_definitions, all_field_definitions);
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/SignatorInformationImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/SignatorInformationImpl.java new file mode 100644 index 0000000..d07dc6a --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/SignatorInformationImpl.java @@ -0,0 +1,20 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.signator;
 +
 +import at.knowcenter.wag.egov.egiz.sig.SignatureData;
 +import at.gv.egiz.pdfas.framework.signator.SignatorInformation;
 +
 +/**
 + * @author wprinz
 + */
 +public abstract class SignatorInformationImpl implements SignatorInformation
 +{
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getSignatureData()
 +   */
 +  public abstract SignatureData getSignatureData();
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java new file mode 100644 index 0000000..916abf4 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java @@ -0,0 +1,51 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.signator.binary;
 +
 +import java.util.List;
 +
 +import at.knowcenter.wag.egov.egiz.sig.SignatureData;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.gv.egiz.pdfas.framework.signator.SignatorInformation;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class BinarySignatorInformation implements SignatorInformation
 +{
 +  protected PdfDataSource originalDocument = null;
 +  
 +  protected byte [] incrementalUpdateBlock = null;
 +  
 +  protected SignatureData signatureData = null;
 +  
 +  protected List replaces = null;
 +  
 +  protected int cert_start = -1;
 +  protected int cert_length = -1;
 +  
 +  protected int enc_start = -1;
 +  protected int enc_length = -1;
 +  
 +  protected SignSignatureObject signSignatureObject = null;
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getSignatureData()
 +   */
 +  public SignatureData getSignatureData()
 +  {
 +    return this.signatureData;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#setSignSignatureObject(at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject)
 +   */
 +  public void setSignSignatureObject(SignSignatureObject signSignatureObject)
 +  {
 +    this.signSignatureObject = signSignatureObject;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java new file mode 100644 index 0000000..6c6ba29 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java @@ -0,0 +1,326 @@ +/**
 + * <copyright> Copyright (c) 2006 by Know-Center, Graz, Austria </copyright>
 + * 
 + * This software is the confidential and proprietary information of Know-Center,
 + * Graz, Austria. You shall not disclose such Confidential Information and shall
 + * use it only in accordance with the terms of the license agreement you entered
 + * into with Know-Center.
 + * 
 + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 + * DERIVATIVES.
 + * 
 + * $Id: BinarySignator_1_0_0.java,v 1.1 2006/08/25 17:07:35 wprinz Exp $
 + */
 +package at.gv.egiz.pdfas.impl.signator.binary;
 +
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.OutputStream;
 +import java.io.UnsupportedEncodingException;
 +import java.util.ArrayList;
 +import java.util.Iterator;
 +import java.util.List;
 +
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +import at.gv.egiz.pdfas.exceptions.framework.SignatorException;
 +import at.gv.egiz.pdfas.framework.input.DataSource;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.gv.egiz.pdfas.framework.output.DataSink;
 +import at.gv.egiz.pdfas.framework.signator.Signator;
 +import at.gv.egiz.pdfas.framework.signator.SignatorInformation;
 +import at.gv.egiz.pdfas.impl.input.CompoundPdfDataSourceImpl;
 +import at.gv.egiz.pdfas.impl.signator.IncrementalUpdateHelper;
 +import at.knowcenter.wag.egov.egiz.PdfAS;
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
 +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature;
 +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation;
 +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction;
 +import at.knowcenter.wag.egov.egiz.pdf.ReplaceInfo;
 +import at.knowcenter.wag.egov.egiz.pdf.StringInfo;
 +import at.knowcenter.wag.egov.egiz.pdf.TablePos;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureData;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureFieldDefinition;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureObject;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObjectHelper;
 +import at.knowcenter.wag.exactparser.ByteArrayUtils;
 +
 +import com.lowagie.text.pdf.PdfPTable;
 +
 +/**
 + * Signs the document binary.
 + * 
 + * <p>
 + * In prepareSign, an Incremental Update is created that contains the Signature
 + * block and the egiz dictionary. For formatting the layout, variable values are
 + * filled with placeholders. After the layout has been fixed, all variable
 + * fields (all holes in the byte ranges) are replaced with 0. This document is
 + * then base64 encoded and signed.
 + * </p>
 + * <p>
 + * In finishSign, the variable fields (values, /Cert) are replaced with the
 + * values according to the encoding.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public class BinarySignator_1_0_0 implements Signator
 +{
 +  /**
 +   * The Pdf-AS ID of this Signator.
 +   */
 +  public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_0_0);
 +
 +  /**
 +   * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId()
 +   */
 +  public PdfASID getMyId()
 +  {
 +    return MY_ID;
 +  }
 +
 +  /**
 +   * Default constructor.
 +   */
 +  public BinarySignator_1_0_0()
 +  {
 +    // Default constructor.
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.signator.Signator#prepareSign(at.gv.egiz.pdfas.framework.input.PdfDataSource,
 +   *      java.lang.String, at.knowcenter.wag.egov.egiz.pdf.TablePos, boolean)
 +   */
 +  public SignatorInformation prepareSign(PdfDataSource pdfDataSource, String profile, TablePos pos, boolean has_SIG_ID) throws SignatorException
 +  {
 +    try
 +    {
 +      SignatureObject signature_object = PdfAS.createSignatureObjectFromType(profile);
 +      signature_object.fillValues((char) BinarySignature.LAYOUT_PLACEHOLDER, has_SIG_ID);
 +
 +      signature_object.setKZ(getMyId());
 +
 +      PdfPTable pdf_table = PdfAS.createPdfPTableFromSignatureObject(signature_object);
 +
 +      PositioningInstruction pi = PdfAS.determineTablePositioning(pos, profile, pdfDataSource, pdf_table);
 +
 +      List all_field_definitions = signature_object.getSignatureTypeDefinition().getFieldDefinitions();
 +      List variable_field_definitions = new ArrayList();
 +      for (int i = 0; i < all_field_definitions.size(); i++)
 +      {
 +        SignatureFieldDefinition sfd = (SignatureFieldDefinition) all_field_definitions.get(i);
 +        if (sfd.placeholder_length > 0)
 +        {
 +          if (sfd.field_name.equals(SignatureTypes.SIG_ID) && has_SIG_ID == false)
 +          {
 +            continue;
 +          }
 +          variable_field_definitions.add(sfd);
 +        }
 +      }
 +      
 +      IncrementalUpdateInformation iui = IncrementalUpdateHelper.writeIncrementalUpdate(pdfDataSource, pdf_table, pi, variable_field_definitions, all_field_definitions);
 +
 +      String temp_string = iui.temp_ir_number + " " + iui.temp_ir_generation + " obj"; //$NON-NLS-1$//$NON-NLS-2$
 +      byte[] temp_bytes = temp_string.getBytes("US-ASCII"); //$NON-NLS-1$
 +      int temp_start = ByteArrayUtils.lastIndexOf(iui.signed_pdf, temp_bytes);
 +      byte[] stream_bytes = new byte[] { '>', '>', 's', 't', 'r', 'e', 'a', 'm', 0x0A };
 +      int stream_start = ByteArrayUtils.indexOf(iui.signed_pdf, temp_start, stream_bytes);
 +      iui.content_stream_start = stream_start + stream_bytes.length;
 +
 +      // update the stream indices
 +      Iterator it = iui.replaces.iterator();
 +      while (it.hasNext())
 +      {
 +        ReplaceInfo ri = (ReplaceInfo) it.next();
 +
 +        Iterator sit = ri.replaces.iterator();
 +        while (sit.hasNext())
 +        {
 +          StringInfo si = (StringInfo) sit.next();
 +          si.string_start += iui.content_stream_start;
 +        }
 +      }
 +      // update KZ list indices:
 +      it = iui.kz_list.iterator();
 +      while (it.hasNext())
 +      {
 +        StringInfo si = (StringInfo) it.next();
 +        si.string_start += iui.content_stream_start;
 +      }
 +
 +      BinarySignature.markByteRanges(iui);
 +
 +      // byte [] old_signed_pdf = iui.signed_pdf;
 +      iui.signed_pdf = BinarySignature.prepareDataToSign(iui.signed_pdf, iui.byte_ranges);
 +
 +      BinarySignatorInformation bsi = compressIUI(iui);
 +      return bsi;
 +
 +    }
 +    catch (UnsupportedEncodingException e)
 +    {
 +      throw new SignatorException(201, e);
 +    }
 +    catch (PDFDocumentException e)
 +    {
 +      throw new SignatorException(e.getErrorCode(), e);
 +    }
 +    catch (PresentableException e)
 +    {
 +      throw new SignatorException(201, e);
 +    }
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.signator.Signator#finishSign(at.gv.egiz.pdfas.framework.signator.SignatorInformation,
 +   *      at.gv.egiz.pdfas.framework.output.DataSink)
 +   */
 +  public void finishSign(SignatorInformation signatorInformation, DataSink dataSink) throws SignatorException
 +  {
 +    try
 +    {
 +      IncrementalUpdateInformation iui = uncompressIUI((BinarySignatorInformation) signatorInformation);
 +
 +      // PERF: need to keep the whole pdf in mem for processing
 +
 +      // PdfAS.prefixID(iui.signed_signature_object, PdfAS.BINARY_ID);
 +      fillReplacesWithValues(iui);
 +
 +      BinarySignature.replaceCertificate(iui);
 +      BinarySignature.replacePlaceholders(iui);
 +
 +      OutputStream os = dataSink.createOutputStream(PdfAS.PDF_MIME_TYPE);
 +      os.write(iui.signed_pdf);
 +      os.close();
 +      
 +      //SignResult sign_result = new SignResult(PdfAS.PDF_MIME_TYPE, iui.signed_pdf);
 +      //return sign_result;
 +    }
 +    catch (PDFDocumentException e)
 +    {
 +      throw new SignatorException(e.getErrorCode(), e);
 +    }
 +    catch (IOException e)
 +    {
 +      throw new SignatorException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e);
 +    }
 +  }
 +
 +  /**
 +   * Reads the signature values from the signed signature object and fills the
 +   * corresponding value in the Replaces array.
 +   * 
 +   * @param iui
 +   *          The IncrementalUpdateInformation.
 +   */
 +  protected void fillReplacesWithValues(IncrementalUpdateInformation iui)
 +  {
 +    Iterator it = iui.replaces.iterator();
 +    while (it.hasNext())
 +    {
 +      ReplaceInfo ri = (ReplaceInfo) it.next();
 +
 +      ri.value = SignSignatureObjectHelper.retrieveStringValueFromSignatureObject(iui.signed_signature_object, ri.sfd.field_name);
 +    }
 +  }
 +
 +  /**
 +   * Forms the SignatureData to be used for signing.
 +   * 
 +   * @param iui
 +   *          The IncrementalUpdateInformation.
 +   * @return Returns the SignatureData to be used for signing.
 +   */
 +  protected SignatureData formSignatureData(IncrementalUpdateInformation iui)
 +  {
 +    // String document_text =
 +    // BinarySignature.retrieveSignableTextFromData(iui.signed_pdf,
 +    // iui.signed_pdf.length); // signed_pdf.length);
 +    //
 +    // byte[] data;
 +    // try
 +    // {
 +    // data = document_text.getBytes("UTF-8"); //$NON-NLS-1$
 +    // }
 +    // catch (UnsupportedEncodingException e)
 +    // {
 +    // throw new RuntimeException("Very strange: UTF-8 character encoding not
 +    // supported.", e); //$NON-NLS-1$
 +    // }
 +    DataSource ds = new CompoundPdfDataSourceImpl(iui.original_document, iui.sign_iui_block);
 +    SignatureData signature_data = new SignatureDataImpl(ds, PdfAS.PDF_MIME_TYPE);
 +
 +    return signature_data;
 +  }
 +
 +  protected BinarySignatorInformation compressIUI(IncrementalUpdateInformation iui)
 +  {
 +    iui.sign_iui_block = new byte[iui.signed_pdf.length - iui.original_document.getLength()];
 +    System.arraycopy(iui.signed_pdf, iui.original_document.getLength(), iui.sign_iui_block, 0, iui.sign_iui_block.length);
 +
 +    iui.signature_data = formSignatureData(iui);
 +
 +    // remove the signed pdf from memory
 +    iui.signed_pdf = null;
 +
 +    BinarySignatorInformation bsi = new BinarySignatorInformation();
 +    bsi.originalDocument = iui.original_document;
 +    bsi.incrementalUpdateBlock = iui.sign_iui_block;
 +    bsi.signatureData = iui.signature_data;
 +    bsi.replaces = iui.replaces;
 +    bsi.cert_start = iui.cert_start;
 +    bsi.cert_length = iui.cert_length;
 +    bsi.enc_start = iui.enc_start;
 +    bsi.enc_length = iui.enc_length;
 +
 +    return bsi;
 +  }
 +
 +  protected IncrementalUpdateInformation uncompressIUI(BinarySignatorInformation bsi)
 +  {
 +    IncrementalUpdateInformation iui = new IncrementalUpdateInformation();
 +
 +    iui.original_document = bsi.originalDocument;
 +    iui.sign_iui_block = bsi.incrementalUpdateBlock;
 +    iui.signature_data = bsi.signatureData;
 +    iui.replaces = bsi.replaces;
 +    iui.cert_start = bsi.cert_start;
 +    iui.cert_length = bsi.cert_length;
 +    iui.enc_start = bsi.enc_start;
 +    iui.enc_length = bsi.enc_length;
 +    
 +    iui.signed_signature_object = bsi.signSignatureObject;
 +
 +    restoreSignedPdf(iui);
 +
 +    return iui;
 +  }
 +
 +  protected void restoreSignedPdf(IncrementalUpdateInformation iui)
 +  {
 +    iui.signed_pdf = new byte[iui.original_document.getLength() + iui.sign_iui_block.length];
 +
 +    try
 +    {
 +      InputStream is = iui.original_document.createInputStream();
 +      is.read(iui.signed_pdf, 0, iui.original_document.getLength());
 +      is.close();
 +    }
 +    catch (IOException e)
 +    {
 +      throw new RuntimeException(e);
 +    }
 +
 +    System.arraycopy(iui.sign_iui_block, 0, iui.signed_pdf, iui.original_document.getLength(), iui.sign_iui_block.length);
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_1_0.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_1_0.java new file mode 100644 index 0000000..7ab62fc --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_1_0.java @@ -0,0 +1,69 @@ +/**
 + * <copyright> Copyright (c) 2006 by Know-Center, Graz, Austria </copyright>
 + * 
 + * This software is the confidential and proprietary information of Know-Center,
 + * Graz, Austria. You shall not disclose such Confidential Information and shall
 + * use it only in accordance with the terms of the license agreement you entered
 + * into with Know-Center.
 + * 
 + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 + * DERIVATIVES.
 + * 
 + * $Id: BinarySignator_1_0_0.java,v 1.1 2006/08/25 17:07:35 wprinz Exp $
 + */
 +package at.gv.egiz.pdfas.impl.signator.binary;
 +
 +import at.gv.egiz.pdfas.impl.input.CompoundPdfDataSourceImpl;
 +import at.gv.egiz.pdfas.framework.input.DataSource;
 +import at.knowcenter.wag.egov.egiz.PdfAS;
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
 +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureData;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl;
 +
 +/**
 + * Signs the document binary.
 + * 
 + * <p>
 + * This just differs from version 1.0.0 in the fact that the signature data is
 + * the actual binary PDF instead of a Base64 encoding.
 + * </p>
 + * 
 + * @see BinarySignator_1_0_0
 + * 
 + * @author wprinz
 + */
 +public class BinarySignator_1_1_0 extends BinarySignator_1_0_0
 +{
 +  /**
 +   * The Pdf-AS ID of this Signator.
 +   */
 +  public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_1_0);
 +    
 +  /**
 +   * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId()
 +   */
 +  public PdfASID getMyId()
 +  {
 +    return MY_ID;
 +  }
 +
 +  /**
 +   * Overrides the SignatureData generation of the BinarySignator 1.0.0 so that
 +   * the SignatureData is the actual binary PDF instead of a Base64 encoding.
 +   * 
 +   * @see at.knowcenter.wag.egov.egiz.framework.signators.BinarySignator_1_0_0#formSignatureData(at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation)
 +   */
 +  protected SignatureData formSignatureData(IncrementalUpdateInformation iui)
 +  {
 +    DataSource ds = new CompoundPdfDataSourceImpl(iui.original_document, iui.sign_iui_block);
 +    SignatureData signature_data = new SignatureDataImpl(ds, PdfAS.PDF_MIME_TYPE);
 +
 +    return signature_data;
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/detached/DetachedTextualSignator_1_0_0.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/detached/DetachedTextualSignator_1_0_0.java new file mode 100644 index 0000000..6a242b6 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/detached/DetachedTextualSignator_1_0_0.java @@ -0,0 +1,142 @@ +/**
 + * <copyright> Copyright (c) 2006 by Know-Center, Graz, Austria </copyright>
 + * 
 + * This software is the confidential and proprietary information of Know-Center,
 + * Graz, Austria. You shall not disclose such Confidential Information and shall
 + * use it only in accordance with the terms of the license agreement you entered
 + * into with Know-Center.
 + * 
 + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 + * DERIVATIVES.
 + * 
 + * $Id: TextualSignator_1_0_0.java,v 1.3 2006/10/31 08:07:50 wprinz Exp $
 + */
 +package at.gv.egiz.pdfas.impl.signator.detached;
 +
 +import java.io.IOException;
 +import java.io.OutputStream;
 +import java.io.OutputStreamWriter;
 +
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +import at.gv.egiz.pdfas.exceptions.framework.SignatorException;
 +import at.gv.egiz.pdfas.framework.SignatorFactory;
 +import at.gv.egiz.pdfas.framework.output.DataSink;
 +import at.gv.egiz.pdfas.framework.signator.SignatorInformation;
 +import at.gv.egiz.pdfas.impl.signator.textual.TextualSignatorInformation;
 +import at.gv.egiz.pdfas.impl.signator.textual.TextualSignator_1_0_0;
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection;
 +
 +/**
 + * Signs a document textually.
 + * 
 + * <p>
 + * In prepareSign, the document text is extracted and normalized.
 + * </p>
 + * <p>
 + * In finishSign, the signed SignatureObject is transformed into a Signature
 + * block, which is then written as an Incremental Update.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public class DetachedTextualSignator_1_0_0 extends TextualSignator_1_0_0
 +{
 +  /**
 +   * The Mime Type.
 +   */
 +  public static final String MIME_TYPE = "text/xml"; //$NON-NLS-1$
 +
 +  /**
 +   * The Pdf-AS ID of this Signator.
 +   */
 +  public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_DETACHED_TEXTUAL, SignatorFactory.VERSION_1_0_0);
 +
 +  /**
 +   * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId()
 +   */
 +  public PdfASID getMyId()
 +  {
 +    return MY_ID;
 +  }
 +
 +  // /**
 +  // * <p>
 +  // * The parameter has_SIG_ID is not used by this Signator because it doesn't
 +  // * pre-format the signature block.
 +  // * </p>
 +  // *
 +  // * @see at.knowcenter.wag.egov.egiz.framework.Signator#prepareSign(byte[],
 +  // * String, TablePos, boolean)
 +  // */
 +  // public IncrementalUpdateInformation prepareSign(PdfDataSource pdf,
 +  // String signature_type, TablePos pos, boolean has_SIG_ID) throws
 +  // PresentableException
 +  // {
 +  // IncrementalUpdateInformation iui = new IncrementalUpdateInformation();
 +  // iui.original_document = pdf;
 +  // iui.signature_type = signature_type;
 +  // iui.pos = pos;
 +  //
 +  // String document_text =
 +  // PdfAS.extractNormalizedTextTextual(pdf.createInputStream());
 +  // // logger_.debug("signed_text = " + document_text);
 +  //    
 +  // DataSource ds = new TextDataSourceImpl(document_text);
 +  // iui.signature_data = new SignatureDataImpl(ds, MIME_TYPE, "UTF-8");
 +  // //$NON-NLS-1$ //$NON-NLS-2$
 +  //
 +  // return iui;
 +  // }
 +  //
 +  // /**
 +  // * @see
 +  // at.knowcenter.wag.egov.egiz.framework.Signator#finishSign(at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation)
 +  // */
 +  // public SignResult finishSign(IncrementalUpdateInformation iui) throws
 +  // PresentableException
 +  // {
 +  // try
 +  // {
 +  // String response =
 +  // iui.signed_signature_object.response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY);
 +  // byte[] response_bytes = response.getBytes("UTF-8"); //$NON-NLS-1$
 +  //
 +  // SignResult sign_result = new SignResult(MIME_TYPE, response_bytes);
 +  // return sign_result;
 +  // }
 +  // catch (UnsupportedEncodingException e)
 +  // {
 +  // e.printStackTrace();
 +  // throw new PDFDocumentException(300, e);
 +  // }
 +  // }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.impl.signator.textual.TextualSignator_1_0_0#finishSign(at.gv.egiz.pdfas.framework.signator.SignatorInformation,
 +   *      at.gv.egiz.pdfas.framework.output.DataSink)
 +   */
 +  public void finishSign(SignatorInformation signatorInformation, DataSink dataSink) throws SignatorException
 +  {
 +    try
 +    {
 +      TextualSignatorInformation tsi = (TextualSignatorInformation) signatorInformation;
 +
 +      String response = tsi.signSignatureObject.response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY);
 +
 +      OutputStream os = dataSink.createOutputStream(MIME_TYPE, "UTF-8");
 +      OutputStreamWriter osw = new OutputStreamWriter(os);
 +      osw.write(response);
 +      osw.close();
 +    }
 +    catch (IOException e)
 +    {
 +      throw new SignatorException(ErrorCode.SIGNATURE_COULDNT_BE_CREATED, e);
 +    }
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java new file mode 100644 index 0000000..c5b18ff --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java @@ -0,0 +1,45 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.signator.textual;
 +
 +import at.knowcenter.wag.egov.egiz.pdf.TablePos;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureData;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.gv.egiz.pdfas.framework.signator.SignatorInformation;
 +
 +/**
 + * @author wprinz
 + * 
 + */
 +public class TextualSignatorInformation implements SignatorInformation
 +{
 +  protected PdfDataSource originalDocument = null;
 +
 +  protected SignatureData signatureData = null;
 +
 +  protected String profile = null;
 +
 +  protected TablePos pos = null;
 +
 +  public SignSignatureObject signSignatureObject = null;
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getSignatureData()
 +   */
 +  public SignatureData getSignatureData()
 +  {
 +    return this.signatureData;
 +  }
 +
 +  /**
 +   * 
 +   * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#setSignSignatureObject(at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject)
 +   */
 +  public void setSignSignatureObject(SignSignatureObject signSignatureObject)
 +  {
 +    this.signSignatureObject = signSignatureObject;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java new file mode 100644 index 0000000..b0494c8 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java @@ -0,0 +1,149 @@ +/**
 + * <copyright> Copyright (c) 2006 by Know-Center, Graz, Austria </copyright>
 + * 
 + * This software is the confidential and proprietary information of Know-Center,
 + * Graz, Austria. You shall not disclose such Confidential Information and shall
 + * use it only in accordance with the terms of the license agreement you entered
 + * into with Know-Center.
 + * 
 + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 + * DERIVATIVES.
 + * 
 + * $Id: TextualSignator_1_0_0.java,v 1.3 2006/10/31 08:07:50 wprinz Exp $
 + */
 +package at.gv.egiz.pdfas.impl.signator.textual;
 +
 +import at.gv.egiz.pdfas.exceptions.framework.SignatorException;
 +import at.gv.egiz.pdfas.framework.input.DataSource;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.gv.egiz.pdfas.framework.output.DataSink;
 +import at.gv.egiz.pdfas.framework.signator.Signator;
 +import at.gv.egiz.pdfas.framework.signator.SignatorInformation;
 +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl;
 +import at.gv.egiz.pdfas.impl.signator.IncrementalUpdateHelper;
 +import at.knowcenter.wag.egov.egiz.PdfAS;
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
 +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction;
 +import at.knowcenter.wag.egov.egiz.pdf.TablePos;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureObject;
 +import at.knowcenter.wag.egov.egiz.sig.signatureobject.SignatureObjectHelper;
 +
 +import com.lowagie.text.pdf.PdfPTable;
 +
 +/**
 + * Signs a document textually.
 + * 
 + * <p>
 + * In prepareSign, the document text is extracted and normalized.
 + * </p>
 + * <p>
 + * In finishSign, the signed SignatureObject is transformed into a Signature
 + * block, which is then written as an Incremental Update.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public class TextualSignator_1_0_0 implements Signator
 +{
 +  /**
 +   * The Pdf-AS ID of this Signator.
 +   */
 +  public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEXTUAL, SignatorFactory.VERSION_1_0_0);
 +
 +  /**
 +   * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId()
 +   */
 +  public PdfASID getMyId()
 +  {
 +    return MY_ID;
 +  }
 +
 +  /**
 +   * Default constructor.
 +   */
 +  public TextualSignator_1_0_0()
 +  {
 +    // Default constructor.
 +  }
 +
 +  /**
 +   * <p>
 +   * The parameter has_SIG_ID is not used by this Signator because it doesn't
 +   * pre-format the signature block.
 +   * </p>
 +   * 
 +   * @see at.gv.egiz.pdfas.framework.signator.Signator#prepareSign(at.gv.egiz.pdfas.framework.input.PdfDataSource,
 +   *      java.lang.String, at.knowcenter.wag.egov.egiz.pdf.TablePos, boolean)
 +   */
 +  public SignatorInformation prepareSign(PdfDataSource pdfDataSource, String profile, TablePos pos, boolean has_SIG_ID) throws SignatorException
 +  {
 +    try
 +    {
 +      TextualSignatorInformation tsi = new TextualSignatorInformation();
 +      tsi.originalDocument = pdfDataSource;
 +      tsi.profile = profile;
 +      tsi.pos = pos;
 +
 +      String document_text = PdfAS.extractNormalizedTextTextual(pdfDataSource.createInputStream());
 +      // logger_.debug("signed_text = " + document_text);
 +
 +      DataSource ds = new TextDataSourceImpl(document_text);
 +      tsi.signatureData = new SignatureDataImpl(ds, "text/plain", "UTF-8");
 +
 +      return tsi;
 +    }
 +    catch (PresentableException pe)
 +    {
 +      throw new SignatorException(pe);
 +    }
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.signator.Signator#finishSign(at.gv.egiz.pdfas.framework.signator.SignatorInformation,
 +   *      at.gv.egiz.pdfas.framework.output.DataSink)
 +   */
 +  public void finishSign(SignatorInformation signatorInformation, DataSink dataSink) throws SignatorException
 +  {
 +    try
 +    {
 +      TextualSignatorInformation tsi = (TextualSignatorInformation) signatorInformation;
 +
 +      // PdfAS.prefixID(iui.signed_signature_object, PdfAS.TEXT_ID);
 +
 +      // iui.signed_signature_object.kz = getMyId().toString();
 +      tsi.signSignatureObject.kz = getMyId().toString();
 +      // TODO what is this for?
 +
 +      SignatureObject so = SignatureObjectHelper.convertSignSignatureObjectToSignatureObject(tsi.signSignatureObject, tsi.profile);
 +
 +      PdfPTable pdf_table = PdfAS.createPdfPTableFromSignatureObject(so);
 +
 +      PositioningInstruction pi = PdfAS.determineTablePositioning(tsi.pos, tsi.profile, tsi.originalDocument, pdf_table);
 +
 +      IncrementalUpdateHelper.writeIncrementalUpdateToDataSink(tsi.originalDocument, dataSink, pdf_table, pi);
 +
 +//      OutputStream os = dataSink.createOutputStream(PdfAS.PDF_MIME_TYPE);
 +//      os.write(signed_iui.signed_pdf);
 +//      os.close();
 +
 +//      SignResult sign_result = new SignResult(PdfAS.PDF_MIME_TYPE, signed_iui.signed_pdf);
 +//      return sign_result;
 +    }
 +    catch (PresentableException pe)
 +    {
 +      throw new SignatorException(pe);
 +    }
 +//    catch (IOException e)
 +//    {
 +//      throw new SignatorException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e);
 +//    }
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_1_0.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_1_0.java new file mode 100644 index 0000000..68cd3a1 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_1_0.java @@ -0,0 +1,45 @@ +/**
 + * <copyright> Copyright (c) 2006 by Know-Center, Graz, Austria </copyright>
 + * 
 + * This software is the confidential and proprietary information of Know-Center,
 + * Graz, Austria. You shall not disclose such Confidential Information and shall
 + * use it only in accordance with the terms of the license agreement you entered
 + * into with Know-Center.
 + * 
 + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 + * DERIVATIVES.
 + * 
 + * $Id: TextualSignator_1_0_0.java,v 1.3 2006/10/31 08:07:50 wprinz Exp $
 + */
 +package at.gv.egiz.pdfas.impl.signator.textual;
 +
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
 +
 +/**
 + * Signs a document textually.
 + *
 + * @see TextualSignator_1_0_0
 + * 
 + * @author wprinz
 + */
 +public class TextualSignator_1_1_0 extends TextualSignator_1_0_0
 +{
 +  /**
 +   * The Pdf-AS ID of this Signator.
 +   */
 +  public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEXTUAL, SignatorFactory.VERSION_1_1_0);
 +
 +  /**
 +   * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId()
 +   */
 +  public PdfASID getMyId()
 +  {
 +    return MY_ID;
 +  }
 +  
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_0_0.java b/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_0_0.java new file mode 100644 index 0000000..b52e97f --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_0_0.java @@ -0,0 +1,399 @@ +/**
 + * <copyright> Copyright (c) 2006 by Know-Center, Graz, Austria </copyright>
 + * 
 + * This software is the confidential and proprietary information of Know-Center,
 + * Graz, Austria. You shall not disclose such Confidential Information and shall
 + * use it only in accordance with the terms of the license agreement you entered
 + * into with Know-Center.
 + * 
 + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 + * DERIVATIVES.
 + * 
 + * $Id: BinaryVerificator_1_0_0.java,v 1.3 2006/10/11 08:03:22 wprinz Exp $
 + */
 +package at.gv.egiz.pdfas.impl.verificator.binary;
 +
 +import java.io.ByteArrayOutputStream;
 +import java.io.FileOutputStream;
 +import java.io.InputStream;
 +import java.util.ArrayList;
 +import java.util.Iterator;
 +import java.util.List;
 +
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.gv.egiz.pdfas.framework.verificator.Verificator;
 +import at.gv.egiz.pdfas.impl.input.ByteArrayPdfDataSourceImpl;
 +import at.gv.egiz.pdfas.impl.input.CompoundPdfDataSourceImpl;
 +import at.gv.egiz.pdfas.impl.input.DelimitedPdfDataSource;
 +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper;
 +
 +import org.apache.log4j.Logger;
 +
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger;
 +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
 +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
 +import at.knowcenter.wag.egov.egiz.framework.VerificationFilter;
 +import at.knowcenter.wag.egov.egiz.pdf.BinaryBlockInfo;
 +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature;
 +import at.knowcenter.wag.egov.egiz.pdf.BinarySignatureHolder;
 +import at.knowcenter.wag.egov.egiz.pdf.Placeholder;
 +import at.knowcenter.wag.egov.egiz.pdf.ReplaceInfo;
 +import at.knowcenter.wag.egov.egiz.pdf.StringInfo;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureObject;
 +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes;
 +import at.knowcenter.wag.exactparser.parsing.IndirectObjectReference;
 +import at.knowcenter.wag.exactparser.parsing.PDFUtils;
 +import at.knowcenter.wag.exactparser.parsing.results.ArrayParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.DictionaryParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.IndirectObjectReferenceParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.NameParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.NumberParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.ObjectParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.ParseResult;
 +
 +/**
 + * The BinaryVerificator parses the EGIT Dictionary and extracts the signature
 + * holder from it.
 + * 
 + * @author wprinz
 + */
 +public class BinaryVerificator_1_0_0 implements Verificator
 +{
 +  /**
 +   * The Pdf-AS ID of this Verificator.
 +   */
 +  public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_0_0);
 +
 +  /**
 +   * Use this to override the MY_ID field.
 +   * 
 +   * @return Returns the Id of this Verificator.
 +   */
 +  protected PdfASID getMyId()
 +  {
 +    return MY_ID;
 +  }
 +
 +  /**
 +   * The /ODS key in the EGIZ Dict.
 +   */
 +  public static final byte[] EGIZ_ODS_NAME = new byte[] { 'O', 'D', 'S' };
 +
 +  /**
 +   * The /ID key in the EGIZ Dict.
 +   */
 +  public static final byte[] EGIZ_KZ_NAME = VerificationFilter.EGIZ_KZ_NAME;
 +
 +  /**
 +   * The /ByteRange key in the EGIZ Dict.
 +   */
 +  public static final byte[] EGIZ_BYTE_RANGE_NAME = new byte[] { 'B', 'y', 't', 'e', 'R', 'a', 'n', 'g', 'e' };
 +
 +  /**
 +   * The /replaces key in the EGIZ Dict.
 +   */
 +  public static final byte[] EGIZ_REPLACES_NAME = new byte[] { 'r', 'e', 'p', 'l', 'a', 'c', 'e', 's' };
 +
 +  /**
 +   * The /encodings key in the EGIZ Dict.
 +   */
 +  public static final byte[] EGIZ_ENCODINGS_NAME = new byte[] { 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g', 's' };
 +
 +  /**
 +   * The /Cert key in the EGIZ Dict.
 +   */
 +  public static final byte[] EGIZ_CERT_NAME = new byte[] { 'C', 'e', 'r', 't' };
 +
 +  /**
 +   * The logger definition.
 +   */
 +  private static final Logger logger_ = ConfigLogger.getLogger(BinaryVerificator_1_0_0.class);
 +
 +  /**
 +   * Default constructor.
 +   */
 +  public BinaryVerificator_1_0_0()
 +  {
 +    // Default constructor.
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.verificator.Verificator#parseBlock(at.gv.egiz.pdfas.framework.input.PdfDataSource,
 +   *      byte[],
 +   *      at.knowcenter.wag.exactparser.parsing.results.FooterParseResult, int)
 +   */
 +  public List parseBlock(PdfDataSource pdfDataSource, byte [] pdf, FooterParseResult block, int start_of_whole_block) throws PresentableException
 +  {
 +    // PERF: BinaryVerificator needs byte array.
 +    
 +    int egiz_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, VerificationFilter.EGIZ_DICT_NAME);
 +    if (egiz_index < 0)
 +    {
 +      throw new PDFDocumentException(ErrorCode.COULDNT_VERIFY, "egiz_index = " + egiz_index);
 +    }
 +
 +    IndirectObjectReferenceParseResult egiz_dict_iorpr = (IndirectObjectReferenceParseResult) block.tpr.dpr.values.get(egiz_index);
 +
 +    IndirectObjectReference ior = egiz_dict_iorpr.ior;
 +
 +    final int egiz_dict_offset = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(block.xpr, ior);
 +
 +    ObjectParseResult obj = PDFUtils.parseObject(pdf, egiz_dict_offset);
 +    DictionaryParseResult egiz_dict = (DictionaryParseResult) obj.object;
 +
 +    NumberParseResult ods_npr = (NumberParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_ODS_NAME);
 +
 +    ArrayParseResult kz_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_KZ_NAME);
 +    PdfASID kz = null;
 +    String kz_string = VerificationFilter.restoreKZ(pdf, kz_apr);
 +    kz = new PdfASID(kz_string);
 +    if (!kz_string.equals(getMyId().toString()))
 +    {
 +      logger_.warn("Warning: Kennzeichnung not recognized:" + kz_string);
 +    }
 +
 +    ArrayParseResult byte_ranges_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_BYTE_RANGE_NAME);
 +
 +    ArrayParseResult replaces_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_REPLACES_NAME);
 +
 +    ArrayParseResult encodings_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_ENCODINGS_NAME);
 +
 +    ArrayParseResult cert_apr = (ArrayParseResult) getValueOfKey(pdf, egiz_dict, EGIZ_CERT_NAME);
 +    byte[] cert = null;
 +    if (cert_apr != null && !cert_apr.elements.isEmpty())
 +    {
 +      LiteralStringParseResult lspr = (LiteralStringParseResult) cert_apr.elements.get(0);
 +      int str_length = lspr.content_end_index - lspr.content_start_index;
 +      byte[] encoded = new byte[str_length];
 +      System.arraycopy(pdf, lspr.content_start_index, encoded, 0, encoded.length);
 +
 +      cert = Placeholder.unescapePDFString(encoded);
 +    }
 +
 +    int num_byte_ranges = byte_ranges_apr.elements.size() / 2;
 +    List byte_ranges = new ArrayList();
 +    for (int i = 0; i < num_byte_ranges; i++)
 +    {
 +      NumberParseResult start_npr = (NumberParseResult) byte_ranges_apr.elements.get(2 * i);
 +      NumberParseResult length_npr = (NumberParseResult) byte_ranges_apr.elements.get(2 * i + 1);
 +
 +      StringInfo si = new StringInfo();
 +      si.string_start = start_npr.number;
 +      si.string_length = length_npr.number;
 +      byte_ranges.add(si);
 +    }
 +
 +    StringInfo sis[] = new StringInfo[num_byte_ranges - 1];
 +    for (int i = 0; i < num_byte_ranges - 1; i++)
 +    {
 +      StringInfo prev = (StringInfo) byte_ranges.get(i);
 +      StringInfo next = (StringInfo) byte_ranges.get(i + 1);
 +
 +      StringInfo hole = new StringInfo();
 +      hole.string_start = prev.string_start + prev.string_length;
 +      hole.string_length = next.string_start - hole.string_start;
 +
 +      sis[i] = hole;
 +    }
 +
 +    int n = replaces_apr.elements.size();
 +    byte[][] brevs = new byte[n][];
 +    for (int i = 0; i < n; i++)
 +    {
 +      NameParseResult lspr = (NameParseResult) replaces_apr.elements.get(i);
 +
 +      byte[] brev = new byte[3];
 +      System.arraycopy(pdf, lspr.name_start_index, brev, 0, brev.length);
 +
 +      brevs[i] = brev; // SignatureTypes.convertBrevToType(brev);
 +    }
 +
 +    n = encodings_apr.elements.size();
 +    byte[][] encodings = new byte[n][];
 +    for (int i = 0; i < n; i++)
 +    {
 +      NameParseResult lspr = (NameParseResult) encodings_apr.elements.get(i);
 +
 +      byte[] enc = new byte[3];
 +      System.arraycopy(pdf, lspr.name_start_index, enc, 0, enc.length);
 +      encodings[i] = enc;
 +    }
 +
 +    BinaryBlockInfo bbi = new BinaryBlockInfo();
 +    bbi.replaces = BinarySignature.reconstructReplaces(pdf, brevs, sis, encodings);
 +    bbi.signed_size = ods_npr.number;
 +
 +    // BinaryBlockInfo bbi = BinarySignature.retrieveEgizDictInformation(pdf,
 +    // ior.object_number, ior.generation_number, egiz_dict_offset);
 +
 +    // byte[] original_pdf = BinarySignature.restoreEgizDictInformation(pdf,
 +    // bbi);
 +
 +    byte[] signed_pdf = BinarySignature.prepareDataToSign(pdf, byte_ranges);
 +    // String signed_text =
 +    // BinarySignature.retrieveSignableTextFromData(signed_pdf,
 +    // signed_pdf.length); // has been moved into the BinarySignatureHolder
 +
 +    SignatureObject signature_object = new SignatureObject();
 +    String default_type = SettingsReader.getInstance().getValueFromKey(SignatureTypes.DEFAULT_TYPE);
 +    signature_object.setSigType(default_type);
 +    signature_object.initByType();
 +
 +    signature_object.setKZ(kz);
 +
 +    if (cert != null)
 +    {
 +      try
 +      {
 +        // ByteArrayInputStream bais = new ByteArrayInputStream(cert);
 +        // CertificateFactory cf = CertificateFactory.getInstance("X.509");
 +        // X509Certificate certificate = (X509Certificate)
 +        // cf.generateCertificate(bais);
 +
 +        // trim zero bytes. - the base 64 cert must not have zero bytes.
 +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
 +        for (int i = 0; i < cert.length; i++)
 +        {
 +          if (cert[i] != 0)
 +          {
 +            baos.write(cert[i]);
 +          }
 +        }
 +        byte[] b64 = baos.toByteArray();
 +
 +        signature_object.storeNewCertificateInLocalStore(b64);
 +      }
 +      catch (Exception e)
 +      {
 +        e.printStackTrace();
 +      }
 +
 +    }
 +
 +    Iterator rit = bbi.replaces.iterator();
 +    while (rit.hasNext())
 +    {
 +      ReplaceInfo ri = (ReplaceInfo) rit.next();
 +
 +      String type = SignatureTypes.convertBrevToType(ri.brev);
 +
 +      // signature_object.setSigValue(ri.type, ri.value);
 +      if (type.equals(SignatureTypes.SIG_DATE))
 +      {
 +        signature_object.setSignationDate(ri.value);
 +        continue;
 +      }
 +
 +      if (type.equals(SignatureTypes.SIG_ISSUER))
 +      {
 +        signature_object.setSignationIssuer(ri.value);
 +        continue;
 +      }
 +
 +      if (type.equals(SignatureTypes.SIG_VALUE))
 +      {
 +        signature_object.setSignationValue(ri.value);
 +        continue;
 +      }
 +
 +      if (type.equals(SignatureTypes.SIG_NUMBER))
 +      {
 +        signature_object.setSignationSerialNumber(ri.value);
 +        continue;
 +      }
 +
 +      if (type.equals(SignatureTypes.SIG_ID))
 +      {
 +        signature_object.setSignationIDs(ri.value);
 +        continue;
 +      }
 +    }
 +
 +    int iu_length = signed_pdf.length - start_of_whole_block;
 +    byte [] iu_block = new byte [iu_length];
 +    System.arraycopy(signed_pdf, start_of_whole_block, iu_block, 0, iu_length);
 +
 +    DelimitedPdfDataSource dpds = new DelimitedPdfDataSource(pdfDataSource, start_of_whole_block);
 +    PdfDataSource ds = new CompoundPdfDataSourceImpl(dpds, iu_block);
 +    
 +    //PdfDataSource dsByteArray = new ByteArrayPdfDataSourceImpl(signed_pdf, signed_pdf.length);
 +    
 +    BinarySignatureHolder signature_holder = new BinarySignatureHolder(ds, signature_object);
 +
 +    List holders = new ArrayList();
 +    holders.add(signature_holder);
 +    return holders;
 +  }
 +
 +  /**
 +   * Retrieves the value of the key from the dictionary.
 +   * 
 +   * @param pdf
 +   *          The PDF.
 +   * @param egiz_dict
 +   *          The dictionary.
 +   * @param name
 +   *          The name of the key.
 +   * @return Returns the value of the key. An exception is thrown if the key
 +   *         doesn't exist.
 +   * @throws PDFDocumentException
 +   *           Thrown, if the key doesn't exist in the dictionary.
 +   */
 +  protected ParseResult getRequiredValueOfKey(byte[] pdf, DictionaryParseResult egiz_dict, byte[] name) throws PDFDocumentException
 +  {
 +    final int index = PDFUtils.indexOfName(pdf, egiz_dict.names, name);
 +    checkIndex(index);
 +    ParseResult value = (ParseResult) egiz_dict.values.get(index);
 +    return value;
 +  }
 +
 +  /**
 +   * Throws an excaption, if the index is lower than 0.
 +   * 
 +   * @param name_index
 +   *          The index.
 +   * @throws PDFDocumentException
 +   *           Thrown, if the index is lower than 0.
 +   */
 +  protected void checkIndex(int name_index) throws PDFDocumentException
 +  {
 +    if (name_index < 0)
 +    {
 +      throw new PDFDocumentException(ErrorCode.COULDNT_VERIFY, "The name wasn't found in the egiz dict.");
 +    }
 +  }
 +
 +  /**
 +   * Retrieves the value of the key from the dictionary.
 +   * 
 +   * @param pdf
 +   *          The PDF.
 +   * @param egiz_dict
 +   *          The dictionary.
 +   * @param name
 +   *          The name of the key.
 +   * @return Returns the key's value, or null if the dictionary didn't contain
 +   *         that key.
 +   */
 +  protected ParseResult getValueOfKey(byte[] pdf, DictionaryParseResult egiz_dict, byte[] name)
 +  {
 +    final int index = PDFUtils.indexOfName(pdf, egiz_dict.names, name);
 +    if (index < 0)
 +    {
 +      return null;
 +    }
 +    ParseResult value = (ParseResult) egiz_dict.values.get(index);
 +    return value;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_1_0.java b/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_1_0.java new file mode 100644 index 0000000..a78c4a8 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_1_0.java @@ -0,0 +1,24 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.verificator.binary;
 +
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class BinaryVerificator_1_1_0 extends BinaryVerificator_1_0_0
 +{
 +  public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_1_0);
 +
 +  /**
 +   * @see at.knowcenter.wag.egov.egiz.framework.verificators.BinaryVerificator_1_0_0#getMyId()
 +   */
 +  protected PdfASID getMyId()
 +  {
 +    return MY_ID;
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/vfilter/Partition.java b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/Partition.java new file mode 100644 index 0000000..6fe90e5 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/Partition.java @@ -0,0 +1,9 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.vfilter;
 +
 +public interface Partition
 +{
 +  public boolean isTextPartition();
 +}
\ No newline at end of file diff --git a/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterImpl.java new file mode 100644 index 0000000..981b868 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterImpl.java @@ -0,0 +1,575 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.vfilter;
 +
 +import java.util.ArrayList;
 +import java.util.Iterator;
 +import java.util.List;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.gv.egiz.pdfas.exceptions.framework.VerificationFilterException;
 +import at.gv.egiz.pdfas.framework.SignatureHolderHelper;
 +import at.gv.egiz.pdfas.framework.VerificatorFactory;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.gv.egiz.pdfas.framework.input.TextDataSource;
 +import at.gv.egiz.pdfas.framework.verificator.Verificator;
 +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilter;
 +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters;
 +import at.gv.egiz.pdfas.impl.input.DelimitedInputStream;
 +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper;
 +import at.gv.egiz.pdfas.impl.vfilter.helper.VerificationFilterBinaryHelper;
 +import at.gv.egiz.pdfas.impl.vfilter.helper.VerificationFilterHelper;
 +import at.gv.egiz.pdfas.impl.vfilter.partition.BinaryPartition;
 +import at.gv.egiz.pdfas.impl.vfilter.partition.TextPartition;
 +import at.knowcenter.wag.egov.egiz.PdfAS;
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException;
 +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException;
 +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException;
 +import at.knowcenter.wag.egov.egiz.pdf.AbsoluteTextSignature;
 +import at.knowcenter.wag.egov.egiz.pdf.EGIZDate;
 +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder;
 +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder;
 +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult;
 +
 +/**
 + * @author wprinz
 + */
 +public class VerificationFilterImpl implements VerificationFilter
 +{
 +
 +  /**
 +   * The log.
 +   */
 +  private static final Log log = LogFactory.getLog(VerificationFilterImpl.class);
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.vfilter.VerificationFilter#extractSignatureHolders(at.gv.egiz.pdfas.framework.input.PdfDataSource,
 +   *      java.util.List,
 +   *      at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters)
 +   */
 +  public List extractSignatureHolders(final PdfDataSource pdf, List blocks, final VerificationFilterParameters parameters) throws VerificationFilterException
 +  {
 +    log.trace("extractSignaturHolders:");
 +
 +    if (log.isDebugEnabled())
 +    {
 +      log.debug("Original IU blocks: " + blocks.size());
 +      debugIUBlocks(blocks);
 +    }
 +
 +    unrollLinearization(blocks);
 +
 +    if (log.isDebugEnabled())
 +    {
 +      log.debug("IU blocks without linearization: " + blocks.size());
 +      debugIUBlocks(blocks);
 +    }
 +
 +    List signatureHolderChain = null;
 +
 +    if (parameters.extractBinarySignaturesOnly())
 +    {
 +      log.debug("Extracting only binary signatures. Binary-only mode.");
 +
 +      signatureHolderChain = performBinaryOnly(pdf, blocks);
 +    }
 +    else
 +    {
 +      List partitions = VerificationFilterHelper.partition(pdf, blocks);
 +      if (log.isDebugEnabled())
 +      {
 +        debugPartitions(partitions);
 +      }
 +
 +      if (parameters.assumeOnlySignatureUpdateBlocks())
 +      {
 +        log.debug("Assuming that there are only signature Incremental Update blocks. Semi-conservative mode.");
 +
 +        signatureHolderChain = performSemiConservative(pdf, parameters.scanForOldSignatures(), blocks, partitions);
 +      }
 +      else
 +      {
 +        log.debug("Scanning complete document. Conservative mode.");
 +
 +        signatureHolderChain = performFullConservative(pdf, parameters.scanForOldSignatures(), blocks, partitions);
 +      }
 +
 +    }
 +
 +    log.trace("extractSignaturHolders finished.");
 +    return signatureHolderChain;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.vfilter.VerificationFilter#extractSignaturHolders(at.gv.egiz.pdfas.framework.input.TextDataSource,
 +   *      at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters)
 +   */
 +  public List extractSignaturHolders(TextDataSource text, VerificationFilterParameters parameters) throws VerificationFilterException
 +  {
 +    if (parameters.extractBinarySignaturesOnly())
 +    {
 +      log
 +          .warn("A free text signature extraction was issued although the VerificationFilter was configured to detect only binary signatures (binary-only mode). The result is of course that no signatures can be found.");
 +
 +      return new ArrayList();
 +    }
 +
 +    String freetext = text.getText();
 +    String normalizedText = normalizeText(freetext);
 +
 +    List foundSignatures = null;
 +    if (parameters.scanForOldSignatures())
 +    {
 +      log.debug("Extracting old and new signatures from text.");
 +
 +      foundSignatures = extractNewAndOldSignaturesFromText(normalizedText);
 +    }
 +    else
 +    {
 +      log.debug("Extracting new signatures from text (not extracting old ones).");
 +
 +      foundSignatures = extractNewSignaturesFromText(normalizedText);
 +    }
 +    
 +    List textOnlySignatures = filterOutBinarySignatures(foundSignatures);
 +    
 +    return textOnlySignatures;
 +  }
 +    
 +    protected String normalizeText(String freetext) throws VerificationFilterException
 +    {
 +      try
 +      {
 +        return PdfAS.normalizeText(freetext);
 +      }
 +      catch (NormalizeException e)
 +      {
 +        throw new VerificationFilterException(e);
 +      }
 +    }
 +
 +  /**
 +   * Removes the linearization footer from the list of update blocks.
 +   * 
 +   * @param blocks
 +   *          The list of FooterParseResult objects in \prev order.
 +   */
 +  protected void unrollLinearization(List blocks)
 +  {
 +    int linearization_index = -1;
 +    for (int i = 0; i < blocks.size(); i++)
 +    {
 +      FooterParseResult bpr = (FooterParseResult) blocks.get(i);
 +
 +      if (bpr.sxpr.xref_index == 0)
 +      {
 +        if (linearization_index >= 0)
 +        {
 +          throw new RuntimeException("There is more than one linearization block! index = " + i);
 +        }
 +        linearization_index = i;
 +      }
 +    }
 +
 +    if (linearization_index >= 0)
 +    {
 +      // logger_.debug("The document is linearized - unrolling
 +      // linearization block " + linearization_index);
 +      blocks.remove(linearization_index);
 +    }
 +  }
 +
 +  protected List performBinaryOnly(PdfDataSource pdf, List blocks) throws VerificationFilterException
 +  {
 +    return extractBinarySignaturesOnly(pdf, blocks);
 +  }
 +
 +  protected List performSemiConservative(PdfDataSource pdf, boolean scanForOldSignatures, List blocks, List partitions) throws VerificationFilterException
 +  {
 +    List binarySignatures = extractBinarySignaturesOnly(pdf, blocks);
 +
 +    TextPartition lastTextPartition = VerificationFilterHelper.findLastTextPartition(partitions);
 +    List extractedSignatures = null;
 +    if (scanForOldSignatures)
 +    {
 +      SignaturesAndOld sao = extractSignaturesFromPartitionAndOld(pdf, lastTextPartition);
 +      extractedSignatures = sao.newSignatures;
 +      if (sao.oldSignature != null)
 +      {
 +        extractedSignatures.add(0, sao.oldSignature);
 +      }
 +    }
 +    else
 +    {
 +      extractedSignatures = extractSignaturesFromPartition(pdf, lastTextPartition);
 +    }
 +
 +    List signatureHolderChain = intermingleSignatures(binarySignatures, extractedSignatures);
 +
 +    return signatureHolderChain;
 +  }
 +
 +  protected List performFullConservative(PdfDataSource pdf, boolean scanForOldSignatures, List blocks, List partitions) throws VerificationFilterException
 +  {
 +    List binarySignatures = extractBinarySignaturesOnly(pdf, blocks);
 +
 +    SignatureHolder oldSignature = null;
 +
 +    List partitionResults = new ArrayList(partitions.size());
 +    for (int i = 0; i < partitions.size(); i++)
 +    {
 +      Partition p = (Partition) partitions.get(i);
 +
 +      if (p instanceof TextPartition)
 +      {
 +        TextPartition tp = (TextPartition) p;
 +
 +        List partitionResult = null;
 +
 +        boolean scanThisPartitionForOldSignature = (i == 0) && scanForOldSignatures;
 +        if (scanThisPartitionForOldSignature)
 +        {
 +          SignaturesAndOld sao = extractSignaturesFromPartitionAndOld(pdf, tp);
 +          partitionResult = sao.newSignatures;
 +          oldSignature = sao.oldSignature;
 +        }
 +        else
 +        {
 +          partitionResult = extractSignaturesFromPartition(pdf, tp);
 +        }
 +
 +        partitionResults.add(partitionResult);
 +      }
 +    }
 +
 +    List extractedSignatures = new ArrayList();
 +    Iterator it = partitionResults.iterator();
 +    List prevPartitionResult = null;
 +    while (it.hasNext())
 +    {
 +      List partitionResult = (List) it.next();
 +
 +      if (prevPartitionResult == null)
 +      {
 +        extractedSignatures.addAll(partitionResult);
 +      }
 +      else
 +      {
 +        assert partitionResult.size() >= prevPartitionResult.size();
 +
 +        for (int i = prevPartitionResult.size(); i < partitionResult.size(); i++)
 +        {
 +          SignatureHolder sh = (SignatureHolder) partitionResult.get(i);
 +          extractedSignatures.add(sh);
 +        }
 +      }
 +
 +      prevPartitionResult = partitionResult;
 +    }
 +
 +    List signatureHolderChain = intermingleSignatures(binarySignatures, extractedSignatures);
 +
 +    if (oldSignature != null)
 +    {
 +      signatureHolderChain.add(0, oldSignature);
 +    }
 +
 +    return signatureHolderChain;
 +  }
 +
 +  protected String extractText(PdfDataSource pdf, int endOfDocument) throws PresentableException
 +  {
 +    DelimitedInputStream dis = new DelimitedInputStream(pdf.createInputStream(), endOfDocument);
 +    return PdfAS.extractNormalizedTextTextual(dis);
 +  }
 +
 +  protected List extractNewSignaturesFromText(String text) throws VerificationFilterException
 +  {
 +    try
 +    {
 +      return AbsoluteTextSignature.extractSignatureHoldersFromText(text);
 +    }
 +    catch (PresentableException e)
 +    {
 +      throw new VerificationFilterException(e);
 +    }
 +  }
 +  
 +  protected List extractNewAndOldSignaturesFromText(String text) throws VerificationFilterException
 +  {
 +    SignaturesAndOld sao = extractSignaturesAndOld(text);
 +    if (sao.oldSignature != null)
 +    {
 +      sao.newSignatures.add(0, sao.oldSignature);
 +    }
 +
 +    return sao.newSignatures;
 +  }
 +
 +  protected List extractOldSignaturesFromText(String text) throws PresentableException
 +  {
 +    return PdfAS.extractSignatureHoldersTextual(text, true);
 +  }
 +
 +  protected List intermingleSignatures(List binarySignatures, List extractedSignatures)
 +  {
 +    List textualSignatures = filterOutBinarySignatures(extractedSignatures);
 +
 +    List intermingled = new ArrayList(binarySignatures.size() + textualSignatures.size());
 +    intermingled.addAll(binarySignatures);
 +    intermingled.addAll(textualSignatures);
 +
 +    sortSignatures(intermingled);
 +
 +    return intermingled;
 +  }
 +
 +  protected List filterOutBinarySignatures(List signatures)
 +  {
 +    List textOnly = new ArrayList(signatures.size());
 +
 +    Iterator it = signatures.iterator();
 +    while (it.hasNext())
 +    {
 +      SignatureHolder sh = (SignatureHolder) it.next();
 +      if (sh.getSignatureObject().isTextual())
 +      {
 +        textOnly.add(sh);
 +      }
 +    }
 +
 +    return textOnly;
 +  }
 +
 +  protected void sortSignatures(List signatures)
 +  {
 +    SignatureHolderHelper.sortByDate(signatures);
 +  }
 +
 +  protected void debugIUBlocks(List blocks)
 +  {
 +    Iterator it = blocks.iterator();
 +    while (it.hasNext())
 +    {
 +      FooterParseResult fpr = (FooterParseResult) it.next();
 +      log.debug("footer: " + fpr.start_index + " to " + fpr.next_index + ", has predecessor = " + fpr.tpr.has_predecessor);
 +    }
 +  }
 +
 +  protected void debugPartitions(List partitions)
 +  {
 +    Iterator it = partitions.iterator();
 +    while (it.hasNext())
 +    {
 +      Object o = it.next();
 +      assert o instanceof Partition;
 +
 +      List blocks = null;
 +      if (o instanceof TextPartition)
 +      {
 +        TextPartition tp = (TextPartition) o;
 +
 +        blocks = tp.blocks;
 +
 +        log.debug("text partition with " + tp.blocks.size() + " blocks:");
 +      }
 +      else
 +      {
 +        BinaryPartition bp = (BinaryPartition) o;
 +
 +        blocks = bp.blocks;
 +
 +        log.debug("binary partition: with " + bp.blocks.size() + " blocks:");
 +
 +      }
 +      debugIUBlocks(blocks);
 +      log.debug("partition finished.");
 +    }
 +  }
 +
 +  /**
 +   * Extracts the binary singatures from the given PDF.
 +   * 
 +   * <p>
 +   * IU blocks without an egiz dict are not considered.
 +   * </p>
 +   * 
 +   * @param pdf
 +   * @param blocks
 +   * @return Returns the List of signature holders.
 +   * @throws PresentableException
 +   */
 +  protected List extractBinarySignaturesOnly(PdfDataSource pdf, List blocks) throws VerificationFilterException
 +  {
 +    try
 +    {
 +      // PERF: extract binary signatures needs byte array
 +      byte[] data = DataSourceHelper.convertDataSourceToByteArray(pdf);
 +
 +      List binarySignatures = new ArrayList(blocks.size());
 +
 +      Iterator it = blocks.iterator();
 +      int prev_end = 0;
 +      while (it.hasNext())
 +      {
 +        FooterParseResult fpr = (FooterParseResult) it.next();
 +        assert fpr.next_index > prev_end;
 +
 +        if (VerificationFilterBinaryHelper.containsEGIZDict(data, fpr))
 +        {
 +          PdfASID kz = VerificationFilterBinaryHelper.extractKZFromEGIZBlock(data, fpr);
 +
 +          Verificator verificator = VerificatorFactory.createBinaryVerificator(kz);
 +          List binary_holders = verificator.parseBlock(pdf, data, fpr, prev_end);
 +
 +          binarySignatures.addAll(binary_holders);
 +        }
 +
 +        prev_end = fpr.next_index;
 +      }
 +
 +      return binarySignatures;
 +    }
 +    catch (PresentableException e)
 +    {
 +      throw new VerificationFilterException(e);
 +    }
 +  }
 +
 +  protected List extractSignatures(PdfDataSource pdf, int endOfDocument) throws VerificationFilterException
 +  {
 +    try
 +    {
 +      log.debug("Extracting text from 0 to " + endOfDocument + " (total document size = " + pdf.getLength() + "):");
 +      String extractedText = extractText(pdf, endOfDocument);
 +      log.debug("Extracting text finished.");
 +
 +      log.debug("Extracting signatures:");
 +      List extractedSignatures = extractNewSignaturesFromText(extractedText);
 +      log.debug("Extracting signatures finished.");
 +
 +      return extractedSignatures;
 +    }
 +    catch (PresentableException e)
 +    {
 +      throw new VerificationFilterException(e);
 +    }
 +  }
 +
 +  protected String determineRestText(List newSignatures, String extractedText)
 +  {
 +    if (newSignatures.isEmpty())
 +    {
 +      return extractedText;
 +    }
 +
 +    // note that even if the oldest signature is a binary signature,
 +    // the rest text is the text of this binary signature, which was extracted
 +    // like a text signature.
 +    TextualSignatureHolder oldestSignature = (TextualSignatureHolder) newSignatures.get(0);
 +    return oldestSignature.getSignedText();
 +  }
 +
 +  protected List extractSignaturesFromPartition(PdfDataSource pdf, Partition partition) throws VerificationFilterException
 +  {
 +    assert partition.isTextPartition();
 +
 +    int endOfDocument = VerificationFilterHelper.getEndOfPartition(partition);
 +    return extractSignatures(pdf, endOfDocument);
 +  }
 +
 +  protected SignaturesAndOld extractSignaturesFromPartitionAndOld(PdfDataSource pdf, Partition partition) throws VerificationFilterException
 +  {
 +    assert partition.isTextPartition();
 +
 +    try
 +    {
 +      int endOfDocument = VerificationFilterHelper.getEndOfPartition(partition);
 +
 +       log.debug("Extracting text from 0 to " + endOfDocument + " (total document size = " + pdf.getLength() + "):");
 +      String extractedText = extractText(pdf, endOfDocument);
 +      log.debug("Extracting text finished.");
 +
 +      SignaturesAndOld sao = extractSignaturesAndOld(extractedText);
 +
 +      return sao;
 +    }
 +    catch (PresentableException e)
 +    {
 +      throw new VerificationFilterException(e);
 +    }
 +  }
 +
 +  protected static class SignaturesAndOld
 +  {
 +    public List newSignatures = null;
 +
 +    public SignatureHolder oldSignature = null;
 +  }
 +  
 +  protected SignaturesAndOld extractSignaturesAndOld(String text) throws VerificationFilterException
 +  {
 +    try
 +    {
 +      log.debug("Extracting signatures:");
 +      List extractedSignatures = extractNewSignaturesFromText(text);
 +      log.debug("Extracting signatures finished.");
 +      
 +      log.debug("Extracting old signatures:");
 +      SignatureHolder oldSignature = extractOldSignature(text, extractedSignatures);
 +      log.debug("Extracting old signatures finished.");
 +
 +      SignaturesAndOld sao = new SignaturesAndOld();
 +      sao.newSignatures = extractedSignatures;
 +      sao.oldSignature = oldSignature;
 +
 +      return sao;
 +    }
 +    catch (PresentableException e)
 +    {
 +      throw new VerificationFilterException(e);
 +    }
 +  }
 +
 +  /**
 +   * Extracts the old signature from the text, but only if it is older than the
 +   * oldest signature of the new signatueres.
 +   * 
 +   * @param extractedText
 +   * @param newSignatures
 +   * @return
 +   * @throws PDFDocumentException
 +   * @throws SignatureException
 +   * @throws NormalizeException
 +   * @throws SignatureTypesException
 +   */
 +  protected SignatureHolder extractOldSignature(String extractedText, List newSignatures) throws PDFDocumentException, SignatureException, NormalizeException, SignatureTypesException
 +  {
 +    SignatureHolder oldSignature = null;
 +
 +    String restText = determineRestText(newSignatures, extractedText);
 +
 +    List oldSignatures = PdfAS.extractSignatureHoldersTextual(restText, true);
 +    if (!oldSignatures.isEmpty())
 +    {
 +      oldSignature = (SignatureHolder) oldSignatures.get(0);
 +      if (!newSignatures.isEmpty())
 +      {
 +        SignatureHolder oldestNewSignature = (SignatureHolder) newSignatures.get(0);
 +        EGIZDate oldDate = EGIZDate.parseFromString(oldSignature.getSignatureObject().getSignationDate());
 +        EGIZDate newDate = EGIZDate.parseFromString(oldestNewSignature.getSignatureObject().getSignationDate());
 +        if (newDate.compareTo(oldDate) <= 0)
 +        {
 +          oldSignature = null;
 +        }
 +      }
 +    }
 +    return oldSignature;
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterParametersImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterParametersImpl.java new file mode 100644 index 0000000..292e816 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterParametersImpl.java @@ -0,0 +1,67 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.vfilter;
 +
 +import java.io.Serializable;
 +
 +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters;
 +
 +/**
 + * @author wprinz
 + * 
 + */
 +public class VerificationFilterParametersImpl implements VerificationFilterParameters, Serializable
 +{
 +  /**
 +   * SVUID.
 +   */
 +  private static final long serialVersionUID = -7118403150485416046L;
 +
 +  protected boolean extractBinarySignaturesOnly = false;
 +
 +  protected boolean assumeOnlySignatureUpdateBlocks = false;
 +  
 +  protected boolean scanForOldSignatures = true;
 +
 +  public VerificationFilterParametersImpl(boolean extractBinarySignaturesOnly, boolean assumeOnlySignatureUpdateBlocks, boolean scanForOldSignatures)
 +  {
 +    this.extractBinarySignaturesOnly = extractBinarySignaturesOnly;
 +    this.assumeOnlySignatureUpdateBlocks = assumeOnlySignatureUpdateBlocks;
 +    this.scanForOldSignatures = scanForOldSignatures;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters#extractBinarySignaturesOnly()
 +   */
 +  public boolean extractBinarySignaturesOnly()
 +  {
 +    return this.extractBinarySignaturesOnly;
 +  }
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters#assumeOnlySignatureUpdateBlocks()
 +   */
 +  public boolean assumeOnlySignatureUpdateBlocks()
 +  {
 +    return this.assumeOnlySignatureUpdateBlocks;
 +  }
 +
 +  
 +  /**
 +   * @see at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters#scanForOldSignatures()
 +   */
 +  public boolean scanForOldSignatures()
 +  {
 +    return this.scanForOldSignatures;
 +  }
 +
 +  /**
 +   * @see java.lang.Object#toString()
 +   */
 +  // @override
 +  public String toString()
 +  {
 +    return "{VerificationFilterParametersImpl: extractBinarySignaturesOnly = " + extractBinarySignaturesOnly() + ", assumeOnlySignatureUpdateBlocks = " + assumeOnlySignatureUpdateBlocks() + "}";
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterBinaryHelper.java b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterBinaryHelper.java new file mode 100644 index 0000000..b7f36d1 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterBinaryHelper.java @@ -0,0 +1,152 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.vfilter.helper;
 +
 +import java.io.IOException;
 +import java.util.ArrayList;
 +import java.util.List;
 +
 +import at.gv.egiz.pdfas.exceptions.ErrorCode;
 +
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException;
 +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException;
 +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature;
 +import at.knowcenter.wag.egov.egiz.pdf.Placeholder;
 +import at.knowcenter.wag.egov.egiz.pdf.StringInfo;
 +import at.knowcenter.wag.exactparser.parsing.IndirectObjectReference;
 +import at.knowcenter.wag.exactparser.parsing.PDFUtils;
 +import at.knowcenter.wag.exactparser.parsing.results.ArrayParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.DictionaryParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.IndirectObjectReferenceParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.NumberParseResult;
 +import at.knowcenter.wag.exactparser.parsing.results.ObjectParseResult;
 +
 +/**
 + * Contains helpful methods used by the VerificationFilter to analyze the PDF for binary signatures.
 + * 
 + * @author wprinz
 + */
 +public final class VerificationFilterBinaryHelper
 +{
 +  /**
 +   * The name of the egiz dict key.
 +   */
 +  public static final byte[] EGIZ_DICT_NAME = { 'E', 'G', 'I', 'Z', 'S', 'i', 'g', 'D', 'i', 'c', 't' };
 +
 +  /**
 +   * The name of the ID (SIG_KZ) property in the egiz dict.
 +   */
 +  public static final byte[] EGIZ_KZ_NAME = { 'I', 'D' };
 +
 +  /**
 +   * Tells, if the given incremental update block contains a binary signature.
 +   * 
 +   * <p>
 +   * According to definition, if a block is a binary block, it must/cannot
 +   * contain other signatures than this one.
 +   * </p>
 +   * 
 +   * @param block
 +   *          The incremental update block.
 +   * @return Returns true, if this block is a binary signature block, false
 +   *         otherwise.
 +   */
 +  public static boolean containsEGIZDict(final byte[] pdf, final FooterParseResult block)
 +  {
 +    int dict_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, EGIZ_DICT_NAME);
 +    if (dict_index <= 0)
 +    {
 +      return false;
 +    }
 +
 +    return true;
 +  }
 +
 +  /**
 +   * Extracts the PDF AS ID of the egiz block.
 +   * 
 +   * @param pdf
 +   *          The pdf.
 +   * @param block
 +   *          The IU block.
 +   * @return Returns the extracted PDF AS ID.
 +   * @throws PDFDocumentException
 +   *           Forwarded exception.
 +   * @throws InvalidIDException
 +   *           Forwarded exception.
 +   */
 +  public static PdfASID extractKZFromEGIZBlock(final byte[] pdf, final FooterParseResult block) throws PDFDocumentException, InvalidIDException
 +  {
 +    int egiz_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, EGIZ_DICT_NAME);
 +    if (egiz_index < 0)
 +    {
 +      throw new PDFDocumentException(301, "egiz_index = " + egiz_index);
 +    }
 +
 +    IndirectObjectReferenceParseResult egiz_dict_iorpr = (IndirectObjectReferenceParseResult) block.tpr.dpr.values.get(egiz_index);
 +    // logger_.debug("egiz_dict_ir = " + egiz_dict_iorpr.ior.object_number
 +    // + " " + egiz_dict_iorpr.ior.generation_number);
 +
 +    IndirectObjectReference ior = egiz_dict_iorpr.ior;
 +
 +    final int egiz_dict_offset = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(block.xpr, ior);
 +    // logger_.debug("egiz_dict_offset = " + egiz_dict_offset);
 +
 +    ObjectParseResult obj = PDFUtils.parseObject(pdf, egiz_dict_offset);
 +    DictionaryParseResult egiz_dict = (DictionaryParseResult) obj.object;
 +
 +    int kz_index = PDFUtils.indexOfName(pdf, egiz_dict.names, EGIZ_KZ_NAME);
 +    if (kz_index < 0)
 +    {
 +      throw new PDFDocumentException(301, "kz_index = " + kz_index);
 +    }
 +    ArrayParseResult kz_apr = (ArrayParseResult) egiz_dict.values.get(kz_index);
 +
 +    String kz_string = restoreKZ(pdf, kz_apr);
 +    PdfASID kz = new PdfASID(kz_string);
 +
 +    return kz;
 +  }
 +
 +  /**
 +   * Restores the Kennzeichnung String from an Array.
 +   * 
 +   * @param pdf
 +   *          The PDF.
 +   * @param kz_apr
 +   *          The Array, as parsed from the EGIZ Dict.
 +   * @return Returns the restored KZ.
 +   * @throws PDFDocumentException
 +   *           Forwarded exception.
 +   */
 +  public static String restoreKZ(byte[] pdf, ArrayParseResult kz_apr) throws PDFDocumentException
 +  {
 +    try
 +    {
 +      List partition = new ArrayList();
 +
 +      for (int i = 0; i < kz_apr.elements.size() / 2; i++)
 +      {
 +        NumberParseResult start_npr = (NumberParseResult) kz_apr.elements.get(i * 2);
 +        NumberParseResult length_npr = (NumberParseResult) kz_apr.elements.get(i * 2 + 1);
 +
 +        StringInfo si = new StringInfo();
 +        si.string_start = start_npr.number;
 +        si.string_length = length_npr.number;
 +
 +        partition.add(si);
 +      }
 +
 +      String KZ = Placeholder.reconstructStringFromPartition(pdf, partition, BinarySignature.ENCODING_WIN);
 +      return KZ;
 +    }
 +    catch (IOException e1)
 +    {
 +      throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e1);
 +    }
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterHelper.java b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterHelper.java new file mode 100644 index 0000000..67af129 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterHelper.java @@ -0,0 +1,142 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.vfilter.helper;
 +
 +import java.util.ArrayList;
 +import java.util.Iterator;
 +import java.util.List;
 +
 +import at.gv.egiz.pdfas.exceptions.framework.VerificationFilterException;
 +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper;
 +import at.gv.egiz.pdfas.impl.vfilter.Partition;
 +import at.gv.egiz.pdfas.impl.vfilter.partition.BinaryPartition;
 +import at.gv.egiz.pdfas.impl.vfilter.partition.TextPartition;
 +import at.gv.egiz.pdfas.framework.input.PdfDataSource;
 +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult;
 +
 +/**
 + * Contains helpful methods used by the VerificationFilter.
 + * 
 + * @author wprinz
 + */
 +public final class VerificationFilterHelper
 +{
 +  /**
 +   * Partitions the list of Incremental Update blocks into text and binary
 +   * partitions.
 +   * 
 +   * <p>
 +   * A partition is a sequence of Incremental Update blocks of the same type.
 +   * </p>
 +   * <p>
 +   * An Incremental Update block is considered to have the type "binary" if it
 +   * contains an egiz dictionary. A block not containing an egiz dictionary is
 +   * considert to have the type "text".
 +   * </p>
 +   * 
 +   * @param pdf
 +   *          The PDF.
 +   * @param blocks
 +   *          The Incremental Update blocks.
 +   * @return Returns the partitioning of the blocks.
 +   * @throws VerificationFilterException
 +   *           Thrown if something goes wrong.
 +   */
 +  public static List partition(PdfDataSource pdf, List blocks) throws VerificationFilterException
 +  {
 +      List partitions = new ArrayList(blocks.size());
 +
 +      Iterator it = blocks.iterator();
 +      while (it.hasNext())
 +      {
 +        FooterParseResult fpr = (FooterParseResult) it.next();
 +
 +        byte[] data = DataSourceHelper.convertDataSourceToByteArray(pdf);
 +        if (VerificationFilterBinaryHelper.containsEGIZDict(data, fpr))
 +        {
 +          BinaryPartition bp = null;
 +          if (partitions.isEmpty() || ((Partition) partitions.get(partitions.size() - 1)).isTextPartition())
 +          {
 +            bp = new BinaryPartition();
 +            bp.blocks = new ArrayList(blocks.size());
 +            partitions.add(bp);
 +          }
 +          else
 +          {
 +            bp = (BinaryPartition) partitions.get(partitions.size() - 1);
 +          }
 +          assert bp != null;
 +
 +          bp.blocks.add(fpr);
 +        }
 +        else
 +        {
 +          TextPartition tp = null;
 +          if (partitions.isEmpty() || !((Partition) partitions.get(partitions.size() - 1)).isTextPartition())
 +          {
 +            tp = new TextPartition();
 +            tp.blocks = new ArrayList(blocks.size());
 +            partitions.add(tp);
 +          }
 +          else
 +          {
 +            tp = (TextPartition) partitions.get(partitions.size() - 1);
 +          }
 +          assert tp != null;
 +
 +          tp.blocks.add(fpr);
 +        }
 +      }
 +
 +      assert partitions.size() >= 1 : "There must be at least one partition";
 +
 +      return partitions;
 +  }
 +
 +  /**
 +   * Determines the end of the given partiton.
 +   * 
 +   * @param partition
 +   *          The partition.
 +   * @return Returns the end index of the given partition.
 +   */
 +  public static int getEndOfPartition(Partition partition)
 +  {
 +    List blocks = null;
 +    if (partition instanceof TextPartition)
 +    {
 +      blocks = ((TextPartition) partition).blocks;
 +    }
 +    else
 +    {
 +      blocks = ((BinaryPartition) partition).blocks;
 +    }
 +
 +    return ((FooterParseResult) blocks.get(blocks.size() - 1)).next_index;
 +  }
 +
 +  /**
 +   * Finds the last text partition in the given list of partitions.
 +   * 
 +   * @param partitions
 +   *          The partitions.
 +   * @return Returns the last TextPartition.
 +   */
 +  public static TextPartition findLastTextPartition(List partitions)
 +  {
 +    Partition lastTextPartition = (Partition) partitions.get(partitions.size() - 1);
 +
 +    if (!lastTextPartition.isTextPartition())
 +    {
 +      assert partitions.size() > 1 : "The only one partition cannot be a binary partition - where is the original document?";
 +      Partition previousToLastPartition = (Partition) partitions.get(partitions.size() - 2);
 +      assert previousToLastPartition.isTextPartition() : "The previous to last partition must be a text partition or something is wrong with the partitioning algorithm.";
 +
 +      lastTextPartition = previousToLastPartition;
 +    }
 +
 +    return (TextPartition) lastTextPartition;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterTextHelper.java b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterTextHelper.java new file mode 100644 index 0000000..f9a79b0 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterTextHelper.java @@ -0,0 +1,15 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.vfilter.helper;
 +
 +/**
 + * Contains helpful methods used by the VerificationFilter to analyze text and
 + * find text signatures.
 + * 
 + * @author wprinz
 + */
 +public final class VerificationFilterTextHelper
 +{
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/BinaryPartition.java b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/BinaryPartition.java new file mode 100644 index 0000000..520f3b1 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/BinaryPartition.java @@ -0,0 +1,19 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.vfilter.partition;
 +
 +import java.util.List;
 +
 +import at.gv.egiz.pdfas.impl.vfilter.Partition;
 +
 +
 +public class BinaryPartition implements Partition
 +{
 +  public List blocks = null;
 +
 +  public boolean isTextPartition()
 +  {
 +    return false;
 +  }
 +}
\ No newline at end of file diff --git a/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/TextPartition.java b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/TextPartition.java new file mode 100644 index 0000000..bf17633 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/TextPartition.java @@ -0,0 +1,20 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.impl.vfilter.partition;
 +
 +import java.util.List;
 +
 +import at.gv.egiz.pdfas.impl.vfilter.Partition;
 +
 +
 +public class TextPartition implements Partition
 +{
 +  public List blocks = null;
 +
 +  public boolean isTextPartition()
 +  {
 +    return true;
 +  }
 +
 +}
\ No newline at end of file diff --git a/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounter.java b/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounter.java new file mode 100644 index 0000000..2d9b461 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounter.java @@ -0,0 +1,62 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.performance;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +/**
 + * @author wprinz
 + */
 +public class PerformanceCounter
 +{
 +  /**
 +   * The log.
 +   */
 +  private static Log log = LogFactory.getLog(PerformanceCounter.class);
 +
 +  protected String name = null;
 +
 +  protected long counter = 0;
 +
 +  public PerformanceCounter(String name)
 +  {
 +    this.name = name;
 +    reset();
 +  }
 +
 +  public PerformanceCounter(Class clazz)
 +  {
 +    this(clazz.getName());
 +  }
 +
 +  public void increment()
 +  {
 +    this.counter++;
 +    log.trace(this.name + ": incremented to " + this.counter);
 +  }
 +
 +  public void reset()
 +  {
 +    this.counter = 0;
 +    log.trace(this.name + ": reset to 0");
 +  }
 +
 +  /**
 +   * @return the name
 +   */
 +  public String getName()
 +  {
 +    return this.name;
 +  }
 +
 +  /**
 +   * @return the counter
 +   */
 +  public long getCounter()
 +  {
 +    return this.counter;
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounters.java b/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounters.java new file mode 100644 index 0000000..6251c55 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounters.java @@ -0,0 +1,22 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.performance;
 +
 +/**
 + * Contains various global PerformanceCounters that provide information about the system.
 + * 
 + * @author wprinz
 + */
 +public final class PerformanceCounters
 +{
 +  /**
 +   * Keeps track of the number of text extractions done so far.
 +   */
 +  public static PerformanceCounter textExtractions = new PerformanceCounter("TextExtractions");
 +
 +  /**
 +   * Keeps track of the number of large byte array allocations.
 +   */
 +  public static PerformanceCounter byteArrays = new PerformanceCounter("ByteArrays");
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/performance/PerformanceTimer.java b/src/main/java/at/gv/egiz/pdfas/performance/PerformanceTimer.java new file mode 100644 index 0000000..6ebb9be --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/performance/PerformanceTimer.java @@ -0,0 +1,48 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.performance;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +/**
 + * @author wprinz
 + * 
 + */
 +public class PerformanceTimer
 +{
 +  /**
 +   * The log.
 +   */
 +  private static Log log = LogFactory.getLog(PerformanceTimer.class);
 +
 +  protected String name = null;
 +
 +  protected long startTime = -1;
 +
 +  protected long stopTime = -1;
 +
 +  public PerformanceTimer(String name)
 +  {
 +    this.name = name;
 +  }
 +
 +  public void start()
 +  {
 +    this.startTime = System.currentTimeMillis();
 +    log.trace(this.name + ": started at " + this.startTime);
 +  }
 +
 +  public void stop()
 +  {
 +    this.stopTime = System.currentTimeMillis();
 +    log.trace(this.name + ": stopped at " + this.stopTime);
 +    log.trace(this.name + ": time elapsed = " + getTimeElapsed());
 +  }
 +
 +  public long getTimeElapsed()
 +  {
 +    return this.stopTime - this.startTime;
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/utils/DataHashUtils.java b/src/main/java/at/gv/egiz/pdfas/utils/DataHashUtils.java new file mode 100644 index 0000000..19d7b33 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/utils/DataHashUtils.java @@ -0,0 +1,136 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.utils;
 +
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.UnsupportedEncodingException;
 +import java.security.DigestInputStream;
 +import java.security.MessageDigest;
 +import java.security.NoSuchAlgorithmException;
 +
 +import org.apache.commons.codec.binary.Base64;
 +
 +import at.knowcenter.wag.egov.egiz.pdf.BinarySignatureHolder;
 +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder;
 +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder;
 +
 +/**
 + * Contains helpful methods for building data hashed.
 + * 
 + * <p>
 + * Data hashes are useful for summarizing the signed data of signatures for
 + * debugging and testing purposes. Do not use these hashes for signatures.
 + * </p>
 + * <p>
 + * A data hash is always a Base64 encoded String.
 + * </p>
 + * 
 + * @author wprinz
 + * 
 + */
 +public final class DataHashUtils
 +{
 +
 +  /**
 +   * 
 +   * @param text
 +   * @return
 +   */
 +  public static String buildDataHash(String text)
 +  {
 +    try
 +    {
 +      MessageDigest md = getMessageDigest();
 +      // probable performance leak for very large texts
 +      md.update(text.getBytes("UTF-8"));
 +      byte[] rawDigest = md.digest();
 +
 +      return encodeDigest(rawDigest);
 +    }
 +    catch (UnsupportedEncodingException e)
 +    {
 +      throw new RuntimeException(e);
 +    }
 +  }
 +
 +  public static String buildDataHash(byte[] data)
 +  {
 +    MessageDigest md = getMessageDigest();
 +    md.update(data);
 +    byte[] rawDigest = md.digest();
 +
 +    return encodeDigest(rawDigest);
 +  }
 +
 +  public static String buildDataHash(InputStream is)
 +  {
 +    try
 +    {
 +      MessageDigest md = getMessageDigest();
 +
 +      DigestInputStream dis = new DigestInputStream(is, md);
 +
 +      byte[] temp = new byte[1024];
 +      int i = 0;
 +      while (dis.read(temp) >= 0)
 +      {
 +        // this just keeps the compiler from optimizing this loop away
 +        i++;
 +      }
 +      dis.close();
 +
 +      byte[] rawDigest = md.digest();
 +
 +      return encodeDigest(rawDigest);
 +    }
 +    catch (IOException e)
 +    {
 +      throw new RuntimeException(e);
 +    }
 +  }
 +  
 +  public static String buildDataHash(SignatureHolder sh)
 +  {
 +    if (sh instanceof TextualSignatureHolder)
 +    {
 +      TextualSignatureHolder tsh = (TextualSignatureHolder) sh;
 +      String signedText = tsh.getSignedText();
 +      return buildDataHash(signedText);
 +    }
 +    
 +    {
 +      BinarySignatureHolder bsh = (BinarySignatureHolder) sh;
 +      InputStream is = bsh.getSignedPdf().createInputStream();
 +      return buildDataHash(is);
 +    }
 +  }
 +
 +  protected static MessageDigest getMessageDigest()
 +  {
 +    try
 +    {
 +      MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
 +      return sha1;
 +    }
 +    catch (NoSuchAlgorithmException e)
 +    {
 +      throw new RuntimeException(e);
 +    }
 +  }
 +
 +  protected static String encodeDigest(byte[] rawDigest)
 +  {
 +    try
 +    {
 +      byte[] encoded = Base64.encodeBase64(rawDigest);
 +      String str = new String(encoded, "US-ASCII");
 +      return str;
 +    }
 +    catch (UnsupportedEncodingException e)
 +    {
 +      throw new RuntimeException(e);
 +    }
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/utils/StreamUtils.java b/src/main/java/at/gv/egiz/pdfas/utils/StreamUtils.java new file mode 100644 index 0000000..acf7e75 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/utils/StreamUtils.java @@ -0,0 +1,42 @@ +package at.gv.egiz.pdfas.utils;
 +
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.OutputStream;
 +
 +public class StreamUtils
 +{
 +  
 +  public static void writeInputStreamToOutputStream (InputStream is, OutputStream os) throws IOException
 +  {
 +    byte [] buffer = new byte [2048];
 +    
 +    int read = -1;
 +    while ((read = is.read(buffer)) > 0)
 +    {
 +      os.write(buffer, 0, read);
 +    }
 +    is.close();
 +    os.close();
 +  }
 +  
 +  // The InputStream should be self- delimited.
 +//  public static void writeInputStreamToOutputStream(InputStream is, OutputStream os, int length) throws IOException
 +//  {
 +//    byte [] buffer = new byte [2048];
 +//    
 +//    int bytes_to_write = length;
 +//    
 +//    int read = -1;
 +//    while ((read = is.read(buffer, 0, (bytes_to_write >= buffer.length) ? buffer.length : bytes_to_write)) > 0)
 +//    {
 +//      os.write(buffer, 0, read);
 +//      bytes_to_write -= read;
 +//    }
 +//    is.close();
 +//    os.close();
 +//    
 +//    assert bytes_to_write == 0;
 +//  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/web/CurrentLocalOperation.java b/src/main/java/at/gv/egiz/pdfas/web/CurrentLocalOperation.java new file mode 100644 index 0000000..83d214c --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/web/CurrentLocalOperation.java @@ -0,0 +1,87 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.web;
 +
 +import java.util.List;
 +import java.util.Properties;
 +
 +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder;
 +import at.knowcenter.wag.egov.egiz.web.LocalRequest;
 +
 +/**
 + * Encapsulates a local operation.
 + * 
 + * <p>
 + * A local operation is a sequence of successive local verifications.
 + * </p>
 + * <p>
 + * This is held on the VerifySessionInformation so that the DataURLServlet and RetrieveSignatureDataServlet
 + * can provide their data to the local service easily.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public class CurrentLocalOperation
 +{
 +
 +  /**
 +   * The signature holders to be verified in the current local operation.
 +   */
 +  public List holders_to_be_verified;
 +
 +  
 +  /**
 +   * An array of local requests to be processed.
 +   */
 +  public LocalRequest[] requests = null;
 +
 +  /**
 +   * An array of response strings of the local requests.
 +   */
 +  public Properties[] response_properties = null;
 +
 +  /**
 +   * The index of the holder/request to be processed.
 +   */
 +  public int current_operation = 0;
 +
 +//  /**
 +//   * Tells, if the current local request has been finished.
 +//   */
 +//  public boolean finished = false;
 +
 +  /**
 +   * @see at.gv.egiz.pdfas.web.LocalOperation#isFinished()
 +   */
 +  public boolean isFinished()
 +  {
 +    return this.current_operation >= this.requests.length;
 +  }
 +  
 +  /**
 +   * @see at.gv.egiz.pdfas.web.LocalOperation#getCurrentLocalRequest()
 +   */
 +  public LocalRequest getCurrentLocalRequest()
 +  {
 +    return this.requests[this.current_operation];
 +  }
 +  
 +  /**
 +   * @see at.gv.egiz.pdfas.web.LocalOperation#getCurrentSignatureHolder()
 +   */
 +  public SignatureHolder getCurrentSignatureHolder()
 +  {
 +    return (SignatureHolder) this.holders_to_be_verified.get(this.current_operation);
 +  }
 +  
 +  /**
 +   * @see at.gv.egiz.pdfas.web.LocalOperation#finishCurrentOperation(java.util.Properties)
 +   */
 +  public void finishCurrentOperation(Properties response_properties)
 +  {
 +    this.response_properties[this.current_operation] = response_properties;
 +    
 +    this.current_operation++;
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/web/SignSessionInformation.java b/src/main/java/at/gv/egiz/pdfas/web/SignSessionInformation.java new file mode 100644 index 0000000..459a104 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/web/SignSessionInformation.java @@ -0,0 +1,140 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.web;
 +
 +import java.io.Serializable;
 +import java.util.Properties;
 +
 +import javax.servlet.http.HttpSessionBindingEvent;
 +import javax.servlet.http.HttpSessionBindingListener;
 +
 +import at.gv.egiz.pdfas.impl.input.FileBasedPdfDataSourceImpl;
 +import at.gv.egiz.pdfas.impl.output.FileBasedDataSink;
 +import at.gv.egiz.pdfas.web.helper.TempDirHelper;
 +import at.gv.egiz.pdfas.framework.signator.SignatorInformation;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.knowcenter.wag.egov.egiz.pdf.TablePos;
 +import at.knowcenter.wag.egov.egiz.web.ExternAppInformation;
 +import at.knowcenter.wag.egov.egiz.web.LocalRequest;
 +
 +/**
 + * @author wprinz
 + * 
 + */
 +public class SignSessionInformation implements HttpSessionBindingListener, Serializable
 +{
 +  /**
 +   * SVUID.
 +   */
 +  private static final long serialVersionUID = 2739944460007369626L;
 +
 +  /**
 +   * The log.
 +   */
 +  private static Log log = LogFactory.getLog(SignSessionInformation.class);
 +
 +  /**
 +   * The connector.
 +   */
 +  public String connector = null;
 +
 +  /**
 +   * For local requests, tells the application (sign, verify).
 +   */
 +  public String application = null;
 +
 +  /**
 +   * Tells the operation mode (binary, textual).
 +   */
 +  public String mode = null;
 +
 +  /**
 +   * The original, uploaded pdf.
 +   */
 +  public FileBasedPdfDataSourceImpl pdfDataSource = null;
 +
 +  /**
 +   * The type/profile of the signature.
 +   */
 +  public String type = null;
 +
 +  /**
 +   * The suggested filename.
 +   */
 +  public String filename;
 +
 +  /**
 +   * Tells, if the file download should be done inline or as attachment.
 +   */
 +  public boolean download_inline;
 +
 +  /**
 +   * Object containing information about the calling webapplication.
 +   * 
 +   * @author: Thomas Zefferer
 +   */
 +  public ExternAppInformation exappinf;
 +
 +  /**
 +   * Information about the signature position
 +   * 
 +   * @author: Thomas Zefferer
 +   */
 +  public TablePos pos;
 +
 +  /**
 +   * The SignatorInformation.
 +   */
 +  public SignatorInformation si = null;
 +
 +  /**
 +   * The DataSink to write the output data to.
 +   */
 +  public FileBasedDataSink output = null;
 +
 +  /**
 +   * The local request to be sent to the device.
 +   */
 +  public LocalRequest localRequest = null;
 +  
 +  /**
 +   * The response properties of the local request.
 +   */
 +  public Properties response_properties = null;
 +
 +  /**
 +   * Tells if the sign request has been processed and the signed document is
 +   * available in the DataSink.
 +   */
 +  public boolean outputAvailable = false;
 +
 +
 +  /**
 +   * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)
 +   */
 +  public void valueBound(HttpSessionBindingEvent event)
 +  {
 +    log.debug("Bound SignSessionInformation to session.");
 +  }
 +
 +  /**
 +   * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent)
 +   */
 +  public void valueUnbound(HttpSessionBindingEvent event)
 +  {
 +    log.debug("Unbound SignSessionInformation from session.");
 +    
 +    if (this.pdfDataSource != null)
 +    {
 +      TempDirHelper.deleteDataSourceIfFileBased(this.pdfDataSource);
 +    }
 +    if (this.output != null)
 +    {
 +      TempDirHelper.deleteDataSinkIfFileBased(this.output);
 +    }
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/web/VerifySessionInformation.java b/src/main/java/at/gv/egiz/pdfas/web/VerifySessionInformation.java new file mode 100644 index 0000000..e998ded --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/web/VerifySessionInformation.java @@ -0,0 +1,195 @@ +/**
 + * <copyright> Copyright (c) 2006 by Know-Center, Graz, Austria </copyright>
 + * 
 + * This software is the confidential and proprietary information of Know-Center,
 + * Graz, Austria. You shall not disclose such Confidential Information and shall
 + * use it only in accordance with the terms of the license agreement you entered
 + * into with Know-Center.
 + * 
 + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 + * DERIVATIVES.
 + * 
 + * $Id: SessionInformation.java,v 1.2 2006/08/25 17:06:11 wprinz Exp $
 + */
 +package at.gv.egiz.pdfas.web;
 +
 +import java.io.Serializable;
 +import java.util.Iterator;
 +import java.util.List;
 +
 +import javax.servlet.http.HttpSessionBindingEvent;
 +import javax.servlet.http.HttpSessionBindingListener;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.gv.egiz.pdfas.framework.input.DataSource;
 +import at.gv.egiz.pdfas.web.helper.TempDirHelper;
 +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder;
 +import at.knowcenter.wag.egov.egiz.pdf.TablePos;
 +import at.knowcenter.wag.egov.egiz.web.ExternAppInformation;
 +
 +/**
 + * This class is a collection of various session parameters that are passed
 + * between the servlets and jsps.
 + * 
 + * <p>
 + * The SessionInformation class contains type safe references to the objects.
 + * </p>
 + * 
 + * @author wprinz
 + */
 +public class VerifySessionInformation implements HttpSessionBindingListener, Serializable
 +{
 +
 +  /**
 +   * SVUID.
 +   */
 +  private static final long serialVersionUID = -7413884936584659150L;
 +
 +  /**
 +   * The log.
 +   */
 +  private static Log log = LogFactory.getLog(VerifySessionInformation.class);
 +
 +  /**
 +   * The connector.
 +   */
 +  public String connector = null;
 +
 +  /**
 +   * For local requests, tells the application (sign, verify).
 +   */
 +  public String application = null;
 +
 +  /**
 +   * Tells the operation mode (binary, textual).
 +   */
 +  public String mode = null;
 +
 +  /**
 +   * The original, uploaded pdf.
 +   */
 +  //public FileBasedPdfDataSourceImpl pdfDataSource = null;
 +  public DataSource inputDataSource = null;
 +
 +  /**
 +   * The type/profile of the signature.
 +   */
 +  public String type = null;
 +
 +//  /**
 +//   * The user name.
 +//   */
 +//  public String user_name = null;
 +//
 +//  /**
 +//   * The password.
 +//   */
 +//  public String user_password = null;
 +
 +  /**
 +   * All SignatureHolders extracted from the document.
 +   */
 +  public List signature_holders;
 +
 +  /**
 +   * Keeps track of the currently running local operation.
 +   * 
 +   * <p>
 +   * Only valid during local verify.
 +   * </p>
 +   */
 +  public CurrentLocalOperation currentLocalOperation = null;
 +  
 +  /**
 +   * This is used only for MOA loc-ref web verify.
 +   */
 +  public SignatureHolder moa_holder;
 +  
 +
 +//  /**
 +//   * The incremental update information that has been extracted from the given
 +//   * PDF document.
 +//   */
 +//  public IncrementalUpdateInformation iui;
 +
 +//  public SignatorInformation si = null;
 +  
 +//  public FileBasedDataSink output = null;
 +  
 +  
 +//  /**
 +//   * Copy of signature holders. It's needed by BKU when we try to verify single by single 
 +//   * signature.
 +//   */
 +//  public List copy_of_signature_holders;
 +
 +//  /**
 +//   * The suggested filename.
 +//   */
 +//  public String filename;
 +//
 +//  /**
 +//   * Tells, if the file download should be done inline or as attachment.
 +//   */
 +//  public boolean download_inline;
 +
 +////  /**
 +////   * The sign result to be passed back to the user.
 +////   */
 +////  public SignResult sign_result;
 +//  
 +//  public boolean isSignFinished = false;
 +  
 +  
 +  
 +  /**
 +   * Object containing information about the calling webapplication.
 +   * @author: Thomas Zefferer
 +   */  
 +  public ExternAppInformation exappinf;
 +  
 +  /**
 +   * Information about the signature position
 +   * @author: Thomas Zefferer
 +   */  
 +  public TablePos pos ;  
 +
 +
 +  
 +  /**
 +   * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)
 +   */
 +  public void valueBound(HttpSessionBindingEvent event)
 +  {
 +    log.debug("Bound SignSessionInformation to session.");
 +  }
 +
 +  /**
 +   * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent)
 +   */
 +  public void valueUnbound(HttpSessionBindingEvent event)
 +  {
 +    log.debug("Unbound SignSessionInformation from session.");
 +    
 +    if (this.inputDataSource != null)
 +    {
 +      TempDirHelper.deleteDataSourceIfFileBased(this.inputDataSource);
 +    }
 +    if (this.signature_holders != null)
 +    {
 +      Iterator it = this.signature_holders.iterator();
 +      while (it.hasNext())
 +      {
 +        SignatureHolder sh = (SignatureHolder) it.next();
 +        TempDirHelper.deleteDataSourceIfFileBased(sh.getDataSource());
 +      }
 +    }
 +  }
 +
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java b/src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java new file mode 100644 index 0000000..5752838 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/web/helper/SessionHelper.java @@ -0,0 +1,48 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.web.helper;
 +
 +import javax.servlet.ServletException;
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpSession;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.gv.egiz.pdfas.exceptions.web.SessionExpiredException;
 +import at.knowcenter.wag.egov.egiz.web.SessionAttributes;
 +
 +/**
 + * @author wprinz
 + * 
 + */
 +public class SessionHelper
 +{
 +  /**
 +   * The log.
 +   */
 +  private static Log log = LogFactory.getLog(SessionHelper.class);
 +
 +  public static Object getSession(HttpServletRequest request) throws SessionExpiredException
 +  {
 +
 +    HttpSession session = request.getSession(false);
 +    if (session == null)
 +    {
 +      String msg = "There is no session associated with this request."; //$NON-NLS-1$
 +      log.error(msg);
 +      throw new SessionExpiredException(msg);
 +    }
 +
 +    Object sessionObject = session.getAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION);
 +    if (sessionObject == null)
 +    {
 +      String msg = "The session is not found or no longer valid."; //$NON-NLS-1$
 +      log.error(msg);
 +      throw new SessionExpiredException(msg);
 +    }
 +
 +    return sessionObject;
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java b/src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java new file mode 100644 index 0000000..55e0051 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/web/helper/SignServletHelper.java @@ -0,0 +1,229 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.web.helper;
 +
 +import java.io.IOException;
 +import java.net.URL;
 +
 +import javax.servlet.RequestDispatcher;
 +import javax.servlet.ServletContext;
 +import javax.servlet.ServletException;
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.gv.egiz.pdfas.framework.SignatorFactory;
 +import at.gv.egiz.pdfas.framework.signator.Signator;
 +import at.gv.egiz.pdfas.web.SignSessionInformation;
 +import at.knowcenter.wag.egov.egiz.PdfASID;
 +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
 +import at.knowcenter.wag.egov.egiz.framework.signators.DetachedSignator_1_0_0;
 +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorChooser;
 +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject;
 +import at.knowcenter.wag.egov.egiz.web.FormFields;
 +import at.knowcenter.wag.egov.egiz.web.LocalRequestHelper;
 +
 +/**
 + * @author wprinz
 + *
 + */
 +public class SignServletHelper
 +{
 +  /**
 +   * The log.
 +   */
 +  private static Log log = LogFactory.getLog(SignServletHelper.class);
 +
 +  protected static void dispatch(HttpServletRequest request, HttpServletResponse response, String resource, ServletContext context) throws ServletException, IOException
 +  {
 +    response.setContentType("text/html");
 +    response.setCharacterEncoding("UTF-8");
 +
 +    RequestDispatcher disp = context.getRequestDispatcher(resource);
 +    disp.forward(request, response);
 +  }
 +
 +
 +  /**
 +   * Prepares the sign.
 +   * 
 +   * <p>
 +   * This prepares the data for both being signed or being previewed.
 +   * </p>
 +   * 
 +   * @param si
 +   *          The SessionInformation to be prepared.
 +   * @throws PresentableException
 +   *           f.e.
 +   */
 +  public static void prepareSign(SignSessionInformation si) throws PresentableException
 +  {
 +    log.debug("prepareSign:"); //$NON-NLS-1$
 +
 +    PdfASID algorithm = FormFields.translateSignatureModeToPdfASID(si.mode);
 +    Signator signator = SignatorFactory.createSignator(algorithm);
 +
 +    // tzefferer: modified
 +    // si.iui = signator.prepareSign(si.pdf, si.type, null,
 +    // ConnectorFactory.needsSIG_ID(si.connector));
 +    si.si = signator.prepareSign(si.pdfDataSource, si.type, si.pos, ConnectorFactory.needsSIG_ID(si.connector));
 +    // end modify
 +    log.debug("prepareSign finished."); //$NON-NLS-1$
 +  }
 +  
 +  /**
 +   * Finishes the sign.
 +   * 
 +   * <p>
 +   * For non local connectors this concludes the sign process, signs the
 +   * document and returns the result. For local connectors this initializes the
 +   * local sign process and redirects to following servlets.
 +   * </p>
 +   * 
 +   * @param si
 +   *          The SessionInformation.
 +   * @param request
 +   *          The servlet request for dispatching.
 +   * @param response
 +   *          The servlet response for dispatching.
 +   * @param context
 +   *          The servlet context for dispatching.
 +   * @throws PresentableException
 +   *           f.e.
 +   * @throws IOException
 +   *           f. e.
 +   * @throws ServletException
 +   *           f. e.
 +   */
 +  public static void finishSign(SignSessionInformation si, HttpServletRequest request, HttpServletResponse response, ServletContext context) throws PresentableException, IOException, ServletException
 +  {
 +    log.debug("finishSign:"); //$NON-NLS-1$
 +
 +    log.debug("connector = " + si.connector); //$NON-NLS-1$
 +    if (ConnectorFactory.isConnectorLocal(si.connector))
 +    {
 +      log.debug("Connector is local -> dispatching to local processing."); //$NON-NLS-1$
 +
 +      String dispatch_to = LocalRequestHelper.processLocalSign(si, request, response);
 +      dispatch(request, response, dispatch_to, context);
 +      return;
 +    }
 +    log.debug("Connector is not local -> finishing the sign."); //$NON-NLS-1$
 +
 +    PdfASID algorithm = FormFields.translateSignatureModeToPdfASID(si.mode);
 +    Signator signator = SignatorFactory.createSignator(algorithm);
 +
 +    log.debug("RequestURL = " + request.getRequestURL());
 +    log.debug("ContextPath = " + request.getContextPath());
 +    String host = request.getServerName();
 +    URL signature_data_URL = new URL(request.getScheme(), host, request.getServerPort(), request.getContextPath() + "/RetrieveSignatureData");
 +    String signature_data_url = response.encodeURL(signature_data_URL.toString());
 +
 +    Connector c = ConnectorChooser.chooseWebConnectorForSign(si.connector, si.type, signature_data_url);
 +    SignSignatureObject signSignatureObject = c.doSign(si.si.getSignatureData());
 +    
 +    si.si.setSignSignatureObject(signSignatureObject);
 +
 +    si.output = TempDirHelper.createTempDataSink(si.filename + "_signed.pdf"); 
 +    signator.finishSign(si.si, si.output);
 +
 +    returnSignResponse(si, response);
 +
 +    log.debug("finishSign finished."); //$NON-NLS-1$
 +  }
 +  
 +  /**
 +   * Returns the data in the SignResult with proper content disposition.
 +   * 
 +   * @param si
 +   *          SessionInformation.
 +   * @param response
 +   *          The servlet response.
 +   * @throws IOException
 +   *           The IO Exception.
 +   */
 +  public static void returnSignResponse(SignSessionInformation si, HttpServletResponse response) throws IOException
 +  {
 +//    SignResult sign_result = si.sign_result;
 +
 +    String file_name = formatFileNameForSignResult(si.filename, si.output.getMimeType());
 +
 +    // tzefferer: added condition
 +    if (si.exappinf == null)
 +    {
 +
 +      // The name parameter is actually deprecated in favour of
 +      // Content-Disposition filename
 +      // Unfortunately Acrobat reader does recognize neither of these parameters
 +      // with its inline save-as. It always takes the page name.
 +      response.setContentType(si.output.getMimeType() + "; name=\"" + file_name + "\"");
 +      if (si.download_inline)
 +      {
 +        response.addHeader("Content-Disposition", "inline; filename=\"" + file_name + "\"");
 +      }
 +      else
 +      {
 +        response.addHeader("Content-Disposition", "attachment; filename=\"" + file_name + "\"");
 +      }
 +      
 +      TempDirHelper.writeDataSinkToHttpResponse(si.output, response);
 +      //response.getOutputStream().write(sign_result.getData());
 +      
 +      // tzefferer: added else-block
 +    }
 +    else
 +    {
 +      // TODO @tzefferer: what is this code?
 +      throw new RuntimeException("This has to be refactored.");
 +//      SignResult sr = si.sign_result;
 +//      byte[] signed_pdf = sr.getData();
 +//      PDFContainer entry = new PDFContainer(signed_pdf, si.exappinf.pdf_id);
 +//      ProvidePDFServlet.signedDocuments.add(entry);
 +//
 +//      // notify webapp...
 +//      String invoke_url = si.exappinf.invoke_url;
 +//
 +//      String providePDFServlet = "ProvidePDF";
 +//      String pdf_id = String.valueOf(si.exappinf.pdf_id);
 +//      String session_id = si.exappinf.session_id;
 +//
 +//      // build URL
 +//      int ind = invoke_url.indexOf("?");
 +//      String query = invoke_url.substring(0, ind) + ";jsessionid=" + session_id + invoke_url.substring(ind) + "&" + FormFields.FIELD_PDF_URL + "=" + providePDFServlet + "&" + FormFields.FIELD_PDF_ID
 +//          + "=" + pdf_id + "&" + FormFields.FIELD_FILE_LENGTH + "=" + signed_pdf.length;
 +//
 +//      response.sendRedirect(query);
 +
 +    }
 +
 +  }
 +  
 +  /**
 +   * Formats the file name according to the SignResult.
 +   * 
 +   * @param file_name
 +   *          The file name.
 +   * @param sign_result
 +   *          The sign result.
 +   * @return Returns the formatted file name.
 +   */
 +  public static String formatFileNameForSignResult(String file_name, String mimeType)
 +  {
 +    String output = file_name + "_signed";
 +    if (mimeType.equals(DetachedSignator_1_0_0.MIME_TYPE))
 +    {
 +      output += ".xml";
 +    }
 +    else
 +    {
 +      output += ".pdf";
 +    }
 +
 +    return output;
 +  }
 +}
 diff --git a/src/main/java/at/gv/egiz/pdfas/web/helper/TempDirHelper.java b/src/main/java/at/gv/egiz/pdfas/web/helper/TempDirHelper.java new file mode 100644 index 0000000..9f2b6fb --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/web/helper/TempDirHelper.java @@ -0,0 +1,242 @@ +/**
 + * 
 + */
 +package at.gv.egiz.pdfas.web.helper;
 +
 +import java.io.File;
 +import java.io.FileInputStream;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.OutputStream;
 +import java.io.OutputStreamWriter;
 +import java.text.DecimalFormat;
 +import java.text.NumberFormat;
 +import java.util.Iterator;
 +import java.util.List;
 +
 +import javax.servlet.http.HttpServletResponse;
 +
 +import org.apache.commons.logging.Log;
 +import org.apache.commons.logging.LogFactory;
 +
 +import at.gv.egiz.pdfas.framework.input.DataSource;
 +import at.gv.egiz.pdfas.framework.input.TextDataSource;
 +import at.gv.egiz.pdfas.framework.output.DataSink;
 +import at.gv.egiz.pdfas.impl.input.FileBased;
 +import at.gv.egiz.pdfas.impl.input.FileBasedPdfDataSourceImpl;
 +import at.gv.egiz.pdfas.impl.input.FileBasedTextDataSourceImpl;
 +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl;
 +import at.gv.egiz.pdfas.impl.output.FileBasedDataSink;
 +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader;
 +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder;
 +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder;
 +
 +/**
 + * @author wprinz
 + * 
 + */
 +public class TempDirHelper
 +{
 +  /**
 +   * The log.
 +   */
 +  private static Log log = LogFactory.getLog(TempDirHelper.class);
 +
 +  protected static long runningIndex = 0;
 +
 +  public static void storeTextSignatureHoldersIfApplicable(List shs, String fileNameSuffix) throws IOException
 +  {
 +    Iterator it = shs.iterator();
 +    while (it.hasNext())
 +    {
 +      SignatureHolder sh = (SignatureHolder) it.next();
 +      if (sh instanceof TextualSignatureHolder)
 +      {
 +        TextualSignatureHolder tsh = (TextualSignatureHolder) sh;
 +        if (!(tsh.getDataSource() instanceof FileBased))
 +        {
 +          TextDataSource tds = (TextDataSource) tsh.getDataSource();
 +          if (isReasonableToStore(tds.getText().length()))
 +          {
 +            TextDataSource fbtds = placeTextIntoTempDir(tds.getText(), fileNameSuffix);
 +            tsh.exchangeDataSource(fbtds);
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  /**
 +   * Places the text into the temp dir if reasonable.
 +   * 
 +   * <p>
 +   * Reasonable means that the text is longer than a certain threshold.
 +   * Otherwise a short text is simply held in memory.
 +   * </p>
 +   * 
 +   * @param text
 +   *          The text to be stored.
 +   * @param fileNameSuffix
 +   *          A file name suffix so that the temp file gets a more "readable"
 +   *          name.
 +   * @return Returns the TextDataSource.
 +   * @throws IOException
 +   *           F.e.
 +   */
 +  public static TextDataSource placeTextIntoTempDir(String text, String fileNameSuffix) throws IOException
 +  {
 +    if (isReasonableToStore(text.length()))
 +    {
 +      String fileName = formatFileName(fileNameSuffix);
 +
 +      File tmpFile = createTempFileInDir(fileName);
 +
 +      FileOutputStream fos = new FileOutputStream(tmpFile);
 +      OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
 +      osw.write(text);
 +      osw.close();
 +
 +      FileBasedTextDataSourceImpl textDataSource = new FileBasedTextDataSourceImpl(tmpFile, "UTF-8");
 +      return textDataSource;
 +    }
 +    else
 +    {
 +      return new TextDataSourceImpl(text);
 +    }
 +  }
 +
 +  /**
 +   * Tells, if it is reasonable to store the text of the given length onto the
 +   * disk.
 +   * 
 +   * @param textLength
 +   *          The length of the text under question.
 +   * @return Returns true if the text should be stored on the disk.
 +   */
 +  public static boolean isReasonableToStore(int textLength)
 +  {
 +    return textLength >= 10000;
 +  }
 +
 +  public static FileBasedPdfDataSourceImpl placePdfIntoTempDir(InputStream pdfInput, String fileNameSuffix) throws IOException
 +  {
 +    File pdfFile = placeInputIntoTempDirFile(pdfInput, fileNameSuffix);
 +
 +    FileBasedPdfDataSourceImpl pdfDataSource = new FileBasedPdfDataSourceImpl(pdfFile, (int) pdfFile.length());
 +    return pdfDataSource;
 +  }
 +
 +  protected static File placeInputIntoTempDirFile(InputStream input, String fileNameSuffix) throws IOException
 +  {
 +    String fileName = formatFileName(fileNameSuffix);
 +
 +    File tmpFile = createTempFileInDir(fileName);
 +
 +    FileOutputStream fos = new FileOutputStream(tmpFile);
 +
 +    byte[] buffer = new byte[2048];
 +    int read = -1;
 +    while ((read = input.read(buffer)) > 0)
 +    {
 +      fos.write(buffer, 0, read);
 +    }
 +    fos.close();
 +    input.close();
 +
 +    return tmpFile;
 +  }
 +
 +  protected static String formatFileName(String fileNameSuffix)
 +  {
 +    String fileName = "tmp" + formatIndex(runningIndex) + "_" + fileNameSuffix;
 +    runningIndex++;
 +
 +    return fileName;
 +  }
 +
 +  protected static String formatIndex(long index)
 +  {
 +    NumberFormat nf = new DecimalFormat("00000000");
 +
 +    return nf.format(index);
 +  }
 +
 +  protected static File createTempFileInDir(String fileName) throws IOException
 +  {
 +    File tempDir = new File(new File(SettingsReader.RESOURCES_PATH), "pdfastmp");
 +
 +    File tmpFile = new File(tempDir, fileName);
 +
 +    tmpFile.createNewFile();
 +
 +    tmpFile.deleteOnExit();
 +
 +    return tmpFile;
 +  }
 +
 +  public static FileBasedDataSink createTempDataSink(String fileNameSuffix) throws IOException
 +  {
 +    String fileName = formatFileName(fileNameSuffix);
 +
 +    File tmpFile = createTempFileInDir(fileName);
 +
 +    FileBasedDataSink fbds = new FileBasedDataSink(tmpFile);
 +
 +    return fbds;
 +  }
 +
 +  public static void writeDataSinkToHttpResponse(FileBasedDataSink fbds, HttpServletResponse response) throws IOException
 +  {
 +
 +    response.setContentType(fbds.getMimeType());
 +    response.setCharacterEncoding(fbds.getCharacterEncoding());
 +
 +    OutputStream os = response.getOutputStream();
 +
 +    byte[] buffer = new byte[2048];
 +    FileInputStream fis = new FileInputStream(fbds.getFile());
 +    int n = -1;
 +    while ((n = fis.read(buffer)) > 0)
 +    {
 +      os.write(buffer, 0, n);
 +    }
 +    fis.close();
 +    os.close();
 +  }
 +
 +  /**
 +   * Deletes the underlying file of the FileBased DataSource.
 +   * 
 +   * <p>
 +   * If the DataSource is not FileBased, nothing is done.
 +   * </p>
 +   * <p>
 +   * This is usually used by the application to delete temporary files.
 +   * </p>
 +   * 
 +   * @param dataSource
 +   */
 +  public static void deleteDataSourceIfFileBased(DataSource dataSource)
 +  {
 +    if (dataSource instanceof FileBased)
 +    {
 +      FileBased fb = (FileBased) dataSource;
 +      log.debug("Deleting temp file " + fb.getFile());
 +      boolean deleted = fb.getFile().delete();
 +      log.debug("deleted = " + deleted);
 +    }
 +  }
 +
 +  public static void deleteDataSinkIfFileBased(DataSink dataSink)
 +  {
 +    if (dataSink instanceof FileBased)
 +    {
 +      FileBased fb = (FileBased) dataSink;
 +      log.debug("Deleting temp file " + fb.getFile());
 +      boolean deleted = fb.getFile().delete();
 +      log.debug("deleted = " + deleted);
 +    }
 +  }
 +
 +}
 | 
