From 6025b6016517c6d898d8957d1d7e03ba71431912 Mon Sep 17 00:00:00 2001 From: tknall Date: Fri, 1 Dec 2006 12:20:24 +0000 Subject: Initial import of release 2.2. git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@4 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../java/at/knowcenter/wag/egov/egiz/PdfAS.java | 1083 ++++++++++++ .../java/at/knowcenter/wag/egov/egiz/PdfASID.java | 173 ++ .../knowcenter/wag/egov/egiz/cfg/ConfigLogger.java | 71 + .../knowcenter/wag/egov/egiz/cfg/PropertyTree.java | 348 ++++ .../at/knowcenter/wag/egov/egiz/cfg/Settings.java | 57 + .../wag/egov/egiz/cfg/SettingsReader.java | 683 ++++++++ .../knowcenter/wag/egov/egiz/commandline/Main.java | 917 +++++++++++ .../egiz/exceptions/ConnectorFactoryException.java | 64 + .../egov/egiz/exceptions/ErrorCodeException.java | 308 ++++ .../egov/egiz/exceptions/InvalidIDException.java | 52 + .../egov/egiz/exceptions/NormalizeException.java | 72 + .../egov/egiz/exceptions/PDFDocumentException.java | 69 + .../egov/egiz/exceptions/PlaceholderException.java | 56 + .../egov/egiz/exceptions/PresentableException.java | 65 + .../egiz/exceptions/SettingNotFoundException.java | 70 + .../egov/egiz/exceptions/SettingsException.java | 63 + .../egiz/exceptions/SignatorFactoryException.java | 37 + .../egov/egiz/exceptions/SignatureException.java | 72 + .../egiz/exceptions/SignatureTypesException.java | 57 + .../wag/egov/egiz/exceptions/WebException.java | 72 + .../wag/egov/egiz/framework/FoundBlock.java | 198 +++ .../wag/egov/egiz/framework/FoundKey.java | 96 ++ .../wag/egov/egiz/framework/SignResult.java | 96 ++ .../wag/egov/egiz/framework/Signator.java | 67 + .../wag/egov/egiz/framework/SignatorFactory.java | 174 ++ .../egov/egiz/framework/VerificationFilter.java | 494 ++++++ .../wag/egov/egiz/framework/Verificator.java | 52 + .../framework/signators/BinarySignator_1_0_0.java | 195 +++ .../signators/DetachedSignator_1_0_0.java | 99 ++ .../framework/signators/TextualSignator_1_0_0.java | 122 ++ .../verificators/BinaryVerificator_1_0_0.java | 373 +++++ .../verificators/TextualVerificator_1_0_0.java | 136 ++ .../verificators/TextualVerificator_pdfasold.java | 97 ++ .../wag/egov/egiz/pdf/AbsoluteTextSignature.java | 656 ++++++++ .../wag/egov/egiz/pdf/BinaryBlockInfo.java | 53 + .../wag/egov/egiz/pdf/BinarySignature.java | 1731 ++++++++++++++++++++ .../wag/egov/egiz/pdf/BinarySignatureHolder.java | 146 ++ .../at/knowcenter/wag/egov/egiz/pdf/EGIZDate.java | 189 +++ .../egiz/pdf/IncrementalUpdateInformation.java | 152 ++ .../at/knowcenter/wag/egov/egiz/pdf/PDFPage.java | 539 ++++++ .../wag/egov/egiz/pdf/PDFSignatureCreation.java | 170 ++ .../wag/egov/egiz/pdf/PDFSignatureObject.java | 50 + .../wag/egov/egiz/pdf/PDFSignatureObjectIText.java | 490 ++++++ .../knowcenter/wag/egov/egiz/pdf/PDFUtilities.java | 89 + .../knowcenter/wag/egov/egiz/pdf/Placeholder.java | 552 +++++++ .../java/at/knowcenter/wag/egov/egiz/pdf/Pos.java | 62 + .../knowcenter/wag/egov/egiz/pdf/ReplaceInfo.java | 64 + .../wag/egov/egiz/pdf/SignatureHolder.java | 62 + .../knowcenter/wag/egov/egiz/pdf/SplitStrings.java | 162 ++ .../knowcenter/wag/egov/egiz/pdf/StringInfo.java | 93 ++ .../at/knowcenter/wag/egov/egiz/pdf/TablePos.java | 56 + .../wag/egov/egiz/pdf/TextualSignature.java | 177 ++ .../wag/egov/egiz/pdf/TextualSignatureHolder.java | 73 + .../at/knowcenter/wag/egov/egiz/pdf/Utils.java | 96 ++ .../at/knowcenter/wag/egov/egiz/sig/Connector.java | 59 + .../wag/egov/egiz/sig/ConnectorFactory.java | 326 ++++ .../wag/egov/egiz/sig/ConnectorInformation.java | 89 + .../knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java | 70 + .../wag/egov/egiz/sig/LocalConnector.java | 117 ++ .../wag/egov/egiz/sig/SignatureBlock.java | 306 ++++ .../wag/egov/egiz/sig/SignatureEntry.java | 155 ++ .../egov/egiz/sig/SignatureFieldDefinition.java | 80 + .../wag/egov/egiz/sig/SignatureObject.java | 1499 +++++++++++++++++ .../wag/egov/egiz/sig/SignatureResponse.java | 470 ++++++ .../wag/egov/egiz/sig/SignatureSeparator.java | 139 ++ .../wag/egov/egiz/sig/SignatureTypeDefinition.java | 423 +++++ .../wag/egov/egiz/sig/SignatureTypes.java | 462 ++++++ .../at/knowcenter/wag/egov/egiz/sig/X509Cert.java | 462 ++++++ .../wag/egov/egiz/sig/connectors/A1Connector.java | 55 + .../wag/egov/egiz/sig/connectors/BKUConnector.java | 813 +++++++++ .../egiz/sig/connectors/BKUPostConnection.java | 95 ++ .../sig/connectors/ConnectorConfigurationKeys.java | 35 + .../wag/egov/egiz/sig/connectors/MOAConnector.java | 880 ++++++++++ .../at/knowcenter/wag/egov/egiz/table/Entry.java | 227 +++ .../at/knowcenter/wag/egov/egiz/table/Style.java | 368 +++++ .../at/knowcenter/wag/egov/egiz/table/Table.java | 215 +++ .../knowcenter/wag/egov/egiz/test/AbsTexTest.java | 141 ++ .../at/knowcenter/wag/egov/egiz/test/BinSig.java | 345 ++++ .../wag/egov/egiz/test/ExtractTextTextual.java | 62 + .../at/knowcenter/wag/egov/egiz/test/X509.java | 40 + .../at/knowcenter/wag/egov/egiz/test/X509Ext.java | 48 + .../wag/egov/egiz/tools/CodingHelper.java | 272 +++ .../knowcenter/wag/egov/egiz/tools/FileHelper.java | 88 + .../knowcenter/wag/egov/egiz/tools/Normalize.java | 48 + .../wag/egov/egiz/tools/NormalizeV01.java | 166 ++ .../knowcenter/wag/egov/egiz/tools/Normalizer.java | 270 +++ .../egov/egiz/web/AsynchronousDataResponder.java | 155 ++ .../egiz/web/AsynchronousRedirectResponder.java | 196 +++ .../knowcenter/wag/egov/egiz/web/FormFields.java | 210 +++ .../knowcenter/wag/egov/egiz/web/LocalRequest.java | 80 + .../wag/egov/egiz/web/LocalRequestHelper.java | 226 +++ .../egov/egiz/web/PdfASServletContextListener.java | 76 + .../wag/egov/egiz/web/SessionAttributes.java | 46 + .../wag/egov/egiz/web/SessionInformation.java | 126 ++ .../knowcenter/wag/egov/egiz/web/SessionTable.java | 94 ++ .../java/at/knowcenter/wag/egov/egiz/web/Sign.java | 525 ++++++ .../knowcenter/wag/egov/egiz/web/SignPreview.java | 105 ++ .../at/knowcenter/wag/egov/egiz/web/Verify.java | 285 ++++ .../wag/egov/egiz/web/VerifyPreview.java | 704 ++++++++ .../knowcenter/wag/exactparser/ByteArrayUtils.java | 140 ++ .../knowcenter/wag/exactparser/ParseDocument.java | 265 +++ .../parsing/IndirectObjectReference.java | 49 + .../wag/exactparser/parsing/PDFNames.java | 176 ++ .../wag/exactparser/parsing/PDFUtils.java | 1393 ++++++++++++++++ .../parsing/results/ArrayParseResult.java | 34 + .../parsing/results/BooleanParseResult.java | 30 + .../parsing/results/ContainerParseResult.java | 37 + .../parsing/results/DictionaryParseResult.java | 33 + .../parsing/results/EOFParseResult.java | 39 + .../parsing/results/FooterParseResult.java | 45 + .../parsing/results/HeaderParseResult.java | 40 + .../parsing/results/HexStringParseResult.java | 28 + .../IndirectObjectReferenceParseResult.java | 36 + .../parsing/results/IntegerParseResult.java | 28 + .../parsing/results/LiteralStringParseResult.java | 29 + .../parsing/results/NameParseResult.java | 27 + .../parsing/results/NullParseResult.java | 26 + .../parsing/results/NumberParseResult.java | 33 + .../parsing/results/ObjectHeaderParseResult.java | 43 + .../parsing/results/ObjectParseResult.java | 42 + .../exactparser/parsing/results/ParseResult.java | 42 + .../parsing/results/StartXRefParseResult.java | 28 + .../parsing/results/StreamParseResult.java | 33 + .../parsing/results/TrailerParseResult.java | 76 + .../parsing/results/XRefLineParseResult.java | 32 + .../parsing/results/XRefSectionParseResult.java | 58 + .../parsing/results/XRefSubSectionParseResult.java | 51 + 127 files changed, 26796 insertions(+) create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/PdfASID.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/cfg/ConfigLogger.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/cfg/Settings.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorFactoryException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ErrorCodeException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/InvalidIDException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/NormalizeException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PDFDocumentException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PlaceholderException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PresentableException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingNotFoundException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingsException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatorFactoryException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureTypesException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/exceptions/WebException.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundBlock.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundKey.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/SignResult.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/Signator.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/SignatorFactory.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/Verificator.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_0_0.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_1_0_0.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_pdfasold.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinaryBlockInfo.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignatureHolder.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/EGIZDate.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/IncrementalUpdateInformation.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureCreation.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObject.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/Placeholder.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/Pos.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/ReplaceInfo.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/SignatureHolder.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/SplitStrings.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/StringInfo.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignatureHolder.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/pdf/Utils.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/table/Entry.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/table/Style.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/test/AbsTexTest.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/test/BinSig.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/test/ExtractTextTextual.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/test/X509.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/test/X509Ext.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalize.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/tools/NormalizeV01.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalizer.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousDataResponder.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousRedirectResponder.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/FormFields.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequest.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequestHelper.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/PdfASServletContextListener.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/SessionAttributes.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/SessionInformation.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/SessionTable.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/Sign.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/SignPreview.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/Verify.java create mode 100644 src/main/java/at/knowcenter/wag/egov/egiz/web/VerifyPreview.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/ByteArrayUtils.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/ParseDocument.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/IndirectObjectReference.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/PDFNames.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/PDFUtils.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/ArrayParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/BooleanParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/ContainerParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/DictionaryParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/EOFParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/FooterParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/HeaderParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/HexStringParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/IndirectObjectReferenceParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/IntegerParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/LiteralStringParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/NameParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/NullParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/NumberParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectHeaderParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/ParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/StartXRefParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/StreamParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/TrailerParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefLineParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSectionParseResult.java create mode 100644 src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSubSectionParseResult.java (limited to 'src/main/java/at/knowcenter/wag') diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java b/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java new file mode 100644 index 0000000..53fafe2 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java @@ -0,0 +1,1083 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PdfAS.java,v 1.5 2006/10/31 08:04:50 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Vector; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +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.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.framework.FoundBlock; +import at.knowcenter.wag.egov.egiz.framework.FoundKey; +import at.knowcenter.wag.egov.egiz.framework.SignResult; +import at.knowcenter.wag.egov.egiz.framework.Signator; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.framework.VerificationFilter; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; +import at.knowcenter.wag.egov.egiz.pdf.PDFSignatureCreation; +import at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject; +import at.knowcenter.wag.egov.egiz.pdf.PDFUtilities; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignature; +import at.knowcenter.wag.egov.egiz.sig.Connector; +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.tools.Normalizer; +import at.knowcenter.wag.exactparser.parsing.PDFUtils; +import at.knowcenter.wag.exactparser.parsing.results.HeaderParseResult; + +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.PdfPTable; +import com.lowagie.text.pdf.PdfReader; + +/** + * This class contains the major methods used by both, the commandline and the + * webapp, to perform signation and verification. + * + * @author wprinz + */ +public abstract class PdfAS +{ + /** + * The key of the strict mode setting. + */ + public static final String STRICT_MODE_KEY = "strict_mode"; + + /** + * The left/right border. + */ + public static final float SIGNATURE_BORDER = 100f; + + /** + * The top/bottom border. + */ + public static final float SIGNATURE_MARGIN = 20f; + + /** + * The Mime Type of a PDF document. + */ + public static final String PDF_MIME_TYPE = "application/pdf"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(PdfAS.class); + + /** + * Tells, if strict PDF checking the PDF version is enabled. + * + * @return Returns true, if incoming PDFs should be checked strictly. + */ + public static boolean isStrictPdfChecking() + { + try + { + SettingsReader settings = SettingsReader.getInstance(); + String strict_mode = settings.getSetting(STRICT_MODE_KEY, "false"); + if (strict_mode.equals("true")) + { + return true; + } + } + catch (SettingsException e) + { + e.printStackTrace(); + } + return false; + } + + /** + * Checks the version of the given PDF to be 1.4 or lower. + * + * @param pdf + * The PDF. + * @return Returns true, if the given PDF is strict 1.4, false otherwise. + * @throws PDFDocumentException + * Forwarded exception. + */ + public static boolean isPdf14(byte[] pdf) throws PDFDocumentException + { + try + { + HeaderParseResult hpr = PDFUtils.parseHeader(pdf, 0); + + if (hpr.major <= 1 && hpr.minor <= 4) + { + return true; + } + return false; + } + catch (Exception e) + { + throw new PDFDocumentException(201, e); + } + } + + /** + * Applies strict version mode on the PDF and throws an exception, if the pdf + * is not 1.4. + * + *

+ * If strict mode is deactivated, this does simply nothing. + *

+ * + * @param pdf + * The pdf to be checked against strict mode. + * @throws PDFDocumentException + */ + public static void applyStrictMode(byte[] pdf) throws PDFDocumentException + { + if (isStrictPdfChecking()) + { + if (!isPdf14(pdf)) + { + throw new PDFDocumentException(201, "StrictMode: The pdf version is not 1.4 or lower."); + } + } + } + + /** + * Verifies the given PDF document. + * + * @param pdf + * The PDF document. + * @param connector + * The connector. + * @return Returns the List of results. + * @throws PresentableException + * Forwarded exception. + */ + public static List verifyPdf(final byte[] pdf, final String connector) throws PresentableException + { + VerificationFilter vf = new VerificationFilter(); + List signature_holders = vf.extractSignaturesFromPdf(pdf); + if (signature_holders.isEmpty()) + { + throw new PDFDocumentException(206); + } + + List results = verifySignatureHolders(signature_holders, connector); + + return results; + } + + /** + * Verifies the given text that is supposed to be extracted from a PDF + * document using text extraction mechanisms. + * + * @param text + * The text to be verified. + * @param connector + * The connecor. + * @return Returns the List of results. + * @throws PresentableException + * Forwarded exception. + */ + public static List verifyText(final String text, final String connector) throws PresentableException + { + VerificationFilter vf = new VerificationFilter(); + List signature_holders = vf.extractSignaturesFromPlainText(text); + if (signature_holders.isEmpty()) + { + throw new PDFDocumentException(206); + } + + List results = verifySignatureHolders(signature_holders, connector); + + return results; + } + + /** + * Extracts all signature blocks from the given raw text using textual mode. + * + * @param raw_text + * The raw text. + * @return Returns a List of all SignatureHolders extracted from the text. + * @throws PDFDocumentException + * F.e. + * @throws SignatureException + * F.e. + * @throws SignatureTypesException + * @throws NormalizeException + */ + public static List extractSignatureHoldersTextual(String raw_text, + boolean old_style) throws PDFDocumentException, SignatureException, SignatureTypesException, NormalizeException + { + List signature_holders = new ArrayList(); + + String text = raw_text; + for (;;) + { + SignatureHolder holder = extractSignatureHolderTextual(text, old_style); + if (holder == null) + { + break; + } + { + logger_.debug("Found holder: " + holder.getSignatureObject().getSignationType()); + } + signature_holders.add(0, holder); + + text = holder.getSignedText(); + } + + return signature_holders; + } + + /** + * Extracts the last signature holder from the given text. + * + * @param raw_text + * @param old_style + * @return Returns the found singature holder, or null, if none could be + * found. + * @throws SignatureException + * @throws SignatureTypesException + * @throws NormalizeException + */ + public static SignatureHolder extractSignatureHolderTextual(String raw_text, + boolean old_style) throws SignatureException, SignatureTypesException, NormalizeException + { + SignatureTypes sig_types = SignatureTypes.getInstance(); + List signatureTypes_ = sig_types.getSignatureTypeDefinitions(); + + List found_blocks = new ArrayList(); + for (int cur_type = 0; cur_type < signatureTypes_.size(); cur_type++) + { + SignatureTypeDefinition cur_std = (SignatureTypeDefinition) signatureTypes_.get(cur_type); + + List found_keys = findBlockInText(raw_text, cur_std, old_style); + if (found_keys != null) + { + FoundBlock found_block = new FoundBlock(); + found_block.found_keys = found_keys; + found_block.end_index = raw_text.length(); + found_block.std = cur_std; + found_blocks.add(found_block); + } + } + + List last_most_blocks = sortOutEarlyBlocks(found_blocks); + + List minimum_blocks = sortOutLargeBlocks(last_most_blocks); + + if (minimum_blocks.size() > 1) + { + logger_.debug("There are still " + minimum_blocks.size() + " candidates:"); + + for (int i = 0; i < minimum_blocks.size(); i++) + { + FoundBlock fb = (FoundBlock) minimum_blocks.get(i); + logger_.debug(" fb: " + fb.std.getType()); + } + + logger_.debug("... checking for Semantic Equality."); + } + + boolean semantic_equality = checkForSemanticEquality(minimum_blocks); + + if (minimum_blocks.size() > 1) + { + logger_.debug("... Semantic Equality = " + semantic_equality); + } + + if (!semantic_equality) + { + throw new SignatureException(314); + } + + if (!minimum_blocks.isEmpty()) + { + FoundBlock actual_block = (FoundBlock) minimum_blocks.get(0); + + String signed_text = raw_text.substring(0, actual_block.getFirstKey().start_index); + + SignatureObject signatureObject_ = new SignatureObject(); + signatureObject_.setSigType(actual_block.std.getType()); + signatureObject_.initByType(); + + int end_index = actual_block.end_index; + for (int i = 0; i < actual_block.found_keys.size(); i++) + { + FoundKey cur_key = (FoundKey) actual_block.found_keys.get(i); + int start_index = cur_key.getStartIndex() + cur_key.caption.length(); + + String value = raw_text.substring(start_index, end_index); + + signatureObject_.setSigValueCaption(cur_key.getKey(), value, cur_key.caption); + + end_index = cur_key.getStartIndex(); + } + + // this normalization is required to get rid of possible trailing newlines. + String normalized_text = normalizeText(signed_text); + SignatureHolder holder = new TextualSignatureHolder(normalized_text, signatureObject_); + return holder; + } + + return null; + } + + /** + * Tries to find a block of the given type in the text. + * + * @param text + * The text. + * @param sig_type_def + * The type of the block. + * @param old_style + * Tells, if the block is old style (SIG_KZ will be ignored), or if + * it is a new block. + * @return Returns a List of the found keys of the block, or null, if the + * block could not be found. + */ + public static List findBlockInText(String text, + SignatureTypeDefinition sig_type_def, boolean old_style) + { + Vector keys = sig_type_def.getRevertSortedKeys(); + Vector captions = sig_type_def.getRevertSortedCaptions(); + + int last_index = text.length(); + + List found_keys = new ArrayList(); + for (int key_idx = 0; key_idx < keys.size(); key_idx++) + { + String key = (String) keys.get(key_idx); + + if (old_style && key.equals(SignatureTypes.SIG_KZ)) + { + // If separating the old style way - skip The "Kennzeichnung" + // key, because it wasn't present in old profiles. + continue; + } + + String caption = (String) captions.get(key_idx); + + int found_index = text.lastIndexOf(caption); + + if (key.equals(SignatureTypes.SIG_ID)) + { + if (found_index < 0 || found_index >= last_index) + { + // not found, SIG_ID is not required + continue; + } + FoundKey fk = new FoundKey(key, caption, found_index); + found_keys.add(fk); + } + else + { + if (found_index < 0 || found_index >= last_index) + { + // one key is not found - the profile doesn't match. + return null; + } + + FoundKey fk = new FoundKey(key, caption, found_index); + found_keys.add(fk); + last_index = found_index; + } + } + + sortFoundKeysDescendingly(found_keys); + + boolean matched = checkThatOrderIsCorrectAndCorrectFoundKeys(found_keys, keys, old_style); + // boolean found_required = checkFoundRequiredKeys(found_keys, old_style); + + if (matched) + { + return found_keys; + } + return null; + } + + /** + * Sorts the FoundKeys List descendingly according to the start indices of the + * found keys (the first found key in the list will have the highest start + * index, the second one the second highest and so forth). + * + * @param found_keys + * The List of FoundKey objects to be sorted. + */ + public static void sortFoundKeysDescendingly(List found_keys) + { + // sort the found_keys according to their start pos reversely. + + Collections.sort(found_keys, new Comparator() + { + public int compare(Object arg0, Object arg1) + { + FoundKey fk0 = (FoundKey) arg0; + FoundKey fk1 = (FoundKey) arg1; + // sort reversely! + return fk1.start_index - fk0.start_index; + } + }); + } + + /** + * Sorts the FoundKeys List ascendingly according to the start indices of the + * found keys (the first found key in the list will have the lowest start + * index, the second one the second lowest and so forth). + * + * @param found_keys + * The List of FoundKey objects to be sorted. + */ + public static void sortFoundKeysAscendingly(List found_keys) + { + // sort the found_keys according to their start pos. + + Collections.sort(found_keys, new Comparator() + { + public int compare(Object arg0, Object arg1) + { + FoundKey fk0 = (FoundKey) arg0; + FoundKey fk1 = (FoundKey) arg1; + return fk0.start_index - fk1.start_index; + } + }); + } + + /** + * Checks that the found keys are in correct order regarding SIG_ID as + * optional key. + * + *

+ * If the SIG_ID key is misplaced, it will be removed from the found keys + * list. + *

+ * + * @param found_keys + * The found keys ordered descendingly to their start position + * @param profile_keys + * The profile keys. + * @param old_style + * Tells, if SIG_KZ should be ignored, or not. + * @return Returns true, if the keys are correct. + */ + public static boolean checkThatOrderIsCorrectAndCorrectFoundKeys( + List found_keys, List profile_keys, boolean old_style) + { + + int found_index = 0; + for (int profile_index = 0; profile_index < profile_keys.size(); profile_index++) + { + String key = (String) profile_keys.get(profile_index); + + if (old_style && key.equals(SignatureTypes.SIG_KZ)) + { + continue; + } + + FoundKey found_key = (FoundKey) found_keys.get(found_index); + + boolean match = key.equals(found_key.getKey()); + if (match) + { + found_index++; + continue; + } + + if (key.equals(SignatureTypes.SIG_ID)) + { + continue; + } + + // doesn't match + return false; + } + + // remove all fields above the found_index - they are not correctly matched + // indices (should be only the ID + int size = found_keys.size(); + for (int i = found_index; i < size; i++) + { + // this removes all (size - found_index) objects above found_index + found_keys.remove(found_index); + } + + return true; + } + + /** + * Sorts out early blocks and leaves only those at the bottom of the text. + * + * @param found_blocks + * The found blocks. + * @return Returns a list of the last blocks. + */ + public static List sortOutEarlyBlocks(List found_blocks) + { + int last_most_index = Integer.MIN_VALUE; + + List last_most_blocks = new ArrayList(); + for (int block_index = 0; block_index < found_blocks.size(); block_index++) + { + FoundBlock block = (FoundBlock) found_blocks.get(block_index); + + int this_last_index = block.getLastKey().start_index; + if (this_last_index < last_most_index) + { + // this block cannot be the last most block. + continue; + } + if (this_last_index == last_most_index) + { + last_most_blocks.add(block); + continue; + } + if (this_last_index > last_most_index) + { + last_most_blocks = new ArrayList(); + last_most_blocks.add(block); + last_most_index = this_last_index; + } + } + + return last_most_blocks; + } + + /** + * Sorts out large blocks. + * + * @param found_blocks + * The found blocks. + * @return Returns a list of the smallest blocks. + */ + public static List sortOutLargeBlocks(List found_blocks) + { + int last_min_size = Integer.MAX_VALUE; + + List min_size_blocks = new ArrayList(); + for (int block_index = 0; block_index < found_blocks.size(); block_index++) + { + FoundBlock block = (FoundBlock) found_blocks.get(block_index); + + int size = block.getSize(); + + if (size > last_min_size) + { + // this block is larger + continue; + } + if (size == last_min_size) + { + min_size_blocks.add(block); + continue; + } + if (size < last_min_size) + { + min_size_blocks = new ArrayList(); + min_size_blocks.add(block); + last_min_size = size; + } + } + + return min_size_blocks; + } + + /** + * Checks the list of blocks for semantic equality. + * + * @param found_blocks + * The list of found blocks. + * @return Returns true if all blocks are semantically equal. + */ + public static boolean checkForSemanticEquality(List found_blocks) + { + if (found_blocks.size() <= 1) + { + return true; + } + + for (int block_index = 0; block_index < found_blocks.size() - 1; block_index++) + { + FoundBlock first_block = (FoundBlock) found_blocks.get(block_index); + FoundBlock second_block = (FoundBlock) found_blocks.get(block_index + 1); + + if (!first_block.isSemanticallyEqual(second_block)) + { + return false; + } + } + + return true; + } + + public static int getIndexOfFoundKey(List found_keys, String key) + { + for (int i = 0; i < found_keys.size(); i++) + { + FoundKey fk = (FoundKey) found_keys.get(i); + if (fk.getKey().equals(key)) + { + return i; + } + } + return -1; + } + + public static boolean containsFoundKey(List found_keys, String key) + { + return getIndexOfFoundKey(found_keys, key) >= 0; + } + + /** + * Checks the found keys for the required keys regarding the old style. + * + * @param found_keys + * The found keys. + * @param old_style + * Flag that tells, if KZ is not required. + * @return Returns true, if all required keys were found. + */ + public static boolean checkFoundRequiredKeys(List found_keys, + boolean old_style) + { + if (!containsFoundKey(found_keys, SignatureTypes.SIG_DATE)) + { + return false; + } + if (!containsFoundKey(found_keys, SignatureTypes.SIG_ISSUER)) + { + return false; + } + if (!containsFoundKey(found_keys, SignatureTypes.SIG_NUMBER)) + { + return false; + } + if (!containsFoundKey(found_keys, SignatureTypes.SIG_VALUE)) + { + return false; + } + if (!old_style && !containsFoundKey(found_keys, SignatureTypes.SIG_KZ)) + { + return false; + } + return true; + } + + /** + * Verifies the List of SignatureHolders using the given connector. + * + * @param signature_holders + * The List of SignatureHolder objects to be verified. + * @param connector + * The connector. + * @return Returns the List of SignatureResponse objects. + * @throws PDFDocumentException + * F.e. + * @throws NormalizeException + * F.e. + * @throws SignatureException + * F.e. + */ + public static List verifySignatureHolders(List signature_holders, + String connector) throws PDFDocumentException, NormalizeException, SignatureException + { + List results = new ArrayList(); + for (int i = 0; i < signature_holders.size(); i++) + { + SignatureHolder holder = (SignatureHolder) signature_holders.get(i); + + // logger_.debug(); + // logger_.debug(); + // logger_.debug("Verifying Holder " + i + "..."); + // logger_.debug("holder[" + i + "].signed_text = " + + // holder.signed_text); + // logger_.debug("holder[" + i + "].sig_obj = "); + // logger_.debug("holder[" + i + "].type = " + + // (holder.signature_object.isTextual() ? "textual" : "binary")); + // logger_.debug(holder.signature_object.toString()); + + SignatureResponse result = verify(holder, connector); + results.add(result); + + // logger_.debug(); + // logger_.debug("check[" + i + "].cert = " + + // result.getCertificateCheckInfo()); + // logger_.debug("check[" + i + "].sig = " + + // result.getSignatureCheckInfo().trim()); + // logger_.debug("check[" + i + "].manifest = " + + // result.getSignatureManifestCheckInfo()); + // logger_.debug(); + } + return results; + } + + /** + * Verifies a SignatureHolder using the given connector. + * + * @param signature_holder + * The SignatureHolder to be verified. + * @param connector + * The connector. + * @return Returns the SignatureResponse object. + * @throws NormalizeException + * F.e. + * @throws PDFDocumentException + * F.e. + * @throws SignatureException + * F.e. + */ + public static SignatureResponse verify(SignatureHolder signature_holder, + String connector) throws NormalizeException, PDFDocumentException, SignatureException + { + String text_to_be_verified = signature_holder.getSignedText(); + + SignatureObject so_to_be_verified = signature_holder.getSignatureObject(); + + if (text_to_be_verified == null) + { + throw new SignatureException(311, "Document can not be verified because the text to be verified is either null."); + } + if (text_to_be_verified.length() <= 0) + { + throw new SignatureException(311, "Document can not be verified because the length of the text to be verified is 0. (length = " + text_to_be_verified.length() + ")"); + } + + if (so_to_be_verified == null) + { + throw new SignatureException(312, "Document can not be verified because no signature object are set."); + } + + try + { + Connector connector_impl = ConnectorFactory.createConnector(connector); + return connector_impl.doVerify(text_to_be_verified, so_to_be_verified); + } + catch (ConnectorFactoryException e) + { + throw new SignatureException(310, e); + } + } + + /** + * Signs the given text with the provided connector using the given signature + * type. + * + * @param text_to_sign + * The text String to be signed. + * @param signature_type + * The type of the signature. + * @param connector + * The connector. + * @param user_name + * The user name. + * @param user_password + * The user password. + * @return Returns the corresponding SignatureObject. + * @throws SignatureException + * F.e. + * @throws PDFDocumentException + * F.e. + */ + public static SignatureObject sign(final String text_to_sign, + final String signature_type, final String connector, + final String user_name, final String user_password) throws SignatureException, PDFDocumentException + { + logger_.info("User signed a document: " + user_name); + + if (text_to_sign == null) { + throw new SignatureException(301, "Signature can not be produced. Text is null."); + } + if (text_to_sign.length() <= 0) + { + throw new SignatureException(301, "Signature can not be produced. Text is empty. (length = " + text_to_sign.length() + ")"); + } + + try + { + Connector connector_impl = ConnectorFactory.createConnector(connector); + SignatureObject signed_signature_object = connector_impl.doSign(signature_type, user_name, text_to_sign); + return signed_signature_object; + } + catch (ConnectorFactoryException e) + { + throw new SignatureException(300, e); + } + } + + /** + * Helper method that creates a SignatureObject and initializes it with the + * given type. + * + * @param signature_type + * The type. + * @return Returns the created SignatureObject. + * @throws SignatureException + * f.e. + * @throws SignatureTypesException + * f.e. + */ + public static SignatureObject createSignatureObjectFromType( + final String signature_type) throws SignatureException, SignatureTypesException + { + SignatureObject sig_obj = new SignatureObject(); + sig_obj.setSigType(signature_type); + sig_obj.initByType(); + + return sig_obj; + } + + /** + * Signs the document using the given algorithm. + * + * @param algorithm + * The Signator algorithm to be used. + * @param pdf + * The PDF. + * @param signature_type + * The signature type. + * @param connector + * The connector. + * @param user_name + * The user name. + * @param user_password + * The password. + * @param pos + * The absolute position. If null, the position is either taken from + * the profile or computed automatically. + * @return Returns the SignResult. + * @throws PresentableException + * F.e. + */ + public static SignResult sign(PdfASID algorithm, final byte[] pdf, + final String signature_type, final String connector, + final String user_name, final String user_password, TablePos pos) throws PresentableException + { + Signator signator = SignatorFactory.createSignator(algorithm); + + IncrementalUpdateInformation iui = signator.prepareSign(pdf, signature_type, pos, ConnectorFactory.needsSIG_ID(connector)); + + iui.signed_signature_object = sign(iui.document_text, signature_type, connector, user_name, user_password); + + SignResult sign_result = signator.finishSign(iui); + + return sign_result; + } + + /** + * Extracts and normalizes the text from the pdf. + * + * @param pdf + * The PDF document. + * @return Returns the text String. + * @throws PresentableException + * F.e. + */ + public static String extractNormalizedTextTextual(final byte[] pdf) throws PresentableException + { +// ByteArrayInputStream bais = new ByteArrayInputStream(pdf); +// String raw_document_text = TextualSignature.extractTextTextual(bais); +// +// String document_text = normalizeText(raw_document_text); + + return extractNormalizedTextTextual(pdf, pdf.length); + } + + /** + * Extracts and normalizes the text from the pdf. + * + * @param pdf + * The PDF document. + * @param length + * The length of the PDF document. The decument is considered to be + * that long even if the byte array is longer. + * @return Returns the text String. + * @throws PresentableException + * F.e. + */ + public static String extractNormalizedTextTextual(final byte[] pdf, final int length) throws PresentableException + { + ByteArrayInputStream bais = new ByteArrayInputStream(pdf, 0, length); + String raw_document_text = TextualSignature.extractTextTextual(bais); + + String document_text = normalizeText(raw_document_text); + + return document_text; + } + + /** + * Normalizes the given text. + * + * @param text + * The text to be normalized. + * @return Returns the normalized text. + * @throws NormalizeException + * F.e. + */ + public static String normalizeText(final String text) throws NormalizeException + { + Normalizer normalizer = new Normalizer(); + String normalized_text = normalizer.normalize(text); + return normalized_text; + } + + /** + * Creates the iText PDFPTable from a given SignatureObject. + * + * @param signature_object + * The SignatureObject. + * @return Returns the created PDFPTable. + * @throws PDFDocumentException + * F.e. + * @throws SignatureException + * F.e. + */ + public static PdfPTable createPdfPTableFromSignatureObject( + final SignatureObject signature_object) throws PDFDocumentException, SignatureException + { + PDFSignatureCreation creation = new PDFSignatureCreation(signature_object); + PDFSignatureObject pdf_sig_obj = creation.getPDFSignatureObject(); + PdfPTable pdf_table = (PdfPTable) pdf_sig_obj.getSignatureObject(); + + return pdf_table; + } + + /** + * Sets the width of the table according to the layout of the document and + * calculates the y position where the PDFPTable should be placed. + * + * @param pdf + * The PDF document. + * @param pdf_table + * The PDFPTable to be placed. + * @return Returns the position where the PDFPTable should be placed. + * @throws PDFDocumentException + * F.e. + */ + public static TablePos adjustTableAndCalculatePosition(final byte[] pdf, + PdfPTable pdf_table) throws PDFDocumentException + { + TablePos pos = new TablePos(); + + PdfReader reader = readInPdfDocument(pdf); + + Rectangle psize = reader.getPageSizeWithRotation(reader.getNumberOfPages()); + float page_width = psize.width(); + float page_height = psize.height(); + + pos.width = page_width - SIGNATURE_BORDER; + pdf_table.setTotalWidth(pos.width); + pdf_table.setLockedWidth(true); + + pos.pos_x = SIGNATURE_BORDER / 2; + + float table_height = pdf_table.getTotalHeight(); + float page_length = PDFUtilities.calculateLastPageLength(pdf); + pos.pos_y = page_height - page_length - SIGNATURE_MARGIN; + + pos.page = reader.getNumberOfPages(); + if (pos.pos_y <= table_height) + { + pos.page = -1; + // negative means to add a new page + pos.pos_y = page_height - SIGNATURE_BORDER / 2; + } + + return pos; + } + + /** + * Creates an iText Reader that parses the document. + *

+ * This is a convenience function for wrapping the Reader's exceptions into + * PDFDocumentException. + *

+ * + * @param pdf + * The PDF document. + * @return Returns the created PdfReader. + * @throws PDFDocumentException + * F.e. + */ + public static PdfReader readInPdfDocument(final byte[] pdf) throws PDFDocumentException + { + try + { + return new PdfReader(pdf); + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + } + + /** + * Parses the TablePos object from a given String with the appropriate format. + * + * @param pos_string + * The pos string. e.g. 1;40.0;600.0;300.0 + * @return Returns the parsed TablePos object. + * @throws PDFDocumentException + * Thrown, if the String doesn't have the proper format. + */ + public static TablePos parsePositionFromPosString(String pos_string) throws PDFDocumentException + { + String[] strs = pos_string.split(";"); + if (strs.length != 4) + { + throw new PDFDocumentException(224, "Pos string (=" + pos_string + ") is invalid."); + } + + try + { + TablePos pos = new TablePos(); + pos.page = Integer.parseInt(strs[0]); + pos.pos_x = Float.parseFloat(strs[1]); + pos.pos_y = Float.parseFloat(strs[2]); + pos.width = Float.parseFloat(strs[3]); + + if (pos.page < 1 && pos.page != -1) + { + throw new PDFDocumentException(225, "pos.page (=" + pos.page + ") must not be lower than -1 and must not be 0."); + } + + if (pos.width <= 0.0f) + { + throw new PDFDocumentException(226, "pos.width (=" + pos.width + ") must not be lower or equal 0."); + } + + return pos; + } + catch (NumberFormatException e) + { + throw new PDFDocumentException(224, "Pos string (=" + pos_string + ") cannot be parsed."); + } + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/PdfASID.java b/src/main/java/at/knowcenter/wag/egov/egiz/PdfASID.java new file mode 100644 index 0000000..0193368 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/PdfASID.java @@ -0,0 +1,173 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PdfASID.java,v 1.1 2006/08/25 17:04:16 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz; + +import java.io.Serializable; + +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException; + +/** + * This class encapsulates the Pdf-AS ID ("Kennzeichnung") urn. + * + * @author wprinz + */ +public class PdfASID implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 4776635173830445739L; + + /** + * The urn word that leads in the identifier. + */ + protected static final String URN = "urn"; + + /** + * The namespace of the urn. + */ + protected static final String NAMESPACE = "pdfsigfilter"; + + /** + * The separator between urn blocks. + */ + protected static final String SPLIT_STRING = ":"; + + /** + * The vendor. + */ + protected String vendor = null; + + /** + * The algorithm type. + */ + protected String type = null; + + /** + * The version of the algorithm. + */ + protected String version = null; + + /** + * Constructor that fills in the parameters directly. + * + * @param vendor + * @param type + * @param version + */ + public PdfASID(String vendor, String type, String version) + { + set(vendor, type, version); + } + + /** + * Parses the given id String and throws an Exception if it is not valid. + * + * @param id + * The id String to be parsed. + */ + public PdfASID(String id) throws InvalidIDException + { + String[] tokens = id.split(SPLIT_STRING); + + if (tokens.length != 5) + { + throw new InvalidIDException(800, "The doesn't have enough tokens (" + id + ")"); + } + + if (!tokens[0].equals(URN)) + { + throw new InvalidIDException(800, "The id must start with " + URN + " (" + id + ")"); + } + + if (!tokens[1].equals(NAMESPACE)) + { + throw new InvalidIDException(800, "The namespace of the id must be " + NAMESPACE + " (" + id + ")"); + } + + set(tokens[2], tokens[3], tokens[4]); + } + + /** + * Copy Constructor. + * + * @param other + * The other PdfASID to copy the data from. + */ + public PdfASID(final PdfASID other) + { + set(other.vendor, other.type, other.version); + } + + /** + * Auxiliary constructor. + * + * @param vendor + * The vendor. + * @param type + * The type. + * @param version + * The version. + */ + private void set(String vendor, String type, String version) + { + this.vendor = vendor; + this.type = type; + this.version = version; + } + + /** + * Returns the type. + * + * @return Returns the type. + */ + public String getType() + { + return this.type; + } + + /** + * Returns the vendor. + * + * @return Returns the vendor. + */ + public String getVendor() + { + return this.vendor; + } + + /** + * Returns the version. + * + * @return Returns the version. + */ + public String getVersion() + { + return this.version; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return URN + SPLIT_STRING + NAMESPACE + SPLIT_STRING + this.vendor + SPLIT_STRING + this.type + SPLIT_STRING + this.version; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/cfg/ConfigLogger.java b/src/main/java/at/knowcenter/wag/egov/egiz/cfg/ConfigLogger.java new file mode 100644 index 0000000..3b32c22 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/cfg/ConfigLogger.java @@ -0,0 +1,71 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: ConfigLogger.java,v 1.3 2006/08/30 13:55:50 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.cfg; + +import java.util.ArrayList; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +/** + * This logger class is the main logger class for the pdf-as project. It holds static logger + * instances with could be configured the level with one method. + */ +public class ConfigLogger { + + /** + * The static logger cache. It holds all used logger instances that could be configured by this + * main class. + */ + private static ArrayList logger_ = new ArrayList(); + /** + * This is the Level to use. Default is INFO. + */ + private static Level level_ = Level.INFO; + + /** + * This method activates a new log4j logger instance and store the instance in the local logger + * store. + * + * @param classRef the caller class to be set + * @return a log4j logger instance + * @see Logger + */ + public static Logger getLogger(Class classRef) { + Logger logger = Logger.getLogger(classRef); + //logger.setLevel(level_); + logger_.add(logger); + return logger; + } + + /** + * This method is to set a new logger level for all stored config logger. + * + * @param level the level to set + */ + public static void setLevel(Level level) { + level_ = level; + for (int log_idx = 0; log_idx < logger_.size(); log_idx++) { + Logger logger = (Logger) logger_.get(log_idx); + logger.setLevel(level_); + logger_.set(log_idx, logger); + } + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java b/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java new file mode 100644 index 0000000..fd700fe --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java @@ -0,0 +1,348 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: PropertyTree.java,v 1.4 2006/10/31 08:06:28 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.cfg; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +/** + * This class can be used to store a property config tree. The property key are separated by the + * {@link at.knowcenter.wag.egov.egiz.cfg.PropertyTree#SPLIT_STRING}. Therefore the keys an also + * the values of a configuration is stored in nested hashes. The keys in an area are stored in a + * HashMap. The values of a key are stored in a Vector to overload some keys. The property tree can + * be used to extract sub nodes and sub keys of different tree levels. + * + * @author wlackner + * @see java.util.HashMap + * @see java.util.Vector + */ +public class PropertyTree implements Serializable { + + /** + * SVUID. + */ + private static final long serialVersionUID = -1686170519955886222L; + + /** + * The key split string. A key can be a complex key. Sub keys are separated from each other with + * the split string. This string is used to devide the complex key. + */ + public static final String SPLIT_STRING = "\\."; + /** + * Stores the key references to the sub nodes + */ + private Map keys_ = new HashMap(3); + /** + * Stores all values of a node + */ + private Vector values_ = new Vector(3); + + /** + * The default constructor od the class. + */ + public PropertyTree() { + } + + /** + * This method takes a key value tupel and store them in the property tree. The key splitted into + * different levels (splitted by the string + * {@link at.knowcenter.wag.egov.egiz.cfg.PropertyTree#SPLIT_STRING}). All subnodes not stored in + * the tree will be created. The last part of the key (last splitted element) adds the value to + * there own value data structure (Vector).
+ * Example: setKeyValue("key.1_level.2_level","the value for k_1_2")null if the key is not a subtree referece + */ + private PropertyTree getLastSubTree(String splitKey) { + String[] keys = splitKey.split(SPLIT_STRING); + PropertyTree curr_tree = this; + for (int key_idx = 0; key_idx < keys.length; key_idx++) { + String key = keys[key_idx]; + if (!curr_tree.containsNode(key)) { + return null; + } + curr_tree = (PropertyTree) curr_tree.getSubNode(key); + } + return curr_tree; + } + + /** + * This method return the subtree that corresponds to a particular key. The key does not split. + * Therefore the key must be a children of the current node. Search only in the key map of the + * current node. + * + * @param key the key that has to be a sub node + * @return a sub tree (PropertyTree) or null if the key is not a children of the + * current node + */ + private PropertyTree getSubNode(String key) { + return (PropertyTree) keys_.get(key); + } + + /** + * Returns the last value (keys can be overloaded) of a key. The key are splitted into subnodes + * and the last node of the key is the current value holder. If a key or subnode is not in the sub + * tree the return value is null. + * + * @param key the key that holds the value (can be a nested key like "key.1.2.3") + * @return the value of the key (last node of the key) or null otherwise + */ + public String getLastValue(String key) { + PropertyTree curr_tree = getLastSubTree(key); + String result = null; + if (curr_tree != null && !curr_tree.values_.isEmpty()) { + result = (String) curr_tree.values_.lastElement(); + } +// if (logger_.isDebugEnabled()) { +// logger_.debug("getLastValue:" + key + "=" + result); +// } + return result; + } + + /** + * Returns the first value (keys can be overloaded) of a key. The key are splitted into subnodes + * and the last node of the key is the current value holder. If a key or subnode is not in the sub + * tree the return value is null. + * + * @param key the key that holds the value (can be a nested key like "key.1.2.3") + * @return the value of the key (last node of the key) or null otherwise + */ + public String getFirstValue(String key) { + PropertyTree curr_tree = getLastSubTree(key); + String result = null; + if (curr_tree != null && !curr_tree.values_.isEmpty()) { + result = (String) curr_tree.values_.firstElement(); + } +// if (logger_.isDebugEnabled()) { +// logger_.debug("getFirstValue:" + key + "=" + result); +// } + return result; + } + + /** + * This method return all values of the current node. The values are stored as String values. + * + * @return the values (type String) of the current node + * @see Vector + */ + public Vector getValues() { + return values_; + } + + /** + * This method return all keys (sub tree references) of the current node as a Map. The keys are + * stored as String values. + * + * @return the keys (type String) of the current node + * @see Map + */ + public Map getKeyEntries() { + return keys_; + } + + /** + * This method return all keys (sub tree references) of the current node as an ArrayList. The keys + * are stored as String values. + * + * @return the keys (type String) of the current node + * @see ArrayList + */ + public ArrayList getKeys() { + if (!keys_.isEmpty()) { + Object[] objs = keys_.keySet().toArray(); + ArrayList keys = new ArrayList(objs.length); + for (int idx = 0; idx < objs.length; idx++) { + keys.add((String) objs[idx]); + } + return keys; + } + return null; + } + + /** + * + * This method return all sub tree references of a key as an ArrayList. The keys are stored as + * String values. + * + * @param key (can be a nested key like "key.1.2.3") + * @return the keys (type String) of the current node + * @see ArrayList + */ + public ArrayList getKeys(String key) { + PropertyTree curr_tree = getLastSubTree(key); + if (curr_tree != null) { + return curr_tree.getKeys(); + } + return null; + } + + /** + * This method return all values of a key. The values are stored as String values. + * + * @param key (can be a nested key like "key.1.2.3") + * @return the values (type Vector) of the key or null if the key is not in the sub + * tree of the current node + * @see Vector + */ + public Vector getValues(String key) { + PropertyTree curr_tree = getLastSubTree(key); + if (curr_tree != null) { + return curr_tree.values_; + } + return null; + } + + /** + * Store a sub tree (type PropertyTree) in the current node. The key and it's sub tree are stored + * in a HashMap. + * + * @param key the reference of the sub tree + * @param tree the sub tree of the key + * @see HashMap + */ + private void setSubTree(String key, PropertyTree tree) { + if (tree == null) { + tree = new PropertyTree(); + } + keys_.put(key, tree); + } + + /** + * Extracts a sub tree of a nested key. The Method returns the last sub tree of the nested key. + * Example: if the key is like: key.1.2.3 the sub tree of the last + * node 3 is returned. + * + * @param key the reference of the sub tree + * @return a sub tree of the key or null if the key can not be found + */ + public PropertyTree getSubTree(String key) { + return getLastSubTree(key); + } + + /** + * This method checks if a key is a reference to a sub tree in the current node. + * + * @param key a simple key that is a parent reference of a sub tree + * @return true if the key is found, false otherwise + */ + public boolean containsNode(String key) { + return keys_.containsKey(key); + } + + /** + * The default toString method. It starts with the current node recursively downwards and return + * the String representation of the node. + * + * @return the string representation of the node + */ + public String toString() { + return toString("", this); + } + + /** + * This is a helper function to define the prefix for different levels in the toString method, not + * realy nice ;-). + * It replaces all "." chars with " ". + * + * @param key + * @return a replaces prefix string + */ + private static String getEmptyString(String key) { + return key.replaceAll(".", " "); + } + + /** + * This method concatenates all values of the current node and return them as a combinded string. + * + * @param prefix + * @param tree + * @return the string representation of the node values + */ + private static String printValues(String prefix, PropertyTree tree) { + String os = ""; + Iterator values = tree.getValues().iterator(); + while (values.hasNext()) { + String value = (String) values.next(); + os += prefix + "=" + value; + } + return os; + } + + /** + * The toString method. It starts with a special level prefix, sub tree and recursively adds all + * sub trees. + * + * @param prefix the prefix for this node + * @param tree the current node + * @return the string representation of the node + */ + public static String toString(String prefix, PropertyTree tree) { + String os = ""; + Iterator entries = tree.getKeyEntries().entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + String key = (String) entry.getKey(); + PropertyTree sub = (PropertyTree) entry.getValue(); + String os_key = "\n" + prefix + "." + key; + os += printValues(os_key, sub); + String subs = toString(prefix + getEmptyString(key) + " |", sub); + if (subs.length() > 0) { + os += os_key + "|" + subs; + } + } + return os; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/cfg/Settings.java b/src/main/java/at/knowcenter/wag/egov/egiz/cfg/Settings.java new file mode 100644 index 0000000..b8eb35e --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/cfg/Settings.java @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: Settings.java,v 1.2 2006/08/03 07:43:03 wprinz Exp $ + */ + +package at.knowcenter.wag.egov.egiz.cfg; + +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; + +/** + * Defines an interface reading a configuration file. + * + * @author wlackner + */ +public interface Settings { + /** + * Search for a key in the configuration file. + * + * @param key to search for + * @return the corresponding value + * @throws SettingNotFoundException if the key is not found + */ + public String getSetting(String key) throws SettingNotFoundException; + + /** + * Search for a key in the configuration file. + * + * @param key to search for + * @param defaultValue return this value if the key is not found + * @return the corresponding value + */ + public String getSetting(String key, String defaultValue); + + /** + * + * @param primaryKey to search for + * @param defaultKey to search for if the primaryKey is not found + * @param defaultValue return this value if the defaultKey is not found + * @return the corresponding value + */ + public String getSetting(String primaryKey, String defaultKey, String defaultValue); +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java b/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java new file mode 100644 index 0000000..a884140 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java @@ -0,0 +1,683 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SettingsReader.java,v 1.6 2006/10/31 08:06:36 wprinz Exp $ + */ + +package at.knowcenter.wag.egov.egiz.cfg; + +import java.io.FileInputStream; +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.Vector; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Properties; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * The SettingsReader reads the settings.txt file. The + * settings.txt is a simple java property file that collects all + * parameters used in different modules. + * + * The SettingsReader provides methods to get the property keys and the + * corresponding values. The keys could be defined as combinations of single + * keys. Therefore it is possible to combine differen classes of keys. An + * example could be: + * + *
+ *     
+ *      
+ *       
+ *        
+ *         
+ *          
+ *           
+ *            
+ *             
+ *              
+ *               
+ *                        #SettingNotFoundException
+ *                        error.code.100=Interner Fehler
+ *                        error.code.101=Die Konfigurationsdatei konnte nicht geladen werden
+ *                        
+ *                        #PDFDocumentException
+ *                        error.code.200=Das Dokument konnte nicht geladen werden
+ *                        
+ *                        #SignatureException
+ *                        error.code.300=Die Signatur ist ungültig
+ *                        
+ *                        #NormalizeException
+ *                        error.code.400=Die angegebene Version ist nicht bekannt
+ *                       
+ *                        normalizer.version=V01
+ *                
+ *               
+ *              
+ *             
+ *            
+ *           
+ *          
+ *         
+ *        
+ *       
+ *      
+ * 
+ * + * The internal representation of the example above is: + * + *
+ *     
+ *      
+ *       
+ *        
+ *         
+ *          
+ *           
+ *            
+ *             
+ *              
+ *               
+ *                        .error|
+ *                              |.code|
+ *                              |     |.200=Das Dokument konnte nicht geladen werden
+ *                              |     |.100=Interner Fehler
+ *                              |     |.400=Die angegebene Version ist nicht bekannt
+ *                              |     |.101=Die Konfigurationsdatei konnte nicht geladen werden
+ *                              |     |.300=Die Signatur ist ungültig
+ *                       .normalizer|
+ *                                  |.version=V01
+ *                
+ *               
+ *              
+ *             
+ *            
+ *           
+ *          
+ *         
+ *        
+ *       
+ *      
+ * 
+ * + * @author wlackner + */ +public class SettingsReader implements Settings, Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -8754114172766023454L; + + /** + * The system File separator char + */ + private static final String FILE_SEP = System.getProperty("file.separator"); + + // /** + // * The system temp file path + // */ + // private static final String TEMP_FILE_PATH = + // System.getProperty("java.io.tmpdir"); + + /** + * The current user path + */ + private static final String USER_DIR = System.getProperty("user.dir"); + +// /** +// * The home path of the tomcat webaplication +// */ +// private static final String CATALINA_HOME = System.getProperty("catalina.home"); + +// /** +// * The default application name used in templates, settings, jsp's etc. +// */ +// private static final String APPL_NAME = "pdf-as"; + + // private static final String APPL_NAME = "egiz"; + /** + * The config file path postfix + */ + private static final String CFG = "cfg"; + + /** + * The file path postfix where certificates are stored + */ + private static final String CERT = "certificates"; + +// /** +// * The web application path +// */ +// private static final String WEB_APPL_DIR = "webapps" + FILE_SEP + APPL_NAME + FILE_SEP; + + /** + * The path of the resources repository. + * + *

+ * This usually contains sub directories for the templates, the configuration + * files, etc. + *

+ */ + public static String RESOURCES_PATH = null; + + /** + * The path of the configuration directory. + */ + public static String CONFIG_PATH = null; + + /** + * The path of the certificated directory. + */ + public static String CERT_PATH = null; + + /** + * The name of the directory, where temporary files are stored. + */ + protected static String TEMP_DIR_NAME = "pdfastmp"; + + // /** + // * The application config path for the command line tool + // */ + // public static final String APPL_CONFIG_PATH = USER_DIR + FILE_SEP + CFG + + // FILE_SEP; + // + // /** + // * The application config path for the web application + // */ + // public static final String WEB_CONFIG_PATH = CATALINA_HOME + FILE_SEP + + // WEB_APPL_DIR + CFG + FILE_SEP; + // + // /** + // * The certificates path for the command line tool + // */ + // public static final String APPL_CERT_PATH = USER_DIR + FILE_SEP + CERT + + // FILE_SEP; + // + // /** + // * The certificates path for the cweb application + // */ + // public static final String WEB_CERT_PATH = CATALINA_HOME + FILE_SEP + + // WEB_APPL_DIR + CERT + FILE_SEP; + + /** + * The name of the default configuration file. The definition syntax is the + * java property config syntax. + */ + public static final String CONFIG_FILE_DEFAULT_NAME = "config.properties"; + + /** + * The name of the help text configuration file. The definition syntax is the + * java property config syntax. + */ + public static final String HELP_TEXT_FILE_DEFAULT_NAME = "help_text.properties"; + + /** + * The java properties from the settings file. + */ + private Properties properties_ = null; + + /** + * The settings reader instance. Used to make the class singleton. + */ + private static SettingsReader instance_ = null; + + /** + * The reference to the settings file. + */ + private static String settingsFile_ = null; + + /** + * The reference to the property representation of the settings file. + */ + private PropertyTree pTree_ = new PropertyTree(); + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SettingsReader.class); + + /** + * Make this constructor private. Use the method + * {@link SettingsReader#getInstance()}to get an instance from this class. + * The only cause to do this is that the definition file should only be read + * once while getting often this instance. The method throws an IOException if + * the settings file could not be read. + * + * @param settingsFile + * load this file, if the settingsFile == null the + * default settings ({@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}) + * file is used + * @throws SettingsException + * if the settings file could not be read + */ + private SettingsReader(String settingsFile) throws SettingsException + { + try + { + String cfg_path = CONFIG_PATH; + properties_ = new Properties(); + if (settingsFile == null) + { + settingsFile = cfg_path + CONFIG_FILE_DEFAULT_NAME; + } + settingsFile_ = settingsFile; + if (logger_.isInfoEnabled()) + { + File file = new File(settingsFile_); + logger_.info("load Settings:" + file.getAbsolutePath()); + // Properties sys_prop = System.getProperties(); + // Enumeration prop_keys = sys_prop.propertyNames(); + // while (prop_keys.hasMoreElements()) { + // String key = (String) prop_keys.nextElement(); + // String value = sys_prop.getProperty(key); + // logger_.info(key + "=" + value); + // } + } + FileInputStream sfs = new FileInputStream(settingsFile_); + properties_.load(sfs); + + Properties help_prop = new Properties(); + FileInputStream hfs = new FileInputStream(cfg_path + HELP_TEXT_FILE_DEFAULT_NAME); + help_prop.load(hfs); + + // load properties from current package! + // properties_.load(getClass().getResourceAsStream(settingsFile_)); + Enumeration prop_keys = properties_.propertyNames(); + while (prop_keys.hasMoreElements()) + { + String key = (String) prop_keys.nextElement(); + String value = properties_.getProperty(key); + pTree_.setKeyValue(key, value); + } + prop_keys = help_prop.propertyNames(); + while (prop_keys.hasMoreElements()) + { + String key = (String) prop_keys.nextElement(); + String value = help_prop.getProperty(key); + properties_.setProperty(key, value); + pTree_.setKeyValue(key, value); + } + } + catch (IOException e) + { + throw new SettingsException(e); + } + } + + /** + * This method returns an synchronized instance of this class. The settings + * file is read only once using this class. This method returns the instance + * holding the definitions of the default settings file. Default file: + * {@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}: "settings.txt" + * + * @return an instance of the SettingsReader + * @throws SettingsException + * if the default settings file could not be read + */ + public synchronized static SettingsReader getInstance() throws SettingsException + { + return getInstance(null); + } + + /** + * This method returns an synchronized instance of this class. The settings + * file is read only once using this class. This method returns the instance + * holding the definitions of the settingsFile. If the input param + * settingsFile == null the default settings file will be load. + * Default file: {@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}: + * "settings.txt" + * + * If an instance of this class exist, the input param is ignored! The + * SettingsReader is singleton and therefore the first + * {@link SettingsReader#getInstance()}defines the settings file that has to + * be loaded. This means changes between a application lifecyle can not be + * done! + * + * @param settingsFile + * the settings file that should be load. + * @return an instance of the SettingsReader + * @throws SettingsException + * if the settings file could not be read + */ + private synchronized static SettingsReader getInstance(String settingsFile) throws SettingsException + { + if (instance_ == null) + { + instance_ = new SettingsReader(settingsFile); + } + return instance_; + } + + /** + * This method returns a property value to the corresponding key. If the key + * is not found in the property file a SettingNotFoundException is thrown. + * + * @param key + * get the value for that key in the property file + * @return the value of the property key. + * @throws SettingNotFoundException + * ErrorCode: 100 + */ + public String getSetting(String key) throws SettingNotFoundException + { + String result = properties_.getProperty(key); + if (result == null) + { + String log_message = "Configuration key not found: '" + key + "'! Check '" + settingsFile_ + "' file."; + if (logger_.isEnabledFor(Level.WARN)) + { + logger_.warn(log_message); + } + SettingNotFoundException snf = new SettingNotFoundException(100, log_message); + throw snf; + } +// if (logger_.isDebugEnabled()) +// { +// logger_.debug("Get Property:" + key + "=" + result); +// } + return result; + } + + /** + * Relocates the relative file. + * + * @param file + * The relative file. + * @return Returns the usable file. + */ + public static String relocateFile(String file) + { + // if (isWeb()) + // { + // return CATALINA_HOME + FILE_SEP + WEB_APPL_DIR + file; + // } + // + // return file; + return RESOURCES_PATH + file; + } + + /** + * This method returns a property value to the corresponding key. If the key + * is not found in the property file the input param defaultValue is returned. + * + * @param key + * get the value for that key in the property file + * @param defaultValue + * the default value if the key is not found + * @return the value of the property key + */ + public String getSetting(String key, String defaultValue) + { + + String result = properties_.getProperty(key); + if (result == null) + { + result = defaultValue; + } +// if (logger_.isDebugEnabled()) +// { +// logger_.debug("Get Property:" + key + "=" + result); +// } + return result; + } + + /** + * This method returns a property value to the corresponding key. If the key + * is not found in the property file the input param defaultKey is searched. + * If the default key is not found the input param defaultValue is returned. + * + * @param primaryKey + * get the value for that key in the property file + * @param defaultKey + * the default key that should be searched if the primaryKey is not + * found + * @param defaultValue + * the default value if the defaultKey is not found + * @return the value of the property key + */ + public String getSetting(String primaryKey, String defaultKey, + String defaultValue) + { + String key = primaryKey; + String result = properties_.getProperty(key); + if (result == null) + { + key = defaultKey; + result = properties_.getProperty(key); + if (result == null) + { + result = defaultValue; + } + } +// if (logger_.isDebugEnabled()) +// { +// logger_.debug("Get Property:" + key + "=" + result); +// } + return result; + } + + /** + * This method returns an array of keys in the same hierarchy of the + * keyPrefix. The method search all keys in the property file that has the + * keyPrefix as leading substring. The Object[] collects all + * sub keys without the keyPrefix. + * + * @param keyPrefix + * to search for sub keys + * @return alls keys starting with the keyPrefix + */ + public Vector getSettingKeys(String keyPrefix) + { + Vector keys = new Vector(); + Enumeration names = properties_.propertyNames(); + while (names.hasMoreElements()) + { + String full_name = (String) names.nextElement(); + if (full_name.indexOf(keyPrefix) == 0) + { + keys.add(full_name.substring(keyPrefix.length() + 1)); + } + } + return keys; + } + + /** + * If a property value is number (interger) this method extracts the value and + * convert it to an int. If the key ist not found or the conversion fails, the + * defaultValue is returned. + * + * @param key + * get the value for that key in the property file + * @param defaultValue + * the default value if the key is not found + * @return the int value of the property key + */ + public int getIntSetting(String key, int defaultValue) + { + int int_property = defaultValue; + String value = null; + try + { + value = getSetting(key); + int_property = Integer.parseInt(value); + } + catch (NumberFormatException e) + { + if (logger_.isEnabledFor(Level.WARN)) + { + logger_.warn("Can not convert " + value + " to int."); + } + } + catch (SettingNotFoundException e) + { + if (logger_.isEnabledFor(Level.WARN)) + { + logger_.warn("Setting " + key + " not found, return default value:" + defaultValue); + } + } + return int_property; + } + + /** + * This method returns an array of sub keys (children references) of the key. + * The method is a wrapper calling the method + * {@link PropertyTree#getKeys(String key)}. + * + * @param key + * get all sub keys for that key in the property file + * @return an list of sub keys (type String) + * @see PropertyTree + */ + public ArrayList getKeys(String key) + { + return pTree_.getKeys(key); + } + + /** + * This method returns a the first value from a key. This means the method + * search in the PropertyTree representation of the config file. The + * PropertyTree class can overload key value paires. But the config file can + * not overload keys. If a key is defined more than one times the last + * definition is stored it the property list. The method is a wrapper calling + * the method {@link PropertyTree#getFirstValue(String key)}. + * + * @param key + * get the value for that key in the property file + * @return the value of the property key + * @see PropertyTree + */ + public String getValueFromKey(String key) + { + String value = pTree_.getFirstValue(key); +// if (logger_.isDebugEnabled()) +// { +// logger_.debug("getValueFromKey:" + key + "=" + value); +// } + return value; + } + + /** + * This method returns the PropertyTree representation of the configuration + * file. + * + * @return Returns the pTree. + * @see PropertyTree + */ + public PropertyTree getPTree() + { + return pTree_; + } + + // /** + // * This method checks the application context. + // * + // * @return true if the application is running in a webinterface, false + // * otherwise + // */ + // public static boolean isWeb() + // { + // return CATALINA_HOME != null; + // } + + /** + * Assembles the File of the temporary directory without checking if it really + * exists. + */ + protected static File assembleTemporaryDirectoryFile() + { + File temp_dir = new File(RESOURCES_PATH + TEMP_DIR_NAME); + return temp_dir; + } + + /** + * Returns the directory where temporary files should be stored. + * + *

+ * If the directory doesn't exist, it is created. + *

+ * + * @return Returns the directory where temporary files should be stored. + */ + public static File getTemporaryDirectory() + { + File temp_dir = assembleTemporaryDirectoryFile(); + if (!temp_dir.exists()) + { + temp_dir.mkdirs(); + } + return temp_dir; + } + + /** + * Deletes all files in the temporary directory, if it exists. + * + *

+ * This should be used to clear temporary files when the application shuts + * down. + *

+ */ + public static void clearTemporaryDirectory() + { + File temp_dir = assembleTemporaryDirectoryFile(); + logger_.info("Clearing temporary directory: " + temp_dir); + + if (!temp_dir.exists()) + { + return; + } + + File[] files = temp_dir.listFiles(); + for (int i = 0; i < files.length; i++) + { + logger_.info(" Clearing temporary file: " + files[i]); + boolean delete_success = files[i].delete(); + if (!delete_success) + { + logger_.error("Couldn't delete the temporary file: " + files[i]); + } + } + } + + /** + * Initializes the paths of the SettingsReader for web application usage. + * + * @param base_dir The base directory of this web application. E.g. TOMCAT_HOME/webapps/pdf-as + */ + public static void initializeForWeb(String base_dir) + { + RESOURCES_PATH = base_dir + FILE_SEP; //CATALINA_HOME + FILE_SEP + WEB_APPL_DIR; + CONFIG_PATH = RESOURCES_PATH + CFG + FILE_SEP; + CERT_PATH = RESOURCES_PATH + CERT + FILE_SEP; + } + + /** + * Initializes the paths of the SettingsReader for commanline usage. + */ + public static void initializeForCommandLine() + { + RESOURCES_PATH = USER_DIR + FILE_SEP; + CONFIG_PATH = RESOURCES_PATH + CFG + FILE_SEP; + CERT_PATH = RESOURCES_PATH + CERT + FILE_SEP; + } + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java b/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java new file mode 100644 index 0000000..7f5242b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java @@ -0,0 +1,917 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: Main.java,v 1.5 2006/10/31 08:06:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.commandline; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; + +import at.knowcenter.wag.egov.egiz.PdfAS; +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.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.ErrorCodeException; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PlaceholderException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.framework.SignResult; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.framework.VerificationFilter; +import at.knowcenter.wag.egov.egiz.framework.signators.DetachedSignator_1_0_0; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.web.Verify; + +/** + * The main program entry point of the commandline tool. + * + * @author wprinz + */ +public abstract class Main +{ + /** + * Command line parameter setting the application mode sign|verify + */ + protected static final String PARAMETER_MODE = "-mode"; + + /** + * Command line parameter setting the application to connect + */ + protected static final String PARAMETER_CONNECTOR = "-connector"; + + /** + * Command line parameter setting the signature mode. + */ + protected static final String PARAMETER_SIGNATURE_MODE = "-sigmode"; + + /** + * Command line parameter setting the signature type. + */ + protected static final String PARAMETER_SIGNATURE_TYPE = "-sigtype"; + + /** + * Command line parameter setting the username + */ + protected static final String PARAMETER_USER_NAME = "-username"; + + /** + * Command line parameter setting the users password + */ + protected static final String PARAMETER_USER_PASSWORD = "-password"; + + /** + * Command line parameter selecting the position of the signature. + */ + protected static final String PARAMETER_POS = "-pos"; + + /** + * Command line parameter selecting the signature which is going to be + * verified. + */ + protected static final String PARAMETER_VERIFY_WHICH = "-verify_which"; + + /** + * The application mode sign + */ + public static final String VALUE_MODE_SIGN = "sign"; + + /** + * The application mode verify + */ + public static final String VALUE_MODE_VERIFY = "verify"; + + /** + * The application mode sign + */ + public static final String VALUE_SIGNATURE_MODE_BINARY = "binary"; + + /** + * The application mode verify + */ + public static final String VALUE_SIGNATURE_MODE_TEXTUAL = "textual"; + + /** + * The application mode verify + */ + public static final String VALUE_SIGNATURE_MODE_DETACHED = "detached"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(Main.class); + + /** + * Main program entry point. + * + * @param args + * The commandline arguments. + * @throws IOException + */ + public static void main(String[] args) throws IOException + { + // ConfigLogger.setLevel(Level.DEBUG); + + SettingsReader.initializeForCommandLine(); + PropertyConfigurator.configure(SettingsReader.CONFIG_PATH + "log4j.properties"); + + try + { + // printUsage(System.out); + + String mode = null; + String signature_mode = null; + String connector = null; + + String signature_type = null; + String user_name = null; + String user_password = null; + String pos_string = null; + + int verify_which = -1; + + String input = null; + String output = null; + + // for (int i = 0; i < args.length; i++) + // { + // logger_.debug("arg[" + i + "] = " + args[i]); + // } + + for (int i = 0; i < args.length; i++) + { + String cur_arg = args[i].trim(); + + if (cur_arg.equals(PARAMETER_MODE)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_MODE); + return; + } + mode = args[i]; + if (!checkMode(mode)) + { + printUnrecognizedValue(PARAMETER_MODE, mode); + return; + } + continue; + } + + if (cur_arg.equals(PARAMETER_CONNECTOR)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_CONNECTOR); + return; + } + connector = args[i]; + if (!checkConnector(connector)) + { + printUnrecognizedValue(PARAMETER_CONNECTOR, connector); + return; + } + continue; + } + + if (cur_arg.equals(PARAMETER_SIGNATURE_MODE)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_SIGNATURE_MODE); + return; + } + signature_mode = args[i]; + if (!checkSignatureMode(signature_mode)) + { + printUnrecognizedValue(PARAMETER_SIGNATURE_MODE, signature_mode); + return; + } + continue; + } + + if (cur_arg.equals(PARAMETER_SIGNATURE_TYPE)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_SIGNATURE_TYPE); + return; + } + signature_type = args[i]; + if (!checkSignatureType(signature_type)) + { + printUnrecognizedValue(PARAMETER_SIGNATURE_TYPE, signature_type); + return; + } + continue; + } + + if (cur_arg.equals(PARAMETER_USER_NAME)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_USER_NAME); + return; + } + user_name = args[i]; + continue; + } + + if (cur_arg.equals(PARAMETER_USER_PASSWORD)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_USER_PASSWORD); + return; + } + user_password = args[i]; + continue; + } + + if (cur_arg.equals(PARAMETER_POS)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_POS); + return; + } + pos_string = args[i]; + continue; + } + + if (cur_arg.equals(PARAMETER_VERIFY_WHICH)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_VERIFY_WHICH); + return; + } + String str_verify_which = args[i]; + try + { + verify_which = Integer.parseInt(str_verify_which); + } + catch (NumberFormatException e) + { + printUnrecognizedValue(PARAMETER_VERIFY_WHICH, str_verify_which); + return; + } + + continue; + } + + if (cur_arg.charAt(0) == '-') + { + printUnrecognizedOption(cur_arg); + return; + } + + if (input == null) + { + input = cur_arg; + continue; + } + + if (output == null) + { + output = cur_arg; + continue; + } + + printUnrecognizedAdditionalCommandlineArgument(cur_arg); + return; + } + + if (mode == null) + { + printMissingParameter("a mode", PARAMETER_MODE); + return; + } + if (connector == null) + { + printMissingParameter("a connector", PARAMETER_CONNECTOR); + return; + } + if (mode.equals(VALUE_MODE_SIGN)) + { + if (signature_mode == null) + { + printMissingParameter("a signature mode", PARAMETER_SIGNATURE_MODE); + return; + } + if (signature_type == null) + { + SettingsReader settings = SettingsReader.getInstance(); + String default_type = settings.getValueFromKey(SignatureTypes.DEFAULT_TYPE); + signature_type = default_type; + } + if (user_name == null) + { + user_name = ""; + // printMissingParameter("a user name", PARAMETER_USER_NAME); + // return; + } + if (user_password == null) + { + user_password = ""; + // printMissingParameter("a user password", PARAMETER_USER_PASSWORD); + // return; + } + } + + if (input == null) + { + printMissing("an input document"); + return; + } + + File file = new File(input); + if (!file.exists()) + { + System.err.println("The input file '" + input + "' doesn't exist."); + return; + } + + carryOutCommand(mode, signature_mode, connector, signature_type, user_name, user_password, verify_which, input, output, pos_string); + + } + catch (PresentableException e) + { + if (e instanceof ErrorCodeException) + { + ErrorCodeException ece = (ErrorCodeException) e; + printErrorCodeException(ece); + } + else + { + System.err.println("PresentableException:"); + System.err.println(e.getMessage()); + logger_.debug(e.toString()); + } + } + finally + { + SettingsReader.clearTemporaryDirectory(); + } + } + + /** + * Carries out the actual command given via the commandline parameters. + * + *

+ * This is simply the procedure that is executed after the commandline + * parameters have been parsed successfully. + *

+ * + * @param mode + * The operation mode (e.g. "sign", "verify"). + * @param signature_mode + * The signature mode (e.g. "binary", "textual"). + * @param connector + * The connector (e.g. "bku", "a1"). + * @param signature_type + * The signature type/profile. For signing only. + * @param user_name + * The user name. For signing only. + * @param user_password + * The user password. For signing only. + * @param verify_which + * The number of the signature to be verified. For verifying only. + * @param input + * The input file name. + * @param output + * The output file name. + * @throws PresentableException + */ + protected static void carryOutCommand(final String mode, + final String signature_mode, final String connector, + final String signature_type, final String user_name, + final String user_password, final int verify_which, final String input, + String output, final String pos_string) throws PresentableException + { + File file = new File(input); + + byte[] input_bytes = null; + try + { + FileInputStream fis = new FileInputStream(file); + input_bytes = new byte[(int) file.length()]; + fis.read(input_bytes); + fis.close(); + } + catch (IOException e) + { + throw new PDFDocumentException(201); + } + + if (mode.equals(VALUE_MODE_SIGN)) + { + System.out.println("Signing..."); + + PdfAS.applyStrictMode(input_bytes); + + TablePos pos = null; + if (pos_string != null) + { + try + { + pos = PdfAS.parsePositionFromPosString(pos_string); + } + catch (PDFDocumentException e) + { + printUnrecognizedValue(PARAMETER_POS, pos_string); + return; + + } + } + + PdfASID algorithm = translateSignatureModeToPdfASID(signature_mode); + SignResult sign_result = PdfAS.sign(algorithm, input_bytes, signature_type, connector, user_name, user_password, pos); + + try + { + if (output == null) + { + output = generateOutputFileNameFromInput(input, sign_result); + } + + FileOutputStream fos = new FileOutputStream(output); + fos.write(sign_result.getData()); + fos.close(); + } + catch (IOException e) + { + throw new PDFDocumentException(205); + } + + System.out.println("Signing was successful."); + } + else + { + System.out.println("Verifying..."); + + VerificationFilter vf = new VerificationFilter(); + + List signature_holders = null; + + String extension = Verify.extractExtension(input); + if (extension != null && extension.equals("txt")) + { + try + { + String text = new String(input_bytes, "UTF-8"); + signature_holders = vf.extractSignaturesFromPlainText(text); + } + catch (UnsupportedEncodingException e) + { + throw new PresentableException(e); + } + } + else + { + signature_holders = vf.extractSignaturesFromPdf(input_bytes); + } + + if (signature_holders.isEmpty()) + { + throw new PDFDocumentException(206); + } + + List holders_to_verify = signature_holders; + + if (verify_which >= 0) + { + if (verify_which >= signature_holders.size()) + { + throw new SignatureException(312, "The selected signature to be verified doesn't exist."); + } + + SignatureHolder holder = (SignatureHolder) signature_holders.get(verify_which); + holders_to_verify = new ArrayList(); + holders_to_verify.add(holder); + } + + List results = PdfAS.verifySignatureHolders(holders_to_verify, connector); + System.out.println("Verification results:"); + formatVerifyResults(results, System.out); + } + } + + /** + * Generates a suitable output file name for the output regarding the type of + * the sign_result. + * + * @param input + * The input file name. + * @param sign_result + * The sign result. + * @return Returns the output file name. + */ + protected static String generateOutputFileNameFromInput(String input, + SignResult sign_result) + { + String output = input + "_out"; + if (sign_result.getMimeType().equals(DetachedSignator_1_0_0.MIME_TYPE)) + { + output += ".xml"; + } + else + { + output += ".pdf"; + } + + return output; + } + + /** + * Prints that the provided option was unrecognized. + * + * @param option + * The unrecognized option. + * @throws PresentableException + * Forwarded exception. + */ + protected static void printUnrecognizedOption(final String option) throws PresentableException + { + System.err.println("Unrecognized option '" + option + "'."); + printUsage(System.out); + } + + /** + * Prints that the provided value was unrecognized. + * + * @param parameter + * The parameter, which is missing a value. + * @throws PresentableException + * Forwarded exception. + */ + protected static void printNoValue(final String parameter) throws PresentableException + { + System.err.println("The parameter " + parameter + " requires a value as next argument."); + printUsage(System.out); + } + + /** + * Prints that the provided value was unrecognized. + * + * @param value + * The unrecognized value. + * @throws PresentableException + * Forwarded exception. + */ + protected static void printUnrecognizedValue(final String parameter, + final String value) throws PresentableException + { + System.err.println("The parameter " + parameter + " doesn't recognize the provided value '" + value + "'."); + printUsage(System.out); + } + + /** + * Prints that the provided additional commandline argument was unrecognized. + * + * @param argument + * The unrecognized argument. + * @throws PresentableException + * Forwarded exception. + */ + protected static void printUnrecognizedAdditionalCommandlineArgument( + final String argument) throws PresentableException + { + System.err.println("Unrecognized additional commandline argument '" + argument + "'."); + printUsage(System.out); + } + + /** + * Prints that a certain parameter was missing. + * + * @param missing_term + * A description of the missing parameter ("e.g. a mode"). + * @param parameter + * The missing parameter itself (e.g. "-mode"). + * @throws PresentableException + * Forwarded exception. + */ + protected static void printMissingParameter(final String missing_term, + final String parameter) throws PresentableException + { + printMissing(missing_term + " ('" + parameter + "' parameter)"); + } + + /** + * Prints that something is missing. + * + * @param missing_term + * A descriptive message of the missing thing. + * @throws PresentableException + * Forwarded exception. + */ + protected static void printMissing(final String missing_term) throws PresentableException + { + System.err.println("Please specify " + missing_term + "."); + printUsage(System.out); + } + + /** + * Prints out the ErrorCodeException in a descriptive form. + * + * @param ece + * The ErrorCodeException to be printed. + */ + protected static void printErrorCodeException(final ErrorCodeException ece) + { + if (ece instanceof PlaceholderException) + { + PlaceholderException phe = (PlaceholderException) ece; + + System.err.println("Der Platzhalter des Feldes " + phe.getField() + " ist um " + phe.getMissing() + " Bytes zu kurz. "); + } + + System.err.println("Fehler " + ece.getErrorCode() + ": " + ece.getErrorCodeMessage()); + + if (ece.hasExternalErrorMessage()) + { + System.err.println("Externer Fehlergrund: " + ece.getExternalErrorCode() + ": " + ece.getExternalErrorMessage()); + } + + logger_.debug(ece.toString()); + } + + /** + * Prints the usage text. + * + * @param writer + * The writer to print the text to. + * @throws PresentableException + * Forwarded exception. + */ + public static void printUsage(PrintStream writer) throws PresentableException + { + writer.println("Usage: pdf-as [OPTIONS] [output file]"); + writer.println(" Required OPTIONS:"); + + writer.println(" " + PARAMETER_MODE + " <" + VALUE_MODE_SIGN + "|" + VALUE_MODE_VERIFY + ">"); + writer.println(" " + VALUE_MODE_SIGN + " ... signs a document"); + writer.println(" " + VALUE_MODE_VERIFY + " ... verifies a document"); + + writer.print(" " + PARAMETER_CONNECTOR + " "); + ConnectorInformation[] ci = ConnectorFactory.getConnectorInformationArray(); + for (int i = 0; i < ci.length; i++) + { + String id = ci[i].getIdentifier(); + if (!ConnectorFactory.isAvailableForCommandline(id)) + { + continue; + } + writer.print(id); + if (i < ci.length - 1) + { + writer.print("|"); + } + } + writer.println(); + for (int i = 0; i < ci.length; i++) + { + String id = ci[i].getIdentifier(); + if (!ConnectorFactory.isAvailableForCommandline(id)) + { + continue; + } + writer.println(" " + id + " ... " + ci[i].getDescription()); + } + + writer.println(" OPTIONS for signation:"); + + writer.println(" " + PARAMETER_SIGNATURE_MODE + " <" + VALUE_SIGNATURE_MODE_BINARY + "|" + VALUE_SIGNATURE_MODE_TEXTUAL + ">"); + writer.println(" " + VALUE_SIGNATURE_MODE_BINARY + " ... signs the complete binary document"); + writer.println(" " + VALUE_SIGNATURE_MODE_TEXTUAL + " ... signs only the textual portion of the document"); + writer.println(" " + VALUE_SIGNATURE_MODE_DETACHED + " ... signs the document and returns the xml signature of it."); + + writer.print(" " + PARAMETER_SIGNATURE_TYPE + " <"); + SignatureTypes sig_types = SignatureTypes.getInstance(); + SettingsReader settings = SettingsReader.getInstance(); + List types_array = sig_types.getSignatureTypes(); + Iterator it = types_array.iterator(); + while (it.hasNext()) + { + String type = (String) it.next(); + writer.print(type); + if (it.hasNext()) + { + writer.print("|"); + } + } + writer.println(">"); + writer.println(" ... [optional] the profile to be used. If omitted, the default"); + writer.println(" profile is used."); + String default_type = settings.getValueFromKey(SignatureTypes.DEFAULT_TYPE); + it = types_array.iterator(); + while (it.hasNext()) + { + String type = (String) it.next(); + String descr_key = SignatureTypes.SIG_OBJ + type + "." + SignatureTypes.SIG_DESCR; + String type_descr = settings.getValueFromKey(descr_key); + + writer.println(" " + type + " ... " + (type.equals(default_type) ? "(default) " : "") + type_descr); + } + + writer.println(" " + PARAMETER_USER_NAME + " ... the user name"); + writer.println(" " + PARAMETER_USER_PASSWORD + " ... the user password"); + + writer.println(" " + PARAMETER_POS + " ... [optional] the absolute position of the signature block"); + writer.println(" position has the format ;;;"); + writer.println(" ... e.g. -pos=1;20.0;400.0;500.0"); + + writer.println(" OPTIONS for verification:"); + writer.println(" " + PARAMETER_VERIFY_WHICH + " ... [optional] zero based number of the signature"); + writer.println(" to be verified. If omitted, all signatures are verified."); + + writer.println(" Example usage:"); + writer.println(" pdf-as " + PARAMETER_MODE + " " + VALUE_MODE_SIGN + " " + PARAMETER_CONNECTOR + " moa " + PARAMETER_USER_NAME + " name " + PARAMETER_USER_PASSWORD + " pwd some_document.pdf"); + writer.println(" pdf-as " + PARAMETER_MODE + " " + VALUE_MODE_VERIFY + " some_document.pdf_out.pdf"); + + } + + /** + * Checks the value for correctness. + * + * @param mode + * The parameter's value. + * @return Returns true, if the value is correct, false otherwise. + */ + protected static boolean checkMode(String mode) + { + return mode.equals(VALUE_MODE_SIGN) || mode.equals(VALUE_MODE_VERIFY); + } + + /** + * Checks the value for correctness. + * + * @param signature_mode + * The parameter's value. + * @return Returns true, if the value is correct, false otherwise. + */ + protected static boolean checkSignatureMode(String signature_mode) + { + return signature_mode.equals(VALUE_SIGNATURE_MODE_BINARY) || signature_mode.equals(VALUE_SIGNATURE_MODE_TEXTUAL) || signature_mode.equals(VALUE_SIGNATURE_MODE_DETACHED); + } + + /** + * Checks the value for correctness. + * + * @param connector + * The parameter's value. + * @return Returns true, if the value is correct, false otherwise. + * @throws ConnectorFactoryException + * F.e. + */ + protected static boolean checkConnector(String connector) throws ConnectorFactoryException + { + return ConnectorFactory.isValidConnectorIdentifier(connector) && ConnectorFactory.isAvailableForCommandline(connector); + } + + /** + * Checks the value for correctness. + * + * @param signature_type + * The parameter's value. + * @return Returns true, if the value is correct, false otherwise. + */ + protected static boolean checkSignatureType(String signature_type) throws SignatureTypesException + { + SignatureTypes sig_types = SignatureTypes.getInstance(); + List types_array = sig_types.getSignatureTypes(); + Iterator it = types_array.iterator(); + while (it.hasNext()) + { + String type = (String) it.next(); + if (type.equals(signature_type)) + { + return true; + } + } + return false; + } + + /** + * Translates the commandline argument to a PDF-AS-ID. + * + * @param signature_mode + * The signator mode commandline argument. + * @return Returns the corresponding PDFASID. + */ + protected static PdfASID translateSignatureModeToPdfASID(String signature_mode) + { + if (signature_mode.equals(VALUE_SIGNATURE_MODE_BINARY)) + { + return SignatorFactory.MOST_RECENT_BINARY_SIGNATOR_ID; + } + if (signature_mode.equals(VALUE_SIGNATURE_MODE_TEXTUAL)) + { + return SignatorFactory.MOST_RECENT_TEXTUAL_SIGNATOR_ID; + } + if (signature_mode.equals(VALUE_SIGNATURE_MODE_DETACHED)) + { + return SignatorFactory.MOST_RECENT_DETACHED_SIGNATOR_ID; + } + return null; + } + + /** + * Formats the verification results. + * + * @param results + * The List of SignatureResponse verification results. + * @param writer + * The output sink to write the formatted text to. + * @throws SettingNotFoundException + * Forwarded exception. + */ + protected static void formatVerifyResults(List results, PrintStream writer) throws SettingNotFoundException + { + Iterator it = results.iterator(); + while (it.hasNext()) + { + SignatureResponse result = (SignatureResponse) it.next(); + formatSignatureResponse(result, writer); + + if (it.hasNext()) + { + writer.println(); + } + } + } + + /** + * Formats the SignatureResponse. + * + * @param result + * The SignatureResponse to be printed. + * @param writer + * The output sink to write the formatted text to. + * @throws SettingNotFoundException + * Forwarded exception. + */ + public static void formatSignatureResponse(SignatureResponse result, + PrintStream writer) throws SettingNotFoundException + { + + writer.println(" Zertifikat:"); + writer.println(" Signator: " + result.getX509SubjectName()); + writer.println(" Aussteller: " + result.getX509IssuerName()); + writer.println(" Seriennummer: " + result.getX509SerialNumber()); + List public_properties = result.getPublicProperties(); + Iterator it = public_properties.iterator(); + while (it.hasNext()) + { + String public_property = (String) it.next(); + writer.println(" Eigenschaft: " + public_property); + } + + writer.println(" Zertifikat-Check:"); + writer.println(" " + result.getCertificateCheckCode() + " - " + result.getCertificateCheckInfo()); + writer.println(" Signatur-Check:"); + writer.println(" " + result.getSignatureCheckCode() + " - " + result.getSignatureCheckInfo()); + writer.println(" Manifest-Check:"); + writer.println(" " + result.getSignatureManifestCheckCode() + " - " + result.getSignatureManifestCheckInfo()); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorFactoryException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorFactoryException.java new file mode 100644 index 0000000..733ccb6 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorFactoryException.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ConnectorFactoryException.java,v 1.2 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * This exception is thrown when the connector factory encounters an error + * during providing a connector. + * + *

+ * The most likely case for this exception is that a wrong connector identifier + * was provided. + *

+ * + * @author wprinz + */ +public class ConnectorFactoryException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -1398538795243257880L; + + /** + * @param message + */ + public ConnectorFactoryException(String message) + { + super(message); + } + + /** + * @param message + * @param cause + */ + public ConnectorFactoryException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * @param cause + */ + public ConnectorFactoryException(Throwable cause) + { + super(cause); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ErrorCodeException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ErrorCodeException.java new file mode 100644 index 0000000..42fe597 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ErrorCodeException.java @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ErrorCodeException.java,v 1.1 2006/08/03 07:47:02 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; + +/** + * This exception should be inherit, if an exception should be shown as a + * feedback message in user interfaces. + * + *

+ * The error code is an integer number. The error codes are defined in an + * separate configuration file, readed be the SettingsReader. If the + * SettingsReader can not initialized, a corresponding error message can not + * read! + *

+ *

+ * The error code can be seen a a replacement of the exception message. For all + * intents and purposes, the error code should be used to provide exceptional + * feedback to the user. Nevertheless, if possible, a debug message String (the + * message parameter) should still be provided giving in depth developer + * descriptions of the problem. These message strings will then show up in the + * log files accordingly. + *

+ * + * @author wlackner + * @author wprinz (enforced error code) + * + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + */ +public class ErrorCodeException extends PresentableException +{ + /** + * SVUID. + */ + private static final long serialVersionUID = 2071967845179686593L; + + /** + * Template key getting error messages + */ + private static final String ERROR_CODE_KEY = "error.code."; + + /** + * The default error message + */ + private static final String DEFAULT_ERROR_MESSAGE = "Fehler Code:"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(ErrorCodeException.class); + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * The default error code + */ + private int error_code_ = -1; + + /** + * If an external application is called + */ + private String externalErrorCode_ = null; + + /** + * If an external application is called + */ + private String externalErrorMessage_ = null; + + /** + * Constructor that sets the error code. + * + * @param error_code + * The error code. + */ + public ErrorCodeException(final int error_code) + { + super("error code " + error_code); + this.error_code_ = error_code; + loadSettings(); + } + + /** + * Inherit Constructor from Exception, + * + * @param error_code + * The error code. + * @param message + * The in depth developer provided error message. + * @see Exception + */ + public ErrorCodeException(final int error_code, String message) + { + super("error code " + error_code + ": " + message); + this.error_code_ = error_code; + loadSettings(); + } + + /** + * Inherit Constructor from Exception, + * + * @param error_code + * The error code. + * @param message + * The in depth developer provided error message. + * @param cause + * The cause of this exception. + * @see Exception + */ + public ErrorCodeException(final int error_code, String message, Throwable cause) + { + super("error code " + error_code + ": " + message, cause); + this.error_code_ = error_code; + loadSettings(); + } + + /** + * Inherit Constructor from Exception, + * + * @param error_code + * The error code. + * @param cause + * The cause of this exception. + * @see Exception + */ + public ErrorCodeException(final int error_code, Throwable cause) + { + super("error code " + error_code, cause); + this.error_code_ = error_code; + loadSettings(); + } + + /** + * Load the settings file. Call the SettingsReader instance. + */ + private void loadSettings() + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load pdf signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + } + } + } + + /** + * Return the manually stored error code. The error code is only a key for a + * configurable error message. The error code and its corresponding message + * have to be declared in an separate property file, loaded by the + * SettingsReader + * + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + * @return Returns the errorCode. + */ + public int getErrorCode() + { + return this.error_code_; + } + + /** + * Set a special error code in case of commuicating this error in an user + * interface. The error code is only a key for a configurable error message. + * The error code and its corresponding message have to be declared in an + * separate property file, loaded by the SettingsReader + * + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + * @param error_code + * The error code to be set. + */ + public void setErrorCode(final int error_code) + { + this.error_code_ = error_code; + } + + /** + * Set a special error code in case of commuicating this error in an user + * interface. The error code is a key for an external application error + * message. The error code and its corresponding message have to be declared + * by the external tool that used. + * + * @param errorCode + * The errorCode to set. + */ + public void setExternalErrorCode(String errorCode) + { + externalErrorCode_ = errorCode; + } + + /** + * Returns an external error code that is set manually + * + * @return the external error code if set, null otherwise + */ + public String getExternalErrorCode() + { + return externalErrorCode_; + } + + /** + * Set a special error message in case of commuicating this error in an user + * interface. The error message and its corresponding error code have to be + * declared by the external tool that used. + * + * @param errorMessage + */ + public void setExternalErrorMessage(String errorMessage) + { + externalErrorMessage_ = errorMessage; + } + + /** + * Returns an external error message that is set manually + * + * @return the external error message if set, null otherwise + */ + public String getExternalErrorMessage() + { + return externalErrorMessage_; + } + + /** + * Checks if an external error message is set. + * + * @return returns true if a message is set, false + * otherwise + */ + public boolean hasExternalErrorMessage() + { + return (externalErrorMessage_ != null); + } + + /** + * Get the configured error message that corresponds to the error code. If the + * config file can't be read, or an error code is not declared in the config + * file, the default error message would be returned. + * + * @return an error message that can be used for ui communication + */ + public String getErrorCodeMessage() + { + String err_msg = null; + if (settings_ != null) + { + err_msg = settings_.getSetting(ERROR_CODE_KEY + error_code_, DEFAULT_ERROR_MESSAGE + error_code_); + } + return err_msg; + } + + /** + * Get the configured error message that corresponds to the given error code. + * If the config file can't be read, or an error code is not declared in the + * config file, the default error message would be returned. + * + * @return an error message that can be used for ui communication + */ + public static String getErrorCodeMessage(int errorCode) + { + SettingsReader settings = null; + String err_msg = DEFAULT_ERROR_MESSAGE + errorCode; + try + { + settings = SettingsReader.getInstance(); + err_msg = settings.getSetting(ERROR_CODE_KEY + errorCode, DEFAULT_ERROR_MESSAGE + errorCode); + } + catch (SettingsException e) + { + e.printStackTrace(); + } + return err_msg; + } + + /** + * Checks if the exception has an ErrorCode state. + * + * @return true if an ErrorCode does exist false otherwise + */ + public boolean hasErrorCode() + { + return error_code_ != 0; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/InvalidIDException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/InvalidIDException.java new file mode 100644 index 0000000..33d189b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/InvalidIDException.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: InvalidIDException.java,v 1.1 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * Thrown when parsing an ID ("Kennzeichnung") fails. + * @author wprinz + */ +public class InvalidIDException extends SignatureException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7945398356854048254L; + + public InvalidIDException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + public InvalidIDException(int error_code, String message) + { + super(error_code, message); + } + + public InvalidIDException(int error_code, Throwable cause) + { + super(error_code, cause); + } + + public InvalidIDException(int error_code) + { + super(error_code); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/NormalizeException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/NormalizeException.java new file mode 100644 index 0000000..3675edb --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/NormalizeException.java @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: NormalizeException.java,v 1.1 2006/08/03 07:47:02 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + + +/** + * This exception is thrown by the processing a normalizer. + * + * @author wlackner + */ +public class NormalizeException extends ErrorCodeException { + + /** + * SVUID. + */ + private static final long serialVersionUID = -4080682145462891501L; + + /** + * @param error_code + * @param message + * @param cause + */ + public NormalizeException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + /** + * @param error_code + * @param message + */ + public NormalizeException(int error_code, String message) + { + super(error_code, message); + } + + /** + * @param error_code + * @param cause + */ + public NormalizeException(int error_code, Throwable cause) + { + super(error_code, cause); + } + + /** + * @param error_code + */ + public NormalizeException(int error_code) + { + super(error_code); + } + + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PDFDocumentException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PDFDocumentException.java new file mode 100644 index 0000000..a0cf56a --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PDFDocumentException.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PDFDocumentException.java,v 1.1 2006/08/03 07:47:02 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * This exception is thrown in case of problems using pdf librarys. + * + * @author wlackner + */ +public class PDFDocumentException extends ErrorCodeException +{ + + /** + * + */ + private static final long serialVersionUID = -4595955288382226408L; + + /** + * @param error_code + * @param message + * @param cause + */ + public PDFDocumentException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + /** + * @param error_code + * @param message + */ + public PDFDocumentException(int error_code, String message) + { + super(error_code, message); + } + + /** + * @param error_code + * @param cause + */ + public PDFDocumentException(int error_code, Throwable cause) + { + super(error_code, cause); + } + + /** + * @param error_code + */ + public PDFDocumentException(int error_code) + { + super(error_code); + } + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PlaceholderException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PlaceholderException.java new file mode 100644 index 0000000..1c82c3c --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PlaceholderException.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PlaceholderException.java,v 1.1 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * @author wprinz + */ +public class PlaceholderException extends PDFDocumentException +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -9149805408421810170L; + + + protected String field = null; + protected int missing = -1; + + public PlaceholderException(String field, int missing) + { + super(700, field + ":" + missing); + + this.field = field; + this.missing = missing; + } + + public void setField (String field) + { + this.field = field; + } + + public String getField() + { + return this.field; + } + + public int getMissing() + { + return this.missing; + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PresentableException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PresentableException.java new file mode 100644 index 0000000..ab87002 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PresentableException.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PresentableException.java,v 1.2 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * This exception should be the base for all exceptions that are to be presented + * to the user. + * + *

+ * For example, exceptions that signal that a pdf file is corrupt should be + * represented as presentable exceptions so that the user interface frontends + * can present according texts. + *

+ * + * @author wprinz + */ +public class PresentableException extends Exception +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -102406558526000792L; + + /** + * @param message + */ + public PresentableException(String message) + { + super(message); + } + + /** + * @param message + * @param cause + */ + public PresentableException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * @param cause + */ + public PresentableException(Throwable cause) + { + super(cause); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingNotFoundException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingNotFoundException.java new file mode 100644 index 0000000..02a3b5b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingNotFoundException.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SettingNotFoundException.java,v 1.1 2006/08/03 07:47:03 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * This exception is thrown by the SettingsReader if a property key is not + * found. + * + * @author wlackner + */ +public class SettingNotFoundException extends ErrorCodeException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7502191288775676006L; + + /** + * @param error_code + * @param message + * @param cause + */ + public SettingNotFoundException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + /** + * @param error_code + * @param message + */ + public SettingNotFoundException(int error_code, String message) + { + super(error_code, message); + } + + /** + * @param error_code + * @param cause + */ + public SettingNotFoundException(int error_code, Throwable cause) + { + super(error_code, cause); + } + + /** + * @param error_code + */ + public SettingNotFoundException(int error_code) + { + super(error_code); + } + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingsException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingsException.java new file mode 100644 index 0000000..c53e6f2 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingsException.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SettingsException.java,v 1.2 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * Thrown when the settings couldn't be loaded. + * + *

+ * This is most likely the case when the config file isn't found or when the + * settings are corrupt. + *

+ * + * @author wprinz + */ +public class SettingsException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -99979541706943372L; + + /** + * @param message + */ + public SettingsException(String message) + { + super(message); + } + + /** + * @param message + * @param cause + */ + public SettingsException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * @param cause + */ + public SettingsException(Throwable cause) + { + super(cause); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatorFactoryException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatorFactoryException.java new file mode 100644 index 0000000..dea7cfc --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatorFactoryException.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignatorFactoryException.java,v 1.1 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * Exception coming out of the SignatorFactory. + * @author wprinz + */ +public class SignatorFactoryException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -4051644056058970435L; + + public SignatorFactoryException(String message) + { + super(message); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureException.java new file mode 100644 index 0000000..f036f49 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureException.java @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: SignatureException.java,v 1.1 2006/08/03 07:47:03 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + + +/** + * This exception is thrown by the processing a signature. + * + * @author wlackner + */ +public class SignatureException extends ErrorCodeException { + + /** + * SVUID. + */ + private static final long serialVersionUID = 6387300820234118374L; + + /** + * @param error_code + * @param message + * @param cause + */ + public SignatureException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + /** + * @param error_code + * @param message + */ + public SignatureException(int error_code, String message) + { + super(error_code, message); + } + + /** + * @param error_code + * @param cause + */ + public SignatureException(int error_code, Throwable cause) + { + super(error_code, cause); + } + + /** + * @param error_code + */ + public SignatureException(int error_code) + { + super(error_code); + } + + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureTypesException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureTypesException.java new file mode 100644 index 0000000..4f51418 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureTypesException.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignatureTypesException.java,v 1.2 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * Exception for Signature Type problems. + * @author wprinz + */ +public class SignatureTypesException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7899273202684297943L; + + /** + * @param message + */ + public SignatureTypesException(String message) + { + super(message); + } + + /** + * @param message + * @param cause + */ + public SignatureTypesException(String message, Throwable cause) + { + super(message, cause); + } + + /** + * @param cause + */ + public SignatureTypesException(Throwable cause) + { + super(cause); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/WebException.java b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/WebException.java new file mode 100644 index 0000000..5f72211 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/WebException.java @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: WebException.java,v 1.2 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + + +/** + * Exception for web problems. + * @author wlackner + */ +public class WebException extends ErrorCodeException { + + /** + * SVUID. + */ + private static final long serialVersionUID = 4329890155872840492L; + + /** + * @param error_code + * @param message + * @param cause + */ + public WebException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + /** + * @param error_code + * @param message + */ + public WebException(int error_code, String message) + { + super(error_code, message); + } + + /** + * @param error_code + * @param cause + */ + public WebException(int error_code, Throwable cause) + { + super(error_code, cause); + } + + /** + * @param error_code + */ + public WebException(int error_code) + { + super(error_code); + } + + + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundBlock.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundBlock.java new file mode 100644 index 0000000..53afa10 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundBlock.java @@ -0,0 +1,198 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: FoundBlock.java,v 1.2 2006/10/31 08:07:29 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +import java.util.ArrayList; +import java.util.List; + +import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * Contains all the information about a found Block in text extracton. + * + *

+ * This is basically the ordered list of found captions. + *

+ * + * @author wprinz + */ +public class FoundBlock +{ + /** + * The ordered list of found keys. + */ + public List found_keys = null; + + /** + * The end index of the block. + */ + public int end_index = 0; + + /** + * The type of the block. + */ + public SignatureTypeDefinition std = null; + + /** + * Returns the first key of this block. + * + * @return Returns the first key of this block. + */ + public FoundKey getFirstKey() + { + return (FoundKey) this.found_keys.get(found_keys.size() - 1); + } + + /** + * Returns the last key of this block. + * + * @return Returns the last key of this block. + */ + public FoundKey getLastKey() + { + return (FoundKey) this.found_keys.get(0); + } + + /** + * Returns the size of this block. + * + *

+ * Note that this doesn't give the exact size of the block, but rather a value + * suirable for comparison. + *

+ * + * @return Returns the size of this block. + */ + public int getSize() + { + int size = getLastKey().start_index - getFirstKey().start_index; + return size; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "FoundBlock: std=" + this.std.getType() + ", #=" + this.found_keys.size() + ", size = " + getSize(); + } + + /** + * Tells, if this block is semantically equal to the other block. + * + * Two blocks are semantically equal, if all the required have the + * same captions in the same order. + * + * @param other_block + * The other block. + * @return Returns true, of this block is semantically equal to the other one, + * false otherwise. + */ + public boolean isSemanticallyEqual(FoundBlock other_block) + { + List this_keys = filterOutNonRequiredFoundKeys(this.found_keys); + List other_keys = filterOutNonRequiredFoundKeys(other_block.found_keys); + + if (this_keys.size() != other_keys.size()) + { + return false; + } + + for (int i = 0; i < this_keys.size(); i++) + { + FoundKey this_found_key = (FoundKey) this_keys.get(i); + FoundKey other_found_key = (FoundKey) other_keys.get(i); + + if (!this_found_key.isSemanticallyEqual(other_found_key)) + { + return false; + } + } + return true; + } + + /** + * Filters out all non required keys from the List of found keys. + * + * @param found_keys The List of found keys. + * + * @return Rturns the subset List which contains only the required keys. + */ + protected static List filterOutNonRequiredFoundKeys (List found_keys) + { + List required_found_keys = new ArrayList(found_keys.size()); + for (int i = 0; i < found_keys.size(); i++) + { + FoundKey this_found_key = (FoundKey) found_keys.get(i); + + if (!SignatureTypes.isRequiredKey(this_found_key.key)) + { + continue; + } + + required_found_keys.add(this_found_key); + } + return required_found_keys; + } + + /** + * Tells, if this block is strictly semantically equal to the other block. + * + * Two blocks are strictly semantically equal, if they contain the same keys with the + * same captions in the same order. + * + * @param other_block + * The other block. + * @return Returns true, of this block is semantically equal to the other one, + * false otherwise. + */ + public boolean isStrictlySemanticallyEqual(FoundBlock other_block) + { + if (this.found_keys.size() != other_block.found_keys.size()) + { + return false; + } + + for (int i = 0; i < this.found_keys.size(); i++) + { + FoundKey this_found_key = (FoundKey) this.found_keys.get(i); + FoundKey other_found_key = (FoundKey) other_block.found_keys.get(i); + + if (!this_found_key.isSemanticallyEqual(other_found_key)) + { + return false; + } + } + return true; + } + + + public FoundKey getDateFoundKey () + { + for (int i = 0; i < this.found_keys.size(); i++) + { + FoundKey found_key = (FoundKey) this.found_keys.get(i); + if (found_key.key.equals(SignatureTypes.SIG_DATE)) + { + return found_key; + } + } + throw new RuntimeException("There is no SIG_DATE in the list of found_keys. This must not happen."); + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundKey.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundKey.java new file mode 100644 index 0000000..67cc417 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundKey.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: FoundKey.java,v 1.1 2006/08/25 17:07:21 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +/** + * Holds the information of one found key. + * @author wprinz + */ +public class FoundKey +{ + /** + * The type of the key. + */ + public String key = null; + + /** + * The caption of the key. + */ + public String caption = null; + + /** + * The start index of the caption in the text. + */ + public int start_index = -1; + + /** + * + * @param key The type of the key. + * @param caption The caption of the key. + * @param start_index The start index of the caption in the text. + */ + public FoundKey(String key, String caption, int start_index) + { + this.key = key; + this.caption = caption; + this.start_index = start_index; + } + + /** + * Returns the key. + * @return Returns the key. + */ + public String getKey() + { + return this.key; + } + + /** + * Returns the start_index. + * @return Returns the start_index. + */ + public int getStartIndex() + { + return this.start_index; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return this.key + "(" + this.caption + ")@" + this.start_index; + } + + /** + * Tells, if this FoundKey is semantically equal to the other FoundKey. + * + *

+ * Two FoundKeys are semantically equal if their key and caption are the same. + *

+ * + * @param other_found_key + * The other FoundKey. + * @return Returns true if the two keys are semantically equal. + */ + public boolean isSemanticallyEqual(FoundKey other_found_key) + { + return this.key.equals(other_found_key.key) && this.caption.equals(other_found_key.caption); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignResult.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignResult.java new file mode 100644 index 0000000..c7dfcdb --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignResult.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignResult.java,v 1.1 2006/08/25 17:07:21 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +import java.io.Serializable; + +/** + * This class holds the signed document, which is given by the mime type and the + * binary data. + * + * @author wprinz + */ +public class SignResult implements Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -6664489317508509973L; + + /** + * The mime type of the data specifying the type of the document. + */ + protected String mime_type = null; + + /** + * The binary data of the document. + */ + protected byte[] data = null; + + /** + * Constructor. + * + * @param document_mime_type + * The mime type of the data specifying the type of the document. + * @param document_data + * The binary data of the document. + */ + public SignResult(String document_mime_type, byte[] document_data) + { + if (document_mime_type == null && document_mime_type.length() == 0) + { + throw new IllegalArgumentException("Please provide a valid Mime Type for the SignResult. " + document_mime_type); + } + if (document_data == null) + { + throw new IllegalArgumentException("Please provide document data. " + document_data); + } + + this.mime_type = document_mime_type; + this.data = document_data; + } + + /** + * Returns the binary data. + * + * @return Returns the binary data. + */ + public byte[] getData() + { + return this.data; + } + + /** + * Returns the mime type. + * + * @return Returns the mime type. + */ + public String getMimeType() + { + return this.mime_type; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "SignResult:" + this.mime_type + "," + this.data.length; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/Signator.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/Signator.java new file mode 100644 index 0000000..7719818 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/Signator.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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.knowcenter.wag.egov.egiz.framework; + +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; + +/** + * The basic interface for signator algorithms. + * + * @author wprinz + */ +public interface Signator +{ + /** + * This is called before the data is sent to the connector. + * + * @param pdf + * The PDF document to be signed. + * @param signature_type + * The type/profile of the signature to apply. + * @param pos + * The table position. If null, the position is read from the + * profile, if this is null too, the position is computed. + * @param has_SIG_ID + * Tells the algorithm, id a SIG_ID field will be required after + * signing. Algorithms with fixed formatted signature blocks need to + * know this. + * @return Returns the IncrementalUpdateInformation. + * @throws PresentableException + * Forwarded exception. + */ + public IncrementalUpdateInformation prepareSign(byte[] pdf, + String signature_type, TablePos pos, boolean has_SIG_ID) throws PresentableException; + + /** + * This is called after the data has been signed by the connector. + * + *

+ * Replaces all the left out placeholders with their values retrieved from the + * signation process. + *

+ * + * @param iui + * The IncrementalUpdateInformation. + * @throws PDFDocumentException + * Forwarded exception. + */ + public SignResult finishSign(IncrementalUpdateInformation iui) throws PresentableException; +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignatorFactory.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignatorFactory.java new file mode 100644 index 0000000..fbba7dc --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignatorFactory.java @@ -0,0 +1,174 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignatorFactory.java,v 1.2 2006/08/30 14:02:35 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.SignatorFactoryException; +import at.knowcenter.wag.egov.egiz.framework.signators.BinarySignator_1_0_0; +import at.knowcenter.wag.egov.egiz.framework.signators.DetachedSignator_1_0_0; +import at.knowcenter.wag.egov.egiz.framework.signators.TextualSignator_1_0_0; + +/** + * This factory creates instances of Signator classes corresponding to the given + * PdfAS Algorithm IDs. + * + * @author wprinz + */ +public abstract class SignatorFactory +{ + /** + * The Vendor. + */ + public static final String VENDOR = "bka.gv.at"; + + /** + * The binary Signator algorithm. + */ + public static final String TYPE_BINARY = "binaer"; + + /** + * The textual Signator algorithm. + */ + public static final String TYPE_TEXTUAL = "text"; + + /** + * This signator is only for testing the framework. + */ + public static final String TYPE_TEST = "testalgo"; + + /** + * This application's current algorithm versions. + */ + public static final String VERSION_1_0_0 = "v1.0.0"; + + /** + * The most recent binary algorithm this application provides. + */ + public static final PdfASID MOST_RECENT_BINARY_SIGNATOR_ID = BinarySignator_1_0_0.MY_ID; + + /** + * The most recent textual algorithm this application provides. + */ + public static final PdfASID MOST_RECENT_TEXTUAL_SIGNATOR_ID = TextualSignator_1_0_0.MY_ID; + + /** + * The most recent test algorithm this application provides. + */ + public static final PdfASID MOST_RECENT_DETACHED_SIGNATOR_ID = DetachedSignator_1_0_0.MY_ID; + + /** + * Creates a Signator for the given ID. + * + * @param id + * The ID of the Signator to be created. + * @return Returns the created Signator object. + * @throws SignatorFactoryException + * Thrown, if there is no appropriate Signator for the given ID. + */ + 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 + "')"); + } + + if (id.getType().equals(TYPE_BINARY)) + { + if (id.getVersion().equals(VERSION_1_0_0)) + { + return new BinarySignator_1_0_0(); + } + + throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); + } + + if (id.getType().equals(TYPE_TEXTUAL)) + { + if (id.getVersion().equals(VERSION_1_0_0)) + { + return new TextualSignator_1_0_0(); + } + + throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); + } + + if (id.getType().equals(TYPE_TEST)) + { + if (id.getVersion().equals(VERSION_1_0_0)) + { + return new DetachedSignator_1_0_0(); + } + + throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); + } + + throw new SignatorFactoryException("The type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); + } + + /** + * Creates the most recent signator the application provides for the given + * type. + * + * @param signator_type + * The type of the signator to be created (see the type field of + * PdfASID). + * @return Returns the created Signator instance. + * @throws SignatorFactoryException + * Thrown, if the type is unknown. + */ + public static Signator createMostRecentSignator(String signator_type) throws SignatorFactoryException + { + PdfASID id = null; + if (signator_type.equals(TYPE_BINARY)) + { + id = MOST_RECENT_BINARY_SIGNATOR_ID; + } + if (signator_type.equals(TYPE_TEXTUAL)) + { + id = MOST_RECENT_TEXTUAL_SIGNATOR_ID; + } + if (signator_type.equals(TYPE_TEST)) + { + id = MOST_RECENT_TEXTUAL_SIGNATOR_ID; + } + + if (id == null) + { + throw new SignatorFactoryException("The type '" + signator_type + "' is not supported by this SignatorFactory."); + } + + return createSignator(id); + } + + /** + * Returns the list of available Signator algorithms of this application. + * + *

+ * Use createMostRecentSignator to create the most recent signator for the + * type. + *

+ * + * @return Returns the list of available Signator algorithms of this + * application. + */ + public static String[] getAvailableTyes() + { + String[] types = new String[] { TYPE_BINARY, TYPE_TEXTUAL, TYPE_TEST }; + return types; + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java new file mode 100644 index 0000000..dd7a742 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java @@ -0,0 +1,494 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: VerificationFilter.java,v 1.5 2006/10/31 08:07:20 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfAS; +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.InvalidIDException; +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.framework.verificators.BinaryVerificator_1_0_0; +import at.knowcenter.wag.egov.egiz.framework.verificators.TextualVerificator_1_0_0; +import at.knowcenter.wag.egov.egiz.pdf.AbsoluteTextSignature; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature; +import at.knowcenter.wag.egov.egiz.pdf.Placeholder; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.StringInfo; +import at.knowcenter.wag.exactparser.ParseDocument; +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; + + +/** + * This filter transforms an arbitrary input pdf into an ordered List of + * SignatureHolders for verification. + * + *

+ * The pdf document is parsed and the signature blocks (textual, binary, etc.) + * are extracted as verifyable SignatureHolder objects in the order they appear + * in the document. + *

+ * + * @author wprinz + */ +public class VerificationFilter +{ + public static final byte[] EGIZ_DICT_NAME = { 'E', 'G', 'I', 'Z', 'S', 'i', + 'g', 'D', 'i', 'c', 't' }; + + public static final byte[] EGIZ_KZ_NAME = { 'I', 'D' }; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(VerificationFilter.class); + + /** + * Default constructor. + */ + public VerificationFilter() + { + // empty block. + } + + /** + * Extracts the List of SignatureHolders from the given PDF document. + * + * @param pdf + * The PDF document. + * @return Returns the ordered List of SignatureHolder objects (the first + * signature will be at index 0) extracted from the document or an + * empty list, if none could be found. + * @throws PresentableException + */ + public List extractSignaturesFromPdf(final byte[] pdf) throws PresentableException + { + List holders = new ArrayList(); + + List blocks = null; + try + { + blocks = ParseDocument.parseDocument(pdf); + } + catch (Exception e) + { + throw new PDFDocumentException(201); + } + +// for (int i = 0; i < blocks.size(); i++) +// { +// FooterParseResult bpr = (FooterParseResult) blocks.get(i); +// // logger_.debug("block[" + i + "] from " + bpr.start_index + " to +// // " + bpr.next_index); +// } + + unrollLinearization(blocks); + + for (int i = 0; i < blocks.size(); i++) + { + FooterParseResult bpr = (FooterParseResult) blocks.get(i); + + int prev_end = 0; + if (i > 0) + { + FooterParseResult prev_bpr = (FooterParseResult) blocks.get(i - 1); + prev_end = prev_bpr.next_index; + } + + // logger_.debug("block from " + prev_end + " to " + + // bpr.next_index); + + if (containsEGIZDict(pdf, bpr)) + { + logger_.debug("Parsing Binary Sig:"); + + PdfASID kz = extractKZFromEGIZBlock(pdf, bpr); + + if (!kz.toString().equals(BinaryVerificator_1_0_0.MY_ID.toString())) + { + logger_.debug("Warning: Binary Kennzeichnung not recognized:" + kz.toString()); + } + + Verificator verificator = new BinaryVerificator_1_0_0(); + List binary_holders = verificator.parseBlock(pdf, bpr, prev_end); + + holders.addAll(binary_holders); + + logger_.debug(":Parsing Binary Sig END - holders.size = " + holders.size()); + } + else + { + logger_.debug("Extracting text for: " + prev_end + " to " + bpr.next_index); + + Verificator verificator = new TextualVerificator_1_0_0(); + List text_holders = verificator.parseBlock(pdf, bpr, prev_end); + logger_.debug("text_holders = " + text_holders.size()); + + if (prev_end == 0) + { + String rest_text = null; + if (!text_holders.isEmpty()) + { + SignatureHolder first_holder = (SignatureHolder) text_holders.get(0); + rest_text = first_holder.getSignedText(); + } + else + { + rest_text = PdfAS.extractNormalizedTextTextual(pdf, bpr.next_index); + } + + List old_holders = PdfAS.extractSignatureHoldersTextual(rest_text, true); + + logger_.debug("Found old holders = " + old_holders.size()); + if (!old_holders.isEmpty()) + { + // there must be only one old holder. + holders.add(0, old_holders.get(0)); + } + } + + if (!text_holders.isEmpty()) + { + List actual_text_holders = throwOutBinHolders(text_holders); + holders.addAll(actual_text_holders); + } + + logger_.debug(":Extracting tex END - holders.size = " + holders.size()); + } + } + + for (int i = 0; i < holders.size(); i++) + { + SignatureHolder holder = (SignatureHolder) holders.get(i); + + PdfASID kz = holder.getSignatureObject().getKZ(); + if (kz != null) + { + checkKZ(kz); + } + } + + return holders; + } + + /** + * Checks, if the given KZ is recognized by this application or logs a warning if it isn't. + * @param kz The Kennzeichnung. + */ + protected void checkKZ (PdfASID kz) + { + if (!kz.getVendor().equals(SignatorFactory.VENDOR)) + { + logger_.warn("The vendor " + kz.getVendor() + " isn't known by this application."); + } + if (!kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + logger_.warn("The version " + kz.getVersion() + " istn't supported by this application. This might cause problems."); + } + } + + /** + * Throws out SignatureHolders with a binary KZ. + * + * @param text_holders + * The List of SignatureHolder objects. + * @return Returns the List of SignatureHolder objects, where no object has + * binary KZ. + */ + private List throwOutBinHolders(List text_holders) + { + List actual_text_holders = new ArrayList(); + for (int i = 0; i < text_holders.size(); i++) + { + SignatureHolder sh = (SignatureHolder) text_holders.get(i); + PdfASID kz = null; + try + { + kz = sh.getSignatureObject().getKZ(); + } + catch (InvalidIDException e) + { + e.printStackTrace(); + } + if (kz != null && kz.getType().equals(SignatorFactory.TYPE_BINARY)) + { + logger_.info("Throwing out binary signature: " + kz); + continue; + } + actual_text_holders.add(sh); + } + return actual_text_holders; + } + + /** + * 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); + } + } + + /** + * Extracts the List of SignatureHolders from the given plain text document. + * + *

+ * Note that this can only extract text signatures. + *

+ * + * @param raw_text + * The plain text document. + * @return Returns the ordered List of SignatureHolder objects (the first + * signature will be at index 0) extracted from the document or an + * empty list, if none could be found. + * @throws SignatureException + * @throws PDFDocumentException + * @throws SignatureTypesException + * @throws NormalizeException + */ + public List extractSignaturesFromPlainText(final String raw_text) throws PDFDocumentException, SignatureException, SignatureTypesException, NormalizeException + { + String normalized_text = PdfAS.normalizeText(raw_text); + + //List text_holders = PdfAS.extractSignatureHoldersTextual(normalized_text, false); + List text_holders = AbsoluteTextSignature.extractSignatureHoldersFromText(normalized_text); + + String rest_text = normalized_text; + if (!text_holders.isEmpty()) + { + SignatureHolder holder = (SignatureHolder) text_holders.get(0); + rest_text = holder.getSignedText(); + } + + List old_holders = PdfAS.extractSignatureHoldersTextual(rest_text, true); + if (!old_holders.isEmpty()) + { + text_holders.addAll(0, old_holders); + } + + List actual_text_holders = throwOutBinHolders(text_holders); + + return actual_text_holders; + } + + /** + * Tells, if the given incremental update block contains a binary signature. + * + *

+ * According to definition, if a block is a binary block, it must/cannot + * contain other signatures than this one. + *

+ * + * @param block + * The incremental update block. + * @return Returns true, if this block is a binary signature block, false + * otherwise. + */ + protected 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. + */ + protected PdfASID extractKZFromEGIZBlock(final byte[] pdf, + final FooterParseResult block) throws PDFDocumentException, InvalidIDException + { + int egiz_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, VerificationFilter.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(201); + } + } + + + protected static void printFoundHolders (String list_caption, List found_holders, PrintStream writer) + { + writer.println("------------------------------------"); + writer.println(list_caption + ": #=" + found_holders.size()); + + for (int i = 0; i < found_holders.size(); i++) + { + SignatureHolder holder = (SignatureHolder) found_holders.get(i); + String kz = "invalid"; + try + { + PdfASID kz_id = holder.getSignatureObject().getKZ(); + if (kz_id == null) + { + kz = "old signature"; + } + else + { + kz = kz_id.toString(); + } + } + catch (InvalidIDException e) + { + e.printStackTrace(); + } + writer.println(" holder[" + i + "]: " + holder.getSignatureObject().getSignationType() + ", KZ=" + kz); + } + + writer.println(":" + list_caption); + writer.println("------------------------------------"); + + } + + public static void main(String[] args) throws IOException, PresentableException + { + SettingsReader.initializeForCommandLine(); + + File in = new File(args[0]); + FileInputStream fis = new FileInputStream(in); + byte[] pdf = new byte[(int) in.length()]; + fis.read(pdf); + fis.close(); + + String text = PdfAS.extractNormalizedTextTextual(pdf, pdf.length);; + + VerificationFilter vf = new VerificationFilter(); + //List found = vf.extractSignaturesFromPdf(pdf); + + List found = vf.extractSignaturesFromPlainText(text); + + printFoundHolders("Final Holders", found, System.out); + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/Verificator.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/Verificator.java new file mode 100644 index 0000000..b17fc79 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/Verificator.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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.knowcenter.wag.egov.egiz.framework; + +import java.util.List; + +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(final byte[] pdf, final FooterParseResult block, + int start_of_whole_block) throws PresentableException; + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java new file mode 100644 index 0000000..d28ac3b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java @@ -0,0 +1,195 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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.knowcenter.wag.egov.egiz.framework.signators; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.lowagie.text.pdf.PdfPTable; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +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.SignResult; +import at.knowcenter.wag.egov.egiz.framework.Signator; +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.ReplaceInfo; +import at.knowcenter.wag.egov.egiz.pdf.StringInfo; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +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.exactparser.ByteArrayUtils; + +/** + * Signs the document binary. + * + *

+ * 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. + *

+ *

+ * In finishSign, the variable fields (values, /Cert) are replaced with the + * values according to the encoding. + *

+ * + * @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); + + /** + * Default constructor. + */ + public BinarySignator_1_0_0() + { + // Default constructor. + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#prepareSign(byte[], + * String, TablePos, boolean) + */ + public IncrementalUpdateInformation prepareSign(byte[] pdf, + String signature_type, TablePos pos, boolean has_SIG_ID) throws PresentableException + { + try + { + SignatureObject signature_object = PdfAS.createSignatureObjectFromType(signature_type); + signature_object.fillValues((char) BinarySignature.LAYOUT_PLACEHOLDER, has_SIG_ID); + + signature_object.setKZ(MY_ID); + + PdfPTable pdf_table = PdfAS.createPdfPTableFromSignatureObject(signature_object); + + if (pos == null) + { + String pos_string = SettingsReader.getInstance().getSetting(SignatureTypes.SIG_OBJ + signature_type + ".pos", null); + if (pos_string != null) + { + pos = PdfAS.parsePositionFromPosString(pos_string); + pdf_table.setTotalWidth(pos.width); + pdf_table.setLockedWidth(true); + } + else + { + pos = PdfAS.adjustTableAndCalculatePosition(pdf, pdf_table); + } + } + else + { + pdf_table.setTotalWidth(pos.width); + pdf_table.setLockedWidth(true); + } + + 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 = BinarySignature.writeIncrementalUpdate(pdf, pdf_table, pos, variable_field_definitions, all_field_definitions); + + String temp_string = iui.temp_ir_number + " " + iui.temp_ir_generation + " obj"; + byte[] temp_bytes = temp_string.getBytes("US-ASCII"); + 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); + + iui.document_text = BinarySignature.retrieveSignableTextFromData(iui.signed_pdf, iui.signed_pdf.length); // signed_pdf.length); + + return iui; + + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new PDFDocumentException(201, e); + } + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#finishSign(at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation) + */ + public SignResult finishSign(IncrementalUpdateInformation iui) throws PresentableException + { + // PdfAS.prefixID(iui.signed_signature_object, PdfAS.BINARY_ID); + Iterator it = iui.replaces.iterator(); + while (it.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) it.next(); + + ri.value = iui.signed_signature_object.getSigValue(ri.sfd.field_name); + } + BinarySignature.replaceCertificate(iui); + BinarySignature.replacePlaceholders(iui); + + SignResult sign_result = new SignResult(PdfAS.PDF_MIME_TYPE, iui.signed_pdf); + return sign_result; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java new file mode 100644 index 0000000..88d9338 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: DetachedSignator_1_0_0.java,v 1.1 2006/08/30 14:02:35 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.signators; + +import java.io.UnsupportedEncodingException; + +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.SignResult; +import at.knowcenter.wag.egov.egiz.framework.Signator; +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.TablePos; + +/** + * This signator is just for testing purposes. + * + *

+ * It doesn't modify the original document, but simply returns the XML signature + * response as the signed document. + *

+ * + * @author wprinz + */ +public class DetachedSignator_1_0_0 implements Signator +{ + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEST, SignatorFactory.VERSION_1_0_0); + + /** + * The Mime Type. + */ + public static final String MIME_TYPE = "text/xml"; + + /** + * Default constructor. + */ + public DetachedSignator_1_0_0() + { + // Default constructor. + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#prepareSign(byte[], + * String, TablePos, boolean) + */ + public IncrementalUpdateInformation prepareSign(byte[] 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; + + iui.document_text = BinarySignature.retrieveSignableTextFromData(iui.original_document, iui.original_document.length); + + 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.getRawSignatureResponse(); + byte[] response_bytes = response.getBytes("UTF-8"); + + SignResult sign_result = new SignResult(MIME_TYPE, response_bytes); + return sign_result; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new PDFDocumentException(300, e); + } + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java new file mode 100644 index 0000000..6e605ff --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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.knowcenter.wag.egov.egiz.framework.signators; + +import com.lowagie.text.pdf.PdfPTable; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.SignResult; +import at.knowcenter.wag.egov.egiz.framework.Signator; +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.TablePos; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * Signs a document textually. + * + *

+ * In prepareSign, the document text is extracted and normalized. + *

+ *

+ * In finishSign, the signed SignatureObject is transformed into a Signature + * block, which is then written as an Incremental Update. + *

+ * + * @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); + + /** + * Default constructor. + */ + public TextualSignator_1_0_0() + { + // Default constructor. + } + + /** + *

+ * The parameter has_SIG_ID is not used by this Signator because it doesn't + * pre-format the signature block. + *

+ * + * @see at.knowcenter.wag.egov.egiz.framework.Signator#prepareSign(byte[], + * String, TablePos, boolean) + */ + public IncrementalUpdateInformation prepareSign(byte[] 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; + + iui.document_text = PdfAS.extractNormalizedTextTextual(pdf); + // logger_.debug("signed_text = " + document_text); + + 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 + { + // PdfAS.prefixID(iui.signed_signature_object, PdfAS.TEXT_ID); + + iui.signed_signature_object.setKZ(MY_ID); + + PdfPTable pdf_table = PdfAS.createPdfPTableFromSignatureObject(iui.signed_signature_object); + + if (iui.pos == null) + { + String pos_string = SettingsReader.getInstance().getSetting(SignatureTypes.SIG_OBJ + iui.signature_type + ".pos", null); + if (pos_string != null) + { + iui.pos = PdfAS.parsePositionFromPosString(pos_string); + pdf_table.setTotalWidth(iui.pos.width); + pdf_table.setLockedWidth(true); + } + else + { + iui.pos = PdfAS.adjustTableAndCalculatePosition(iui.original_document, pdf_table); + } + } + else + { + pdf_table.setTotalWidth(iui.pos.width); + pdf_table.setLockedWidth(true); + } + + IncrementalUpdateInformation signed_iui = BinarySignature.writeIncrementalUpdate(iui.original_document, pdf_table, iui.pos, null, null); + + SignResult sign_result = new SignResult(PdfAS.PDF_MIME_TYPE, signed_iui.signed_pdf); + return sign_result; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_0_0.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_0_0.java new file mode 100644 index 0000000..9064629 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_0_0.java @@ -0,0 +1,373 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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.knowcenter.wag.egov.egiz.framework.verificators; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +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.framework.Verificator; +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); + + /** + * 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.knowcenter.wag.egov.egiz.framework.Verificator#parseBlock(byte[], + * at.knowcenter.wag.exactparser.parsing.results.FooterParseResult, int) + */ + public List parseBlock(byte[] pdf, FooterParseResult block, + int start_of_whole_block) throws PresentableException + { + int egiz_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, VerificationFilter.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); + + 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(MY_ID.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; + } + } + + BinarySignatureHolder signature_holder = new BinarySignatureHolder(signed_pdf, signed_pdf.length, 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(301, "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/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_1_0_0.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_1_0_0.java new file mode 100644 index 0000000..bbcebef --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_1_0_0.java @@ -0,0 +1,136 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: TextualVerificator_1_0_0.java,v 1.4 2006/10/31 08:08:00 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.verificators; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.framework.Verificator; +import at.knowcenter.wag.egov.egiz.pdf.AbsoluteTextSignature; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; + + +/** + * The textual verificator. + * + *

+ * All holders of the document so far including the block itself are extracted. + * If at least one has been found it is checked that this one doesn't belong to + * a previous block. + *

+ *

+ * Note that the KZ is not explicitely checked here, so this algorithm will find + * all blocks. + *

+ *

+ * Note that it will not find old style blocks as they don't have the SIG_KZ. + *

+ * + * @author wprinz + */ +public class TextualVerificator_1_0_0 implements Verificator +{ + /** + * The Pdf-AS ID of this Verificator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEXTUAL, SignatorFactory.VERSION_1_0_0); + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(TextualVerificator_1_0_0.class); + + /** + * Default constructor. + */ + public TextualVerificator_1_0_0() + { + // Default constructor. + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Verificator#parseBlock(byte[], + * at.knowcenter.wag.exactparser.parsing.results.FooterParseResult, int) + */ + public List parseBlock(byte[] pdf, FooterParseResult block, + int start_of_whole_block) throws PresentableException + { + String block_text = PdfAS.extractNormalizedTextTextual(pdf, block.next_index); + + logger_.debug("Scanning block:"); + //List signature_holders = PdfAS.extractSignatureHoldersTextual(block_text, false); + List signature_holders = AbsoluteTextSignature.extractSignatureHoldersFromText(block_text); + logger_.debug(": end of Scanning block"); + + // logger_.debug("signature_holders = " + signature_holders.size()); + + if (signature_holders.isEmpty()) + { + return signature_holders; + } + + List text_holder_candidates = null; + if (start_of_whole_block > 0) + { + text_holder_candidates = new ArrayList(); + + String prev_text = PdfAS.extractNormalizedTextTextual(pdf, start_of_whole_block); + + logger_.debug("Scanning prev block:"); + //List prev_signature_holders = PdfAS.extractSignatureHoldersTextual(prev_text, false); + List prev_signature_holders = AbsoluteTextSignature.extractSignatureHoldersFromText(prev_text); + logger_.debug(": end of Scanning prev block"); + + // logger_.debug("prev_signature_holders = " + + // prev_signature_holders.size()); + + for (int i = prev_signature_holders.size(); i < signature_holders.size(); i++) + { + SignatureHolder holder = (SignatureHolder) signature_holders.get(i); + text_holder_candidates.add(holder); + } + } + else + { + logger_.debug("there is no prev - so all found signatures are possible candidates."); + text_holder_candidates = signature_holders; + } + + List text_holders = new ArrayList(); + for (int i = 0; i < text_holder_candidates.size(); i++) + { + SignatureHolder holder = (SignatureHolder) text_holder_candidates.get(i); + if (!holder.getSignatureObject().isTextual()) + { + logger_.debug("Skipping found signature block because it's not textual."); + continue; + } + text_holders.add(holder); + } + + return text_holders; + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_pdfasold.java b/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_pdfasold.java new file mode 100644 index 0000000..5008ed3 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_pdfasold.java @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: TextualVerificator_pdfasold.java,v 1.3 2006/10/11 08:03:22 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.verificators; + +import java.util.List; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.Verificator; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; + + +/** + * This Verificator extracts a PDF-AS old signature from the original document. + * + * @author wprinz + */ +public class TextualVerificator_pdfasold implements Verificator +{ + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(TextualVerificator_1_0_0.class); + + /** + * Default Constructor. + */ + public TextualVerificator_pdfasold() + { + // Default Constructor. + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Verificator#parseBlock(byte[], at.knowcenter.wag.exactparser.parsing.results.FooterParseResult, int) + */ + public List parseBlock(byte[] pdf, FooterParseResult block, + int start_of_whole_block) throws PresentableException + { + if (start_of_whole_block != 0) + { + throw new PDFDocumentException(201, "The PDF-AS-old Verificator can only be applied on original documents."); + } + + String normalized_text = PdfAS.extractNormalizedTextTextual(pdf, block.next_index); + + logger_.debug("Scanning block:"); + List signature_holders = PdfAS.extractSignatureHoldersTextual(normalized_text, true); + logger_.debug(": end of Scanning block"); + + +// List signature_holders = new ArrayList(); +// +// SignatureTypes sig_types = SignatureTypes.getInstance(); +// List signatureTypes_ = sig_types.getSignatureTypeDefinitions(); +// +// boolean can_separate = true; +// int endIndex = normalized_text.length(); +// String signed_text = normalized_text; +// +// SignatureBlock sig_block = new SignatureBlock(signatureTypes_); +// can_separate = sig_block.separateBlockFromRawText(signed_text, true); +// if (can_separate) +// { +// endIndex = sig_block.getStartIndex(); +// signed_text = signed_text.substring(0, endIndex); +// +// SignatureObject sig_object = sig_block.getSignatureObject(); +// +// SignatureHolder holder = new SignatureHolder(); +// holder.signed_text = signed_text; +// holder.signature_object = sig_object; +// signature_holders.add(0, holder); +// } + + return signature_holders; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java new file mode 100644 index 0000000..5523041 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java @@ -0,0 +1,656 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: AbsoluteTextSignature.java,v 1.1 2006/10/31 08:08:33 wprinz Exp $ + */package at.knowcenter.wag.egov.egiz.pdf; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Vector; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.framework.FoundBlock; +import at.knowcenter.wag.egov.egiz.framework.FoundKey; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * Contains methods and helpers that implement the absolute text signature. + * @author wprinz + */ +public class AbsoluteTextSignature +{ + + /** + * The logger definition. + */ + private static final Logger logger = ConfigLogger.getLogger(AbsoluteTextSignature.class); + + + /** + * Extracts all signature holders from a given text. + * + *

+ * First the latest signature holder is extracted. Then the latest signature + * holder in the rest text, which is the second latest one, is extracted. Then + * the third latest signature holder is extracted and so forth until no more + * signature holders are found. + *

+ * + * @param text + * The text. + * @return Returns the List of extracted signature holders ordered by their + * date ascendingly (the lowest, earliest date first, the latest, + * newest date last). An empty list is returned if no signature + * holders were found. + * @throws SignatureException + * F.e. + * @throws SignatureTypesException + * F.e. + */ + public static List extractSignatureHoldersFromText(String text) throws SignatureException, SignatureTypesException + { + List holders = new ArrayList(); + + String current_text = text; + for (;;) + { + SignatureHolder signature_holder = extractLatestBlock(current_text); + if (signature_holder == null) + { + break; + } + + holders.add(0, signature_holder); + + current_text = signature_holder.getSignedText(); + } + + return holders; + } + + /** + * Extracts the latest signature block from the given text and creates a + * SignatureHolder object that can be verified. + * + * @param text + * The text. + * @return Returns the SignatureObject extracted from the text, or null, if no + * latest block was found. + * @throws SignatureException + * F.e. + * @throws SignatureTypesException + * F.e. + */ + public static SignatureHolder extractLatestBlock(String text) throws SignatureException, SignatureTypesException + { + FoundBlock latest_block = findLatestBlock(text); + if (latest_block == null) + { + return null; + } + + String reconstructed_text = cutOutBlock(text, latest_block); + + SignatureObject so = createSignatureObjectFromFoundBlock(text, latest_block); + TextualSignatureHolder tsh = new TextualSignatureHolder(reconstructed_text, so); + + return tsh; + } + + /** + * Finds the latest signature block for a given text. + * + *

+ * The latest block is the one with the highest, most recent date. Usually + * this block will be extracted (cut out) of the text which will result in the + * originally signed text of this signature to be verified using the cut out + * data. + *

+ * + * @param text + * The text to be analyzed. + * @return Returns the latest found block or null, if there was none. + * @throws SignatureException + * F.e. + * @throws SignatureTypesException + * F.e. + */ + public static FoundBlock findLatestBlock(String text) throws SignatureException, SignatureTypesException + { +// try +// { +// writeTextToFile(text, new File("C:\\wprinz\\text.utf8.txt")); +// } +// catch (IOException e) +// { +// e.printStackTrace(); +// } + + SignatureTypes sig_types = SignatureTypes.getInstance(); + List signatureTypes_ = sig_types.getSignatureTypeDefinitions(); + + List found_candidates = new ArrayList(); + + for (int i = 0; i < signatureTypes_.size(); i++) + { + SignatureTypeDefinition block_type = (SignatureTypeDefinition) signatureTypes_.get(i); + List found_candidates_for_type = findPotentialSignaturesForProfile(text, block_type); + + found_candidates.addAll(found_candidates_for_type); + } + + if (found_candidates.isEmpty()) + { + logger.debug("no candidates found at all"); + return null; + } + + logger.debug("checking block integrity"); + for (int i = 0; i < found_candidates.size(); i++) + { + FoundBlock found_block = (FoundBlock) found_candidates.get(i); + + String date_value = getDateValue(text, found_block); + logger.debug("date_value = " + date_value); + EGIZDate date = EGIZDate.parseFromString(date_value); + + logger.debug("found_block = " + date + " - " + found_block); + + checkBlockIntegrity(text, found_block); + } + + sortFoundBlocksByDate(text, found_candidates); + + logger.debug("sorted blocks:"); + for (int i = 0; i < found_candidates.size(); i++) + { + FoundBlock found_block = (FoundBlock) found_candidates.get(i); + + String date_value = getDateValue(text, found_block); + EGIZDate date = EGIZDate.parseFromString(date_value); + + logger.debug(" #" + i + ": " + date + " - " + found_block); + } + + List latest_blocks = filterLastDateEqualBlocks(text, found_candidates); + logger.debug("latest blocks:"); + for (int i = 0; i < latest_blocks.size(); i++) + { + FoundBlock found_block = (FoundBlock) latest_blocks.get(i); + + String date_value = getDateValue(text, found_block); + EGIZDate date = EGIZDate.parseFromString(date_value); + + logger.debug(" #" + i + ": " + date + " - " + found_block); + } + + boolean semantic_equality = PdfAS.checkForSemanticEquality(latest_blocks); + logger.debug("semantic_equality = " + semantic_equality); + if (!semantic_equality) + { + throw new SignatureException(314, "The latest blocks weren't semantically equal."); + } + + FoundBlock latest_block = (FoundBlock) latest_blocks.get(0); + logger.debug("latest block = " + latest_block); + return latest_block; + } + + /** + * Finds the List of potential blocks within the given text for the given + * profile. + * + * @param text + * The text, in which potential block are to be sought. + * @param block_type + * The profile for which the text is to be sought. + * @return Returns the List of potential FoundBlocks or an empty List if none + * could be found. + */ + public static List findPotentialSignaturesForProfile(String text, + SignatureTypeDefinition block_type) + { + logger.debug("find potential signatures for " + block_type.getType()); + + List found_blocks = new ArrayList(); + + final boolean old_style = false; + + Vector keys = block_type.getRevertSortedKeys(); + Vector captions = block_type.getRevertSortedCaptions(); + + String last_key = (String) keys.get(0); + logger.debug("last_key = " + last_key); + String last_caption = (String) captions.get(0); + logger.debug("last_caption = " + last_caption); + + List found_last_captions = findIndices(text, last_caption); + if (logger.isDebugEnabled()) + { + logger.debug("found " + found_last_captions.size() + " last captions."); + for (int i = 0; i < found_last_captions.size(); i++) + { + logger.debug(" found last caption at index " + found_last_captions.get(i)); + } + } + + for (int lci = 0; lci < found_last_captions.size(); lci++) + { + int last_caption_index = ((Integer) found_last_captions.get(lci)).intValue(); + logger.debug("resolving signature block from last caption index " + last_caption_index); + + int potential_block_end = findEndOfValue(text, last_caption_index); + logger.debug("potential_block_end = " + potential_block_end); + + List found_keys = PdfAS.findBlockInText(text.substring(0, potential_block_end), block_type, old_style); // findRestKeys(text, + // keys, + // captions, + // last_caption_index); + + if (found_keys == null) + { + logger.debug("Not all other captions could be found for the last_caption_index " + last_caption_index + " ==> discarding this index."); + + continue; + } + + // sort found keys ascendingly + PdfAS.sortFoundKeysAscendingly(found_keys); + + boolean reverse_check_ok = reverseCheckFoundKeys(text, found_keys); + if (!reverse_check_ok) + { + logger.debug("The reverse check ruled this list of found keys out ==> they are discarded."); + + continue; + } + + logger.debug("The reverse check proved this list of found keys out ==> adding them as potential candidates."); + + FoundBlock found_block = new FoundBlock(); + found_block.std = block_type; + found_block.found_keys = found_keys; + found_block.end_index = findEndOfValue(text, last_caption_index); + found_blocks.add(found_block); + } + + logger.debug("found " + found_blocks.size() + " potential signatures for " + block_type.getType()); + return found_blocks; + } + + /** + * Finds all indices of the given subtext within a given text. + * + *

+ * This is usually used to find the indices of the last captions. + *

+ * + * @param text + * The text to be searched. + * @param subtext + * The subtext to be sought. + * @return Returns the List of found indices. + */ + public static List findIndices(String text, String subtext) + { + List found_indices = new ArrayList(); + int search_from_index = 0; + for (;;) + { + int found_index = text.indexOf(subtext, search_from_index); + if (found_index < 0) + { + break; + } + found_indices.add(new Integer(found_index)); + search_from_index = found_index + subtext.length(); + } + return found_indices; + } + + /** + * Finds the other keys/captions according to their order starting from the + * last_caption index upwards. + * + * @param text + * The text. + * @param keys + * The list of keys. + * @param captions + * The list of captions. + * @param last_caption_index + * The index of the last caption. + * @return Returns the List of found keys, if all keys could be found, or null + * if not all keys could be found. + */ + public static List findRestKeys(String text, List keys, List captions, + int last_caption_index) + { + List found_keys = new ArrayList(); + + FoundKey last_caption_found_key = new FoundKey((String) keys.get(0), (String) captions.get(0), last_caption_index); + found_keys.add(last_caption_found_key); + + String rest_text = text.substring(0, last_caption_index); + + for (int i = 1; i < captions.size(); i++) + { + String sought_caption = (String) captions.get(i); + int index = rest_text.lastIndexOf(sought_caption); + + if (index < 0) + { + return null; + } + + FoundKey found_key = new FoundKey((String) keys.get(i), (String) captions.get(i), index); + found_keys.add(0, found_key); + + rest_text = rest_text.substring(0, index); + } + + return found_keys; + } + + /** + * Performs a reverse (top to bottom) search for the found keys and checks + * that these indices are the same as those that were found during the regular + * (bottom up) search. + *

+ * If a reverse check proves that the found keys are not at the same positions + * as during regular search, this list of found keys should be discarded. + *

+ * + * @param text + * The text. + * @param found_keys + * The found keys to be reversely checked. + * @return Returns true, if all (also the non required) captions could be + * found at the same indices as during regular search, false + * otherwise. + */ + public static boolean reverseCheckFoundKeys(String text, List found_keys) + { + int search_from_index = ((FoundKey) found_keys.get(0)).start_index; + for (int i = 0; i < found_keys.size(); i++) + { + FoundKey found_key = (FoundKey) found_keys.get(i); + + int reverse_found_index = text.indexOf(found_key.caption, search_from_index); + if (reverse_found_index < 0) + { + throw new RuntimeException("The caption " + found_key.caption + " wasn't found in the text during reverse checking - there is something wrong."); + } + + if (reverse_found_index != found_key.start_index) + { + logger.debug("The index for caption " + found_key.caption + " wasn't proved during reverse checking."); + return false; + } + + search_from_index = found_key.start_index + found_key.caption.length(); + } + + return true; + } + + /** + * Finds the end of the value in the text. + * + *

+ * This simply scans for a '\n' from a given start index. The line up to and + * inclusive the '\n' is considered to be the value. + *

+ *

+ * Note that this method does NOT find the accurate value, if the value goes + * over multiple lines! This may bear a serious problem. Usually this method + * is only used to finding the end of the last value in a found block, because + * mid- values are exactly determined by their start index and the start of + * the next caption. Nevertheless, if the last value spans over multiple + * lines, this method will not retrieve it completely. + *

+ * + * @param text + * The text. + * @param start_index + * The start index from where the end of the value is sought. + * @return Returns the end index of the value, which is the index of the first + * character not belonging to the value anymore (the character after + * the '\n'). + */ + public static int findEndOfValue(String text, int start_index) + { + int newline_index = text.indexOf('\n', start_index); + if (newline_index < 0) + { + return text.length(); + } + return newline_index + 1; + } + + /** + * Checks the integrity of a found block. + * + *

+ * This is an assertive function. + *

+ * + * @param text + * The text. + * @param found_block + * The found block. + */ + public static void checkBlockIntegrity(String text, FoundBlock found_block) + { + for (int i = 0; i < found_block.found_keys.size() - 1; i++) + { + FoundKey this_key = (FoundKey) found_block.found_keys.get(i); + FoundKey next_key = (FoundKey) found_block.found_keys.get(i + 1); + + int this_end_index = findEndOfValue(text, this_key.start_index); + if (this_end_index != next_key.start_index) + { + logger.warn("multi line value: " + this_key); + // throw new RuntimeException("The end index of found key " + this_key + + // " doesn't match the start index of found key " + next_key); + } + } + + FoundKey last_key = (FoundKey) found_block.found_keys.get(found_block.found_keys.size() - 1); + if (findEndOfValue(text, last_key.start_index) != found_block.end_index) + { + throw new RuntimeException("The end index of last key " + last_key + " doesn't match the end index of the block " + found_block); + } + + } + + /** + * Cuts out the given found block from the text. + * + * @param text + * The text. + * @param block + * The found block. + * @return Returns the rest text without the block. + */ + public static String cutOutBlock(String text, FoundBlock block) + { + int block_start_index = ((FoundKey) block.found_keys.get(0)).getStartIndex(); + int block_end_index = block.end_index; + + if (block_end_index == text.length()) + { + // if the block is at the end of the text, remove the "\n" before the + // block as well. + String pre = text.substring(0, block_start_index - 1); + return pre; + } + + String pre = text.substring(0, block_start_index); + String post = text.substring(block_end_index); + + String rest_text = pre + post; + return rest_text; + } + + /** + * Returns the value of the date field as String. + * + * @param text + * The text. + * @param block + * The found block. + * @return Returns the date value. + */ + public static String getDateValue(String text, FoundBlock block) + { + FoundKey date_key = block.getDateFoundKey(); + int date_value_start_index = date_key.start_index + date_key.caption.length(); + int date_value_end_index = findEndOfValue(text, date_value_start_index); + String date_value = text.substring(date_value_start_index, date_value_end_index).trim(); + + return date_value; + } + + /** + * Creates a SignatureObject from a found block by extracting the + * corresponding values. + * + * @param text + * The text. + * @param found_block + * The found block. + * @return Returns the created SignatureObject. + * @throws SignatureTypesException + * F.e. + * @throws SignatureException + * F.e. + */ + public static SignatureObject createSignatureObjectFromFoundBlock( + String text, FoundBlock found_block) throws SignatureTypesException, SignatureException + { + SignatureObject signatureObject = new SignatureObject(); + + signatureObject.setSigType(found_block.std.getType()); + signatureObject.initByType(); + + int end_index = found_block.end_index; + for (int i = found_block.found_keys.size() - 1; i >= 0; i--) + { + FoundKey cur_key = (FoundKey) found_block.found_keys.get(i); + int start_index = cur_key.getStartIndex() + cur_key.caption.length(); + + String value = text.substring(start_index, end_index); + + signatureObject.setSigValueCaption(cur_key.getKey(), value, cur_key.caption); + + end_index = cur_key.getStartIndex(); + } + + return signatureObject; + + } + + /** + * Parses the EGIZDate from a found block and the given text. + * + * @param text + * The text. + * @param found_block + * The found block. + * @return Returns the parsed EGIZDate. + */ + public static EGIZDate getDateFromFoundBlock(String text, + FoundBlock found_block) + { + String date_value = getDateValue(text, found_block); + EGIZDate date = EGIZDate.parseFromString(date_value); + return date; + } + + /** + * Sorts the List of found blocks by date. + * + * @param text + * The text. + * @param found_blocks + * The List of found blocks. + */ + public static void sortFoundBlocksByDate(final String text, List found_blocks) + { + Collections.sort(found_blocks, new Comparator() + { + public int compare(Object arg0, Object arg1) + { + FoundBlock fb0 = (FoundBlock) arg0; + FoundBlock fb1 = (FoundBlock) arg1; + + EGIZDate date0 = getDateFromFoundBlock(text, fb0); + EGIZDate date1 = getDateFromFoundBlock(text, fb1); + return date0.compareTo(date1); + } + }); + } + + /** + * Given a List of FoundBlock objects, this method returns the last blocks of + * this list that have the same date. + * + *

+ * Usually a date sorted list (earliest first, latest last) will be provided + * to this method. Then the last date equal blocks are returned, which are the + * last blocks. + *

+ * + * @param text + * The text to retrieve the values of the fields from. + * @param found_blocks + * The List of FoundBlock objects. + * @return Returns the List of the last date equal blocks. + */ + public static List filterLastDateEqualBlocks(String text, List found_blocks) + { + List latest_blocks = new ArrayList(); + + latest_blocks.add(found_blocks.get(found_blocks.size() - 1)); + + for (int i = found_blocks.size() - 2; i >= 0; i--) + { + FoundBlock this_block = (FoundBlock) found_blocks.get(i); + FoundBlock succ_block = (FoundBlock) found_blocks.get(i + 1); + + EGIZDate this_date = getDateFromFoundBlock(text, this_block); + EGIZDate succ_date = getDateFromFoundBlock(text, succ_block); + + if (!this_date.equals(succ_date)) + { + break; + } + latest_blocks.add(0, this_block); + } + + return latest_blocks; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinaryBlockInfo.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinaryBlockInfo.java new file mode 100644 index 0000000..cdc092f --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinaryBlockInfo.java @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: BinaryBlockInfo.java,v 1.1 2006/08/25 17:10:08 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.util.List; + +/** + * Helper class that holds information about a binary signature block. + * + * @author wprinz + */ +public class BinaryBlockInfo +{ + /** + * The signed size, in bytes. + * + *

+ * This includes the block itself. + *

+ */ + public int signed_size = -1; + + /** + * The List of ReplaceInfo objects that specify the replaced strings. + */ + public List replaces = null; + +// /** +// * The start of the /ODS number in the PDF. +// */ +// public int ods_start = -1; +// +// /** +// * The start of the \replaces array in the PDF. +// */ +// public int array_start = -1; + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java new file mode 100644 index 0000000..c5acbc4 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java @@ -0,0 +1,1731 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: BinarySignature.java,v 1.4 2006/10/11 07:57:58 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PlaceholderException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.sig.SignatureBlock; +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.X509Cert; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.exactparser.ByteArrayUtils; + +import com.lowagie.text.Document; +import com.lowagie.text.DocumentException; +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.PRStream; +import com.lowagie.text.pdf.PdfArray; +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfDictionary; +import com.lowagie.text.pdf.PdfIndirectObject; +import com.lowagie.text.pdf.PdfIndirectReference; +import com.lowagie.text.pdf.PdfName; +import com.lowagie.text.pdf.PdfNumber; +import com.lowagie.text.pdf.PdfObject; +import com.lowagie.text.pdf.PdfPTable; +import com.lowagie.text.pdf.PdfReader; +import com.lowagie.text.pdf.PdfStamper; +import com.lowagie.text.pdf.PdfStamperImp; +import com.lowagie.text.pdf.PdfString; +import com.lowagie.text.pdf.PdfTemplate; + +/** + * Contains various extension functions to digitally sign documents. + * + *

+ * These functions are used to replace parts of the original Egiz plain text + * signature mechanism. + *

+ * + * @author wprinz + */ +public abstract class BinarySignature +{ + /** + * The tolerance area of the line break algorithm. + * + * @see Placeholder#replacePlaceholderWithTolerance(byte[], List, byte[], int) + */ + public static final int LINE_BREAK_TOLERANCE = 10; + + /** + * The number of bytes left out for the certificate placeholder. + */ + public static final int CERTIFICATE_PLACEHOLDER_LENGTH = 10000; + + /** + * The placeholder character used to fill out Strings in the layout process. + */ + public static final byte LAYOUT_PLACEHOLDER = 'w'; + + /** + * This placeholder is used to fill out holes between the byte ranges before + * the document is signed. + */ + public static final byte SIGN_PLACEHOLDER = 0; + + /** + * The nil brev used to define an unrecognized value. + */ + public static final byte[] BREV_NIL = { 'n', 'i', 'l' }; + + /** + * The date brev. + */ + public static final byte[] BREV_DAT = { 'd', 'a', 't' }; + + /** + * The issure brev. + */ + public static final byte[] BREV_ISS = { 'i', 's', 's' }; + + /** + * The serial number brev. + */ + public static final byte[] BREV_SNR = { 's', 'n', 'r' }; + + /** + * The value brev. + */ + public static final byte[] BREV_VAL = { 'v', 'a', 'l' }; + + /** + * The SIG_ID brev. + */ + public static final byte[] BREV_SID = { 's', 'i', 'd' }; + + /** + * No explicit encoding. + */ + public static final byte[] ENCODING_NIL = { 'n', 'i', 'l' }; + + /** + * PDF WinAnsiEncoding. + */ + public static final byte[] ENCODING_WIN = { 'w', 'i', 'n' }; + + /** + * URL encoding. + */ + public static final byte[] ENCODING_URL = { 'u', 'r', 'l' }; + + /** + * The PDFName of the Egiz Dictionary. + * + *

+ * Used to locate and identify the Egiz Dictionary in the document. + *

+ */ + public static final PdfName EGIZ_DICT_NAME = new PdfName("EGIZSigDict"); + + /** + * The PDFName of the Original Document Size (ODS) field in an Egiz + * Dictionary. + * + *

+ * The ODS must be a positive integral number. + *

+ */ + public static final PdfName EGIZ_ODS_NAME = new PdfName("ODS"); + + /** + * The PDFName of the Kennzeichnung attribute. + */ + public static final PdfName EGIZ_KZ_NAME = new PdfName("ID"); + + /** + * The PDFName of the /replaces field in an Egiz Dictionary. + */ + public static final PdfName EGIZ_REPLACES_NAME = new PdfName("replaces"); + + /** + * The PDFName of the /encodings field in an Egiz Dictionary. + */ + public static final PdfName EGIZ_ENCODINGS_NAME = new PdfName("encodings"); + + /** + * The PDFName of the byte ranges array. + */ + public static final PdfName EGIZ_BYTERANGES_NAME = new PdfName("ByteRange"); + + /** + * The PdfName of the certificate array. + */ + public static final PdfName EGIZ_CERTIFICATE_NAME = new PdfName("Cert"); + + /** + * The PDFName of the Signature XObject field in an Egiz Dictionary. + * + *

+ * This must be an indirect reference to the XObject containing the Signature + * table. + *

+ */ + public static final PdfName EGIZ_XOBJ_NAME = new PdfName("SigXObject"); + + /** + * The number placeholder that is used to give numbers a fixed length. + */ + protected static final PdfNumber NUMBER_PLACEHOLDER = new PdfNumber(99999999); + + /** + * Extracts the signature text only. + * + *

+ * The signature text is the text of the Signature XObject. + *

+ * + * @param egiz_dict + * The Egiz Dictionary. + * + * @return Returns the signature text. + */ + public static String extractSignatureTextOnly(PdfDictionary egiz_dict) throws IOException + { + PdfIndirectReference xobj_ir = (PdfIndirectReference) egiz_dict.get(EGIZ_XOBJ_NAME); + PRStream temp_stream = (PRStream) PdfReader.getPdfObject(xobj_ir); + + byte[] stream_bytes = PdfReader.getStreamBytes(temp_stream); + + return Utils.extractPureTextFromContentStream(stream_bytes); + } + + /** + * Retrieves the size of the original document from the Egiz Dictionary. + * + * @param egiz_dict + * The Egiz Dictionary. + * @return Returns the size (in bytes) of the original document. + */ + public static int getOriginalDocumentSizeFromEgizDict(PdfDictionary egiz_dict) + { + PdfObject ods_obj = egiz_dict.get(EGIZ_ODS_NAME); + PdfNumber ods_number = (PdfNumber) PdfReader.getPdfObject(ods_obj); + + return ods_number.intValue(); + } + + /** + * Retrieves the previous Egiz dictionary from the given one, if a previous + * dictionary exists. + * + * @param egiz_dict + * The Egiz Dictionary. + * @return Returns the previous Egiz Dictionary, or null if there is none. + */ + public static PdfDictionary getPreviousFromEgizDict(PdfDictionary egiz_dict) + { + PdfObject prev_obj = egiz_dict.get(PdfName.PREV); + PdfDictionary previous_dict = (PdfDictionary) PdfReader.getPdfObject(prev_obj); + return previous_dict; + } + + /** + * Retrieves the Egiz Dictionary from the document if present. + * + * @param reader + * The reader to retrieve the dictionary from. + * @return Returns the Egiz Dictionary, if present, or returns null, if no + * egiz dictionary was found. + */ + public static PdfDictionary getEgizDictFromReader(PdfReader reader) + { + PdfIndirectReference dict_ir = getEgizDictIndRefFromReader(reader); + if (dict_ir == null) + { + return null; + } + + PdfDictionary egiz_dict = (PdfDictionary) PdfReader.getPdfObject(dict_ir); + + return egiz_dict; + } + + /** + * Retrieves the Egiz Dictionary's indirect reference from the reader. + * + * @param reader + * The reader. + * @return Returns the indirect reference of the Egiz Dictionary, or null, if + * none exists. + */ + public static PdfIndirectReference getEgizDictIndRefFromReader( + PdfReader reader) + { + PdfDictionary catalog = reader.getCatalog(); + PdfIndirectReference dict_ir = (PdfIndirectReference) catalog.get(EGIZ_DICT_NAME); + return dict_ir; + } + + /** + * Retrieves the chain of Egiz Dictionaries from the reader. + * + *

+ * The first element in the List will be the top most (oldest) Egiz + * Dictionary. The last element in the List will be the bottom most (latest) + * Egiz Dictionary. If the list is empty, no dictionary could be found at all, + * which means that the document is not digitally signed. + *

+ * + * @param reader + * The reader. + * @return Returns the List of PdfDictionaries from the document. + */ + public static List getEgizDictChainFromReader(PdfReader reader) + { + List dicts = new ArrayList(); + + PdfDictionary current_dict = getEgizDictFromReader(reader); + if (current_dict != null) + { + dicts.add(0, current_dict); + + while ((current_dict = getPreviousFromEgizDict(current_dict)) != null) + { + dicts.add(0, current_dict); + } + } + + return dicts; + } + + /** + * Builds a digest of the given data. + * + * @param data + * The data to be digested. + * @param length + * The length of the data portion that should be used for digesting. + * This allows to build the digest only over parts of the data. + * @return Returns the created digest. + * @throws PDFDocumentException + * Forwarded exception. + */ + public static byte[] buildDigest(final byte[] data, final int length) throws PDFDocumentException + { + MessageDigest sha_512 = null; + try + { + sha_512 = MessageDigest.getInstance("SHA-512"); + } + catch (NoSuchAlgorithmException e) + { + e.printStackTrace(); + throw new PDFDocumentException(202, "Digest algorithm not supported - NoSuchAlgorithmException", e); + } + + sha_512.reset(); + sha_512.update(data, 0, length); + byte[] digest = sha_512.digest(); + + return digest; + } + + /** + * Retrieves the signable text from the given document. + * + * @param data + * The data. + * @param ods + * The original document size. + * @return Returns the signable text. + */ + public static String retrieveSignableTextFromData(final byte[] data, + final int ods) + { + // byte[] digest = buildDigest(data, ods); + String raw_text = CodingHelper.encodeBase64(data);// digest); // data); + return raw_text; + } + + /** + * Fills the holes in the byte ranges with the SIGN_PLACEHOLDER. + * + * @param data + * The given byte ranged data. + * @param byte_ranges + * The byte ranges. + * @return Returns the filled text. + */ + public static byte[] prepareDataToSign(final byte[] data, + final List byte_ranges) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Iterator it = byte_ranges.iterator(); + int last_end = 0; + while (it.hasNext()) + { + StringInfo si = (StringInfo) it.next(); + + for (int i = last_end; i < si.string_start; i++) + { + baos.write(SIGN_PLACEHOLDER); + } + + baos.write(data, si.string_start, si.string_length); + + last_end = si.string_start + si.string_length; + } + byte[] data_to_sign = baos.toByteArray(); + + return data_to_sign; + } + + /** + * Extracts the binary 'text' of a document. + * + *

+ * If the document contains an Egiz Dictionary, which means that it is already + * signed, the binary text is the Base64 coded string of the original document + * followed by the Ascii representation of the signature block. + *

+ *

+ * If the document does not contain an Egiz Dictionary, which means that it is + * unsigned, only the binary Base64 coded original document is returned as + * binary text. + *

+ *

+ * This function is intented for being used instead of the "text extraction" + * mechanism used in the plain text Egiz project. + *

+ * + * @param doc + * The file. + * @return Returns the binary text of the document. + * @throws PDFDocumentException + * Forwarded exception. + */ + public static String extractTextBinary(File doc) throws PDFDocumentException + { + try + { + FileInputStream fis = new FileInputStream(doc); + return extractTextBinary(fis); + } + catch (FileNotFoundException e) + { + throw new PDFDocumentException(202, e); + } + } + + /** + * Extracts the text binary. + * + * @param is + * @return Returns the binary text. + * @throws PDFDocumentException + */ + public static String extractTextBinary(InputStream is) throws PDFDocumentException + { + try + { + // for some stupid reason this produces a read error if the is comes from + // a + // multipart servlet form..??? + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int i = -1; + int acc = 0; + byte[] b = new byte[1000]; + while ((i = is.read(b)) > 0) + { + acc += i; + System.out.print(" " + i); + baos.write(b, 0, i); + } + System.out.println("acc = " + acc); + byte[] pdf = baos.toByteArray(); + + return extractTextBinary(pdf); + } + catch (IOException e) + { + throw new PDFDocumentException(202, e); + } + } + + /** + * Extracts the signable text from a binary pdf document. + * + *

+ * The signable text is the text that will be signed or verified afterwards. + *

+ * + * @param pdf + * The pdf document. + * @return Returns the extracted text String. + * @throws PDFDocumentException + * Forwarded exception. + */ + public static String extractTextBinary(final byte[] pdf) throws PDFDocumentException + { + try + { + PdfReader reader = new PdfReader(new ByteArrayInputStream(pdf)); + PdfDictionary egiz_dict = getEgizDictFromReader(reader); + if (egiz_dict == null) + { + System.out.println("NO Egiz Dict found - whole doc = original doc"); + + int ods = pdf.length; + return retrieveSignableTextFromData(pdf, ods); + } + + String sig_text = extractSignatureTextOnly(egiz_dict); + + int ods = getOriginalDocumentSizeFromEgizDict(egiz_dict); + + String raw_text = retrieveSignableTextFromData(pdf, ods); + raw_text += "\n"; + raw_text += sig_text; + + return raw_text; + } + catch (IOException e) + { + throw new PDFDocumentException(202, e); + } + } + + /** + * Retrieves the List of SignatureHolders containing the information of all + * digital signatures of the given document. + * + *

+ * If the List of SignatureHolders is empty, the document is not signed + * anyways. + *

+ * + * @param pdf + * The complete pdf document. + * @return Returns the List of SignatureHolders. + * @throws PDFDocumentException + * @throws SignatureTypesException + * @throws SignatureException + */ + public static List extractSignatureHoldersBinary(final byte[] pdf) throws PDFDocumentException, SignatureTypesException, SignatureException + { + try + { + PdfReader reader = new PdfReader(new ByteArrayInputStream(pdf)); + List chain = getEgizDictChainFromReader(reader); + + List signatures = new ArrayList(); + Iterator it = chain.iterator(); + while (it.hasNext()) + { + PdfDictionary dict = (PdfDictionary) it.next(); + + int ods = getOriginalDocumentSizeFromEgizDict(dict); + String signature_text = extractSignatureTextOnly(dict); + + SignatureTypes sig_types = SignatureTypes.getInstance(); + List types = sig_types.getSignatureTypeDefinitions(); + SignatureBlock sig_block = new SignatureBlock(types); + boolean could_separate = sig_block.separateBlockFromRawText(signature_text, false); + + if (could_separate) + { + SignatureObject sig_object = sig_block.getSignatureObject(); + + SignatureHolder holder = new BinarySignatureHolder(pdf, ods, sig_object); + signatures.add(holder); + } + } + + return signatures; + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + } + + // /** + // * Signs a document with the given signature table using the Incremental + // * Update method. + // * + // *

+ // * The table containing the signature text will be appended. As specified by + // * the parameters, the signature will be appended to the last page, or a + // plain + // * new page will be created for the signature to hold. + // *

+ // *

+ // * The table will be completely wrapped by an XObject, which will also be + // * indirectly referenced by the Egiz Dictionary. This will ease the + // * verification process. + // *

+ // *

+ // * An Egiz Dictionary will be added to the new document that contains + // * information about the signature. Basically the size of the original + // * document and the reference of the signature table. + // *

+ // * + // * @param original_document + // * The file name of the original document. + // * @param new_document + // * The file name of the new document to be created. + // * @param pdf_table + // * The PdfPTable that contains the signature block. + // * @param pos_x + // * The x position where the table should be inserted. + // * @param pos_y + // * The y position where the table should be inserted (on the last + // * page). If this is negative, a new page will be appended to the + // * document. Then the table will be inserted on that new page using + // * the absolute value of pos_y. Note that pos_y specifies the top + // * line of the table. + // * @throws PresentableException + // * Forwarded exception. + // * + // * @see #writeIncrementalUpdate(byte[], PdfPTable, float, float, boolean) + // */ + // public static void writeIncrementalUpdate(String original_document, + // String new_document, PdfPTable pdf_table, float pos_x, float pos_y, + // int egiz_dict_num_replaces) throws PresentableException + // { + // try + // { + // File original_document_file = new File(original_document); + // FileInputStream fis = new FileInputStream(original_document_file); + // byte[] pdf = new byte[(int) original_document_file.length()]; + // fis.read(pdf); + // fis.close(); + // + // byte[] signed_pdf = writeIncrementalUpdate(pdf, pdf_table, pos_x, pos_y, + // egiz_dict_num_replaces); + // + // File new_document_file = new File(new_document); + // FileOutputStream fos = new FileOutputStream(new_document_file); + // fos.write(signed_pdf); + // fos.close(); + // } + // catch (IOException e) + // { + // throw new PresentableException(e); + // } + // } + + /** + * Signs a document with the given signature table using the Incremental + * Update method. + * + *

+ * The table containing the signature text will be appended. As specified by + * the parameters, the signature will be appended to the last page, or a plain + * new page will be created for the signature to hold. + *

+ *

+ * The table will be completely wrapped by an XObject, which will also be + * indirectly referenced by the Egiz Dictionary. This will ease the + * verification process. + *

+ *

+ * An Egiz Dictionary will be added to the new document that contains + * information about the signature. Basically the size of the original + * document and the reference of the signature table. + *

+ * + * @param original_document + * The original document. + * @param pdf_table + * The PdfPTable that contains the signature block. + * @param pos + * The Position object giving the exact location where to place the + * table. if page is -1, a new page will be appended to the document. + * Then the table will be inserted on that new page using the + * coordinates. + * @return Returns the new document. + * @throws PresentableException + * Forwarded exception. + */ + public static IncrementalUpdateInformation writeIncrementalUpdate( + byte[] original_document, PdfPTable pdf_table, TablePos pos, + List variable_field_definitions, List all_field_definitions) throws PresentableException + { + try + { + IncrementalUpdateInformation iui = new IncrementalUpdateInformation(); + iui.original_document = original_document; + iui.start_index = original_document.length; + + Document.compress = false; + + // System.out.println("wprinz: STAMPING PDF"); + + PdfReader reader = new PdfReader(original_document); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // IMPORTANT: append the new content to the original document using + // incremental updated + // The stamper allows this by setting append = true + PdfStamper stamper = new PdfStamper(reader, baos, '\0', true); + + int pdf_page_num = reader.getNumberOfPages(); + + // int signature_page = -1; + // + // if (pos_y >= 0) + // { + // signature_page = pdf_page_num; + // } + if (pos.page == -1) + { + pos.page = pdf_page_num + 1; + + Rectangle psize = reader.getPageSizeWithRotation(pdf_page_num); + Rectangle rect = new Rectangle(psize); + stamper.insertPage(pos.page, rect); + + // pos_y *= -1; + } + + if (pos.page < 1 || pos.page > stamper.getReader().getNumberOfPages()) + { + throw new PDFDocumentException(224, "The provided pos.page (=" + pos.page + ") is out of range."); + } + PdfContentByte content = stamper.getOverContent(pos.page); + // content = StampContent einer PageStamp. + + // System.out.println("table_width = " + pdf_table.getTotalWidth() + ", + // table_height = " + pdf_table.getTotalHeight()); + + PdfTemplate table_template = content.createTemplate(pdf_table.getTotalWidth(), pdf_table.getTotalHeight()); + + pdf_table.writeSelectedRows(0, -1, 0, pdf_table.getTotalHeight(), table_template); + + // table_template.moveTo(0, 0); + // table_template.lineTo(pdf_table.getTotalWidth(), + // pdf_table.getTotalHeight()); + // table_template.stroke(); + // table_template.moveTo(0, 0); + // table_template.lineTo(100, 100); + // table_template.stroke(); + + // pdf_table.writeSelectedRows(0, -1, SIGNATURE_BORDER / 2, + // table_position, content); + + content.addTemplate(table_template, pos.pos_x, pos.pos_y - pdf_table.getTotalHeight()); + + // For debugging print a 100x100 grid +// { +// Rectangle psize = reader.getPageSizeWithRotation(pos.page); +// float page_width = psize.width(); +// float page_height = psize.height(); +// for (float x = 0; x < page_width; x += 100) +// { +// content.moveTo(x, 0); +// content.lineTo(x, page_height); +// content.stroke(); +// } +// for (float y = 0; y < page_height; y += 100) +// { +// content.moveTo(0, y); +// content.lineTo(page_width, y); +// content.stroke(); +// } +// } + + // content.setLineWidth(10.0f); + // content.moveTo(0, 0); + // content.lineTo(100, 100); + // content.stroke(); + + // PdfIndirectReference page_ref = + // stamper.getWriter().getPageReference(signature_page); + // System.out.println("page_ref = " + page_ref.toString()); + + // PdfObject page_obj = PdfReader.getPdfObject(page_ref); + // System.out.println("page_obj = " + page_obj); + + // PdfDictionary page_dict = (PdfDictionary) page_obj; + // PdfObject resources_obj = page_dict.get(PdfName.RESOURCES); + // System.out.println("resources_obj = " + resources_obj); + // PdfDictionary resources = (PdfDictionary) + // PdfReader.getPdfObject(resources_obj); + // for (Iterator it = resources.getKeys().iterator(); it.hasNext();) + // { + // PdfName key = (PdfName) it.next(); + // PdfObject value = resources.get(key); + // System.out.println(" " + key + " = " + value); + // } + + // add the EGIZ dict: + if (variable_field_definitions != null) + { + createEgizDict(stamper, table_template, iui, variable_field_definitions, all_field_definitions); + } + + stamper.close(); + // System.out.println("wprinz: STAMPING FINISHED"); + + iui.signed_pdf = baos.toByteArray(); + + return iui; + } + catch (IOException e) + { + e.printStackTrace(); + throw new PresentableException(e); + } + catch (DocumentException e) + { + e.printStackTrace(); + throw new PresentableException(e); + } + } + + /** + * Creates the EGIZ Dictionary and adds it to the document. + * + * @param stamper + * The PdfStamper. + * @param table_template + * The Template of the Signature block. + * @param iui + * The IncrementalUpdateInformation. + * @param variable_field_definitions + * The field definitions. + * @throws IOException + * @throws SettingNotFoundException + */ + protected static void createEgizDict(PdfStamper stamper, + PdfTemplate table_template, IncrementalUpdateInformation iui, + List variable_field_definitions, List all_field_definitions) throws IOException, SettingNotFoundException + { + // iui.temp_ir = table_template.getIndirectReference(); + iui.temp_ir_number = table_template.getIndirectReference().getNumber(); + iui.temp_ir_generation = table_template.getIndirectReference().getGeneration(); + + byte[] content_stream = table_template.toPdf(null); + iui.content_stream_length = content_stream.length; + + iui.replaces = determineReplacesInContentStream(content_stream, 0, content_stream.length, variable_field_definitions); + iui.kz_list = determineKZ(content_stream, 0, content_stream.length, all_field_definitions); + + // PdfIndirectReference previous_egiz_dict_ind_ref = + // getEgizDictIndRefFromReader(reader); + + PdfDictionary egiz_dict = new PdfDictionary(EGIZ_DICT_NAME); + egiz_dict.put(EGIZ_XOBJ_NAME, table_template.getIndirectReference()); + egiz_dict.put(EGIZ_ODS_NAME, NUMBER_PLACEHOLDER); + + PdfArray kz_array = new PdfArray(); + for (int i = 0; i < iui.kz_list.size(); i++) + { + kz_array.add(NUMBER_PLACEHOLDER); // start + kz_array.add(NUMBER_PLACEHOLDER); // length + } + egiz_dict.put(EGIZ_KZ_NAME, kz_array); + + int num_replaces = calcNumReps(iui.replaces); + int num_holes = num_replaces + 1 + 1; + // +1 = the /encodings hole + // +1 = the /Cert + int num_byte_ranges = num_holes + 1; + + PdfArray byte_ranges_array = new PdfArray(); + for (int i = 0; i < num_byte_ranges; i++) + { + byte_ranges_array.add(NUMBER_PLACEHOLDER); // start + byte_ranges_array.add(NUMBER_PLACEHOLDER); // length + } + egiz_dict.put(EGIZ_BYTERANGES_NAME, byte_ranges_array); + + PdfArray encodings_array = new PdfArray(); + encodings_array.add(new PdfName(new String(ENCODING_NIL))); // the + // /encodings + encodings_array.add(new PdfName(new String(ENCODING_NIL))); // the /Cert + + // array itself + PdfArray replaces_array = new PdfArray(); + replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the + // /encodings + replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the + // /Cert + + Iterator it = iui.replaces.iterator(); + while (it.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) it.next(); + for (int i = 0; i < ri.replaces.size(); i++) + { + byte[] brev = typeToBrev(ri.sfd.field_name); + String brev_string = new String(brev, "US-ASCII"); + PdfName brev_name = new PdfName(brev_string); + replaces_array.add(brev_name); + + encodings_array.add(new PdfName(new String(ENCODING_WIN, "US-ASCII"))); + } + } + egiz_dict.put(EGIZ_REPLACES_NAME, replaces_array); + + egiz_dict.put(EGIZ_ENCODINGS_NAME, encodings_array); + + PdfArray cert_array = new PdfArray(); + byte[] cert_bytes = new byte[CERTIFICATE_PLACEHOLDER_LENGTH]; + for (int i = 0; i < cert_bytes.length; i++) + { + cert_bytes[i] = 0; + } + PdfString cert_placeholder = new PdfString(cert_bytes); + cert_array.add(cert_placeholder); + egiz_dict.put(EGIZ_CERTIFICATE_NAME, cert_array); + + // if (previous_egiz_dict_ind_ref != null) + // { + // egiz_dict.put(PdfName.PREV, previous_egiz_dict_ind_ref); + // } + // no EGIZ chain + + PdfIndirectObject dict_ref = stamper.getWriter().addToBody(egiz_dict); + // iui.egiz_dict_ir = dict_ref.getIndirectReference(); + iui.egiz_dict_ir_number = dict_ref.getIndirectReference().getNumber(); + iui.egiz_dict_ir_generation = dict_ref.getIndirectReference().getGeneration(); + + PdfIndirectReference root_ref = (PdfIndirectReference) stamper.getReader().getTrailer().get(PdfName.ROOT); + PdfDictionary root = (PdfDictionary) PdfReader.getPdfObject(root_ref); + // root.put(EGIZ_DICT_NAME, dict_ref.getIndirectReference()); + ((PdfStamperImp) stamper.getWriter()).markUsed(root); + + // PdfDictionary extra_cata = stamper.getWriter().getExtraCatalog(); + // extra_cata.put(dict_type, dict_ref.getIndirectReference()); + + ((PdfStamperImp) stamper.getWriter()).setEgizDictTrailerInfo(EGIZ_DICT_NAME, dict_ref.getIndirectReference()); + } + + /** + * Converts a field name (type) to the corresponding BREV. + * + * @param type + * The field name (type). + * @return Returns the corresponding BREV, or BREV_NIL if the type is not + * recognized. + */ + protected static byte[] typeToBrev(String type) + { + if (type.equals(SignatureTypes.SIG_DATE)) + { + return BREV_DAT; + } + if (type.equals(SignatureTypes.SIG_ISSUER)) + { + return BREV_ISS; + } + if (type.equals(SignatureTypes.SIG_VALUE)) + { + return BREV_VAL; + } + if (type.equals(SignatureTypes.SIG_NUMBER)) + { + return BREV_SNR; + } + if (type.equals(SignatureTypes.SIG_ID)) + { + return BREV_SID; + } + + return BREV_NIL; + } + + /** + * Updates the information in the egiz dictionary to reflect the real offsets + * of the byte ranges. + * + *

+ * This replaces the "dummy numbers" in the egiz dictionary with the correct + * values. + *

+ * + * @param iui + * The IncrementalUpdateInformation. + * @throws PDFDocumentException + */ + public static void markByteRanges(IncrementalUpdateInformation iui) throws PDFDocumentException + { + try + { + iui.byte_ranges = new ArrayList(); + + int num_digits = Integer.toString(NUMBER_PLACEHOLDER.intValue()).length(); + byte[] signed_pdf = iui.signed_pdf; + + String str = iui.egiz_dict_ir_number + " " + iui.egiz_dict_ir_generation + " obj"; + byte[] obj_bytes = str.getBytes("US-ASCII"); + int obj_index = ByteArrayUtils.lastIndexOf(signed_pdf, obj_bytes); + int obj_start = obj_index + obj_bytes.length; + + String ods_str = "/ODS "; + byte[] ods_bytes = ods_str.getBytes("US-ASCII"); + int ods_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, ods_bytes); + int ods_start = ods_index + ods_bytes.length; + + String kz_str = "/ID["; + byte[] kz_bytes = kz_str.getBytes("US-ASCII"); + int kz_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, kz_bytes); + int kz_start = kz_index + kz_bytes.length; + + String br_str = "/ByteRange["; + byte[] br_bytes = br_str.getBytes("US-ASCII"); + int br_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, br_bytes); + int array_start = br_index + br_bytes.length; + + String enc_str = "/encodings["; + byte[] enc_bytes = enc_str.getBytes("US-ASCII"); + int enc_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, enc_bytes); + int enc_start = enc_index + enc_bytes.length; + + String cert_str = "/Cert[("; + byte[] cert_bytes = cert_str.getBytes("US-ASCII"); + int cert_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, cert_bytes); + int cert_start = cert_index + cert_bytes.length; + + replaceNumber(signed_pdf, ods_start, signed_pdf.length, num_digits); + + // update the Kennzeichnung byte ranges + int cur_pos = kz_start; + for (int i = 0; i < iui.kz_list.size(); i++) + { + StringInfo si = (StringInfo) iui.kz_list.get(i); + + replaceNumber(signed_pdf, cur_pos, si.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, si.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + } + + int num_replaces = calcNumReps(iui.replaces); + int num_holes = num_replaces + 1 + 1; // +1 = the /encodings hole + // int num_byte_ranges = num_holes + 1; + + cur_pos = array_start; + int cur_br_start = 0; + + // write the /encodings byte range + { + int enc_length = (1 + 3) * num_holes; + + StringInfo byte_range = new StringInfo(); + byte_range.string_start = cur_br_start; + byte_range.string_length = enc_start; + iui.byte_ranges.add(byte_range); + + replaceNumber(signed_pdf, cur_pos, byte_range.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, byte_range.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + + cur_br_start = enc_start + enc_length; + + iui.enc_start = enc_start; + iui.enc_length = enc_length; + } + + // write the /Cert byte range + { + int cert_length = CERTIFICATE_PLACEHOLDER_LENGTH; + + StringInfo byte_range = new StringInfo(); + byte_range.string_start = cur_br_start; + byte_range.string_length = cert_start - cur_br_start; + iui.byte_ranges.add(byte_range); + + replaceNumber(signed_pdf, cur_pos, byte_range.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, byte_range.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + + cur_br_start = cert_start + cert_length; + + iui.cert_start = cert_start; + iui.cert_length = cert_length; + } + + Iterator rit = iui.replaces.iterator(); + while (rit.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) rit.next(); + + // byte [] value_bytes = ri.value.getBytes("ISO-8859-1"); + // int write_pos = 0; + + Iterator sit = ri.replaces.iterator(); + while (sit.hasNext()) + { + StringInfo si = (StringInfo) sit.next(); + + StringInfo byte_range = new StringInfo(); + byte_range.string_start = cur_br_start; + byte_range.string_length = si.string_start - cur_br_start; + iui.byte_ranges.add(byte_range); + + replaceNumber(signed_pdf, cur_pos, byte_range.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, byte_range.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + + cur_br_start = si.string_start + si.string_length; + } + + } + + StringInfo byte_range = new StringInfo(); + byte_range.string_start = cur_br_start; + byte_range.string_length = signed_pdf.length - cur_br_start; + iui.byte_ranges.add(byte_range); + + replaceNumber(signed_pdf, cur_pos, byte_range.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, byte_range.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + + } + + /** + * Replaces the certificate placeholder with the certificate from the signed + * Signature Object. + * + * @param iui + * The IncrementalUpdateInformation. + * @throws PDFDocumentException + */ + public static void replaceCertificate(IncrementalUpdateInformation iui) throws PDFDocumentException + { + X509Cert cert = iui.signed_signature_object.getX509Cert(); + // X509Certificate certificate = cert.getX509Certificate(); + try + { + byte[] encoded = cert.getCertString().getBytes("US-ASCII"); // certificate.getEncoded(); + byte[] escaped = Placeholder.escapePDFString(encoded); + if (escaped.length > iui.cert_length) + { + throw new PlaceholderException("certificate", escaped.length - iui.cert_length); + } + System.arraycopy(escaped, 0, iui.signed_pdf, iui.cert_start, escaped.length); + } + // catch (CertificateEncodingException e) + // { + // throw new PDFDocumentException(300, e); + // } + catch (UnsupportedEncodingException e) + { + throw new PDFDocumentException(300, e); + } + } + + /** + * Replaces the placeholders with values from the signed SignatureObject. + * + * @param iui + * The IncrementalUpdateInformation. + * @throws PDFDocumentException + */ + public static void replacePlaceholders(IncrementalUpdateInformation iui) throws PDFDocumentException + { + final byte[] signed_pdf = iui.signed_pdf; + + // int num_replaces = calcNumReps(iui.replaces); + // int num_holes = num_replaces + 1 + 1; // +1 = the /encodings hole; +1 = + // the + // /Cert + + int encoding_entry_index = 0; + {// /encodings itself + int enc_offset = iui.enc_start + encoding_entry_index * 4; + signed_pdf[enc_offset] = '/'; + System.arraycopy(ENCODING_NIL, 0, signed_pdf, enc_offset + 1, ENCODING_NIL.length); + encoding_entry_index++; + } + {// /Cert itself + int enc_offset = iui.enc_start + encoding_entry_index * 4; + signed_pdf[enc_offset] = '/'; + System.arraycopy(ENCODING_NIL, 0, signed_pdf, enc_offset + 1, ENCODING_NIL.length); + encoding_entry_index++; + } + + for (int i = 0; i < iui.replaces.size(); i++) + { + ReplaceInfo ri = (ReplaceInfo) iui.replaces.get(i); + + try + { + String value = ri.value; + + if (value == null) + { + value = ""; + } + + byte[] encoding = ENCODING_WIN; + byte[] replace_bytes = Placeholder.applyWinAnsiEncoding(value); + + String restored_value = Placeholder.unapplyWinAnsiEncoding(replace_bytes); + if (!value.equals(restored_value)) + { + // debug: + System.out.println("WinAnsiEncoding doesn't fit - using URL instead!"); + // /debug! + + replace_bytes = Placeholder.applyURLEncoding(value); + + encoding = ENCODING_URL; + } + + for (int string_index = 0; string_index < ri.replaces.size(); string_index++) + { + int enc_offset = iui.enc_start + encoding_entry_index * 4; + signed_pdf[enc_offset] = '/'; + System.arraycopy(encoding, 0, signed_pdf, enc_offset + 1, encoding.length); + encoding_entry_index++; + } + + Placeholder.replacePlaceholderWithTolerance(signed_pdf, ri.replaces, replace_bytes, LINE_BREAK_TOLERANCE); + } + catch (PlaceholderException e) + { + throw new PlaceholderException(ri.sfd.field_name, e.getMissing()); + } + + } + } + + /** + * Calculates the number of actual String replaces from a given ReplaceInfo + * list. + *

+ * This is used to determine the number of actual replaces that has to be + * carried out. Accordingly to this number, entries in the dictionary are + * created. + *

+ * + * @param replaces + * The ReplaceInfo list. + * @return Returns the number of string replaces. + */ + protected static int calcNumReps(List replaces) + { + int number = 0; + Iterator it = replaces.iterator(); + while (it.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) it.next(); + number += ri.replaces.size(); + } + return number; + } + + /** + * Determines the List of ReplaceInfo objects of replaces in the content + * stream regarding the given field definitions. + * + *

+ * This method collects all variable String fields in a content stream and + * orders them according to their start offset. + *

+ * + * @param pdf + * The PDF. + * @param begin + * The start of the content stream. + * @param end + * The end of the content stream. + * @param field_definitions + * The field definitions that are counceled to find out which and + * where varaible strings are. + * @return Returns the list of ReplaceInfo objects specifying the variable + * areas. + */ + protected static List determineReplacesInContentStream(final byte[] pdf, + int begin, int end, List field_definitions) + { + List replaces = new ArrayList(); + try + { + + List strings = Placeholder.parseStrings(pdf, begin, end); + + for (int index = 0; index < field_definitions.size(); index++) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) field_definitions.get(index); + + if (sfd.placeholder_length > 0) + { + ReplaceInfo ri = new ReplaceInfo(); + ri.sfd = sfd; + ri.replaces = new ArrayList(); + + byte[] caption = sfd.caption.getBytes("ISO-8859-1"); + + int caption_index = findIndex(strings, caption); + int start_index = skipStrings(strings, caption_index, caption); + int next_index = findFirstNotPlaceholder(strings, start_index); + + for (int i = start_index; i < next_index; i++) + { + StringInfo si = (StringInfo) strings.get(i); + ri.replaces.add(si); + } + + replaces.add(ri); + } + } + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + } + + // sort replaces + Collections.sort(replaces, new Comparator() + { + public int compare(Object arg0, Object arg1) + { + ReplaceInfo ri0 = (ReplaceInfo) arg0; + ReplaceInfo ri1 = (ReplaceInfo) arg1; + int start0 = ((StringInfo) ri0.replaces.get(0)).string_start; + int start1 = ((StringInfo) ri1.replaces.get(0)).string_start; + return start0 - start1; + } + }); + + return replaces; + } + + /** + * Determines the Kennzeichnug in the content stream. + * + * @param pdf + * The PDF. + * @param begin + * The start of the content stream. + * @param end + * The end of the content stream. + * @param field_definitions + * The field definitions. + * @return Returns the List of StringInfo objects representing the KZ field. + * @throws SettingNotFoundException + * F.e. + */ + protected static List determineKZ(final byte[] pdf, int begin, int end, + List field_definitions) throws SettingNotFoundException + { + try + { + List strings = Placeholder.parseStrings(pdf, begin, end); + + for (int index = 0; index < field_definitions.size(); index++) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) field_definitions.get(index); + + if (sfd.field_name.equals(SignatureTypes.SIG_KZ)) + { + List kz_list = new ArrayList(); + + byte[] caption = sfd.caption.getBytes("ISO-8859-1"); + + int caption_index = findIndex(strings, caption); + int start_index = skipStrings(strings, caption_index, caption); + + int end_index = -1; + for (end_index = start_index; end_index < strings.size(); end_index++) + { + StringInfo si = (StringInfo) strings.get(end_index); + + if (startsWithCaption(si, field_definitions)) + { + break; + } + + kz_list.add(si); + } + + return kz_list; + } + } + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + } + throw new SettingNotFoundException(102, "Field " + SignatureTypes.SIG_KZ + " not found."); + } + + /** + * Finds the index of the StringInfo within the StringInfo list that has the + * given content (caption). + * + * @param strings + * The list of StringInfos. + * @param caption + * The text to be matched to the strings. + * @return Returns the index of the found string, or -1 if no string matched. + */ + protected static int findIndex(List strings, byte[] caption) + { + for (int i = 0; i < strings.size(); i++) + { + if (isCaption(strings, i, caption)) + { + return i; + } + } + return -1; + } + + protected static boolean isCaption(List strings, int index, byte[] caption) + { + try + { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = index; i < strings.size(); i++) + { + StringInfo si = (StringInfo) strings.get(i); + baos.write(si.copyStringBytes()); + } + byte[] str_data = baos.toByteArray(); + byte[] unescaped = Placeholder.unescapePDFString(str_data); + if (ByteArrayUtils.compareByteArrays(unescaped, 0, caption)) + { + return true; + } + else + { + return false; + } + } + catch (IOException e) + { + e.printStackTrace(); + return false; + } + + } + + protected static int skipStrings(List strings, int index, byte[] caption) + { + int length = 0; + for (int i = index; i < strings.size(); i++) + { + StringInfo si = (StringInfo) strings.get(i); + length += si.string_length; + + if (length >= caption.length) + { + return i + 1; + } + } + return -1; + } + + /** + * Tells, if the given StringInfo contains only placeholder characters. + * + * @param si + * The StringInfo. + * @param placeholder + * The placeholder character. + * @return Returns true, if the string contains only the given placeholder + * characters, false otherwise. + */ + protected static boolean isPlaceholder(StringInfo si, byte placeholder) + { + byte[] string_bytes = si.copyStringBytes(); + for (int i = 0; i < string_bytes.length; i++) + { + if (string_bytes[i] != placeholder) + { + return false; + } + } + return true; + } + + protected static boolean startsWithCaption(StringInfo si, + List field_definitions) + { + try + { + for (int i = 0; i < field_definitions.size(); i++) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) field_definitions.get(i); + + String caption = sfd.caption; + String str = si.getString("ISO-8859-1"); + + if (caption.startsWith(str)) + { + return true; + } + } + return false; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + return false; + } + } + + /** + * Finds the first string after and at the given index not being a placeholder + * string. + * + * @param strings + * The list of StringInfos. + * @param start + * The index where to start the search. + * @return Returns the index of the first not placeholder string, or + * strings.size() if no more non placeholder strings could be found. + */ + protected static int findFirstNotPlaceholder(List strings, int start) + { + for (int i = start; i < strings.size(); i++) + { + StringInfo si = (StringInfo) strings.get(i); + if (!isPlaceholder(si, LAYOUT_PLACEHOLDER)) + { + return i; + } + } + return strings.size(); + } + + /** + * Restores the given String to its placeholder. + * + * @param pdf + * The PDF. + * @param si + * The string. + * @param placeholder + * The placeholder the string should be filled with. + */ + public static void restorePlaceholder(final byte[] pdf, StringInfo si, + final byte placeholder) + { + byte[] ph = new byte[si.string_length]; + for (int i = 0; i < ph.length; i++) + { + ph[i] = placeholder; + } + System.arraycopy(ph, 0, pdf, si.string_start, ph.length); + } + + /** + * Reconstructs the replaces from the PDF and forms suitable value strings. + * + * @param pdf + * The PDF. + * @param brevs + * The brevs. + * @param sis + * The StringInfo objects of the strings. + * @return Returns the List of ReplaceInfo objects containing the restored + * values. + * @throws PDFDocumentException + */ + public static List reconstructReplaces(final byte[] pdf, byte[][] brevs, + StringInfo[] sis, byte[][] encodings) throws PDFDocumentException + { + try + { + List replaces = new ArrayList(); + + ReplaceInfo cur_ri = null; + + for (int cur = 0; cur < brevs.length; cur++) + { + if (ByteArrayUtils.compareByteArrays(brevs[cur], 0, BREV_NIL)) + { + continue; + } + + if (cur_ri == null || !ByteArrayUtils.compareByteArrays(cur_ri.brev, 0, brevs[cur])) + { + cur_ri = new ReplaceInfo(); + + cur_ri.replaces = new ArrayList(); + + cur_ri.brev = brevs[cur]; + cur_ri.enc = encodings[cur]; + + replaces.add(cur_ri); + } + + cur_ri.replaces.add(sis[cur]); + } + + // restore value Strings + Iterator rit = replaces.iterator(); + while (rit.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) rit.next(); + ri.value = Placeholder.reconstructStringFromPartition(pdf, ri.replaces, ri.enc); + + // System.out.println(new String(ri.brev, "US-ASCII") + ": " + + // ri.value); + } + + return replaces; + } + catch (IOException e) + { + throw new PDFDocumentException(310, e); + } + + } + + /** + * Reads an unsigned integer number. + * + * @param pdf + * The PDF. + * @param start_index + * The start index of the number. + * @param num_digits + * The number of digits. + * @return Returns the read number. + */ + public static int readNumber(final byte[] pdf, final int start_index, + final int num_digits) + { + try + { + byte[] n_bytes = new byte[num_digits]; + System.arraycopy(pdf, start_index, n_bytes, 0, num_digits); + String n_string = new String(n_bytes, "US-ASCII"); + + int n = Integer.parseInt(n_string); + return n; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + return -1; + } + } + + /** + * Replaces a number by the new value. + * + * @param pdf + * The PDF. + * @param start_index + * The start index of the number. + * @param number + * The new number. + * @param num_digits + * The number of digits. + */ + public static void replaceNumber(final byte[] pdf, final int start_index, + final int number, final int num_digits) + { + try + { + if (number < 0) + { + throw new IllegalArgumentException("The given number " + number + " must not be negative."); + } + String number_string = Integer.toString(number); + if (number_string.length() > num_digits) + { + throw new IllegalArgumentException("The given number " + number + " has more than " + num_digits + " digits."); + } + + int leading_zeros = num_digits - number_string.length(); + String zeros_string = ""; + for (int i = 0; i < leading_zeros; i++) + { + zeros_string += "0"; + } + + String total_string = zeros_string + number_string; + byte[] total_bytes = total_string.getBytes("US-ASCII"); + System.arraycopy(total_bytes, 0, pdf, start_index, num_digits); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + } + } + + /** + * For debugging purposes. + * + * @param args + * @throws IOException + */ + public static void main(String[] args) throws IOException + { + File signed_doc = new File("C:/wprinz/temp.pdf"); + + PdfReader reader = new PdfReader(new FileInputStream(signed_doc)); + PdfDictionary egiz_dict = getEgizDictFromReader(reader); + if (egiz_dict == null) + { + System.out.println("NO Egiz Dict"); + return; + } + + String sig_text = extractSignatureTextOnly(egiz_dict); + System.out.println("Sig Text:"); + System.out.println(sig_text); + + int ods = getOriginalDocumentSizeFromEgizDict(egiz_dict); + System.out.println("Original Document Size = " + ods); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignatureHolder.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignatureHolder.java new file mode 100644 index 0000000..1f522ff --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignatureHolder.java @@ -0,0 +1,146 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: BinarySignatureHolder.java,v 1.1 2006/10/11 07:58:28 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; + +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * Data structure that holds the information of one binary signature block, + * which is the signed/signable pdf and the corresponding SignatureObject. + * + *

+ * The actual signed text is computed by Base64 encoding the binary data when + * first requested. + *

+ *

+ * The corresponding getters can be used to retrieve the signed document (e.g. + * for displaying a preview). + *

+ * + * @author wprinz + */ +public class BinarySignatureHolder implements Serializable, SignatureHolder +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7208103904479272760L; + + /** + * The whole pdf this holder was extracted from. + */ + private byte[] signed_pdf = null; + + /** + * The number of bytes that give the signed document. + */ + private int signed_pdf_length = -1; + + /** + * The signed text of this object. + * + *

+ * This is the value that will be signed by the Connector. + *

+ */ + private String signed_text = null; + + /** + * The signature object. + */ + private SignatureObject signature_object = null; + + /** + * Constructor that takes the pdf and the SignatureObject as parameters. + * + * @param pdf + * The pdf data. + * @param length + * The length (number of bytes) of the pdf data to be used for being + * converted into "signed text". + * @param so + * The signed signature object. + */ + public BinarySignatureHolder(final byte[] pdf, final int length, SignatureObject so) + { + this.signed_pdf = pdf; + this.signed_pdf_length = length; + this.signature_object = so; + + this.signed_text = null; + } + + /** + * @see at.knowcenter.wag.egov.egiz.pdf.SignatureHolder#getSignedText() + */ + public String getSignedText() + { + if (this.signed_text == null) + { + computeSignedText(); + } + return this.signed_text; + } + + /** + * @see at.knowcenter.wag.egov.egiz.pdf.SignatureHolder#getSignatureObject() + */ + public SignatureObject getSignatureObject() + { + return this.signature_object; + } + + /** + * Computes or recomputes the signed text from the underlying binary data. + * + *

+ * This usually encodes the binary data of given length in Base64. + *

+ * + *

+ * This is usually called automatically when the signed text is first + * requested. + *

+ */ + protected void computeSignedText() + { + this.signed_text = BinarySignature.retrieveSignableTextFromData(this.signed_pdf, this.signed_pdf_length); + } + + /** + * Returns the signed_pdf. + * @return Returns the signed_pdf. + */ + public byte[] getSignedPdf() + { + return this.signed_pdf; + } + + /** + * Returns the signed_pdf_length. + * @return Returns the signed_pdf_length. + */ + public int getSignedPdfLength() + { + return this.signed_pdf_length; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/EGIZDate.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/EGIZDate.java new file mode 100644 index 0000000..7b71d27 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/EGIZDate.java @@ -0,0 +1,189 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: EGIZDate.java,v 1.1 2006/10/31 08:08:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Represents a signature date and the signing time as can be found in the + * SIG_DATE field. + * + *

+ * This is used to compare date values of signatures. + *

+ * + * @author wprinz + */ +public class EGIZDate +{ + + /** + * The year. + */ + protected int year; + + /** + * The month. + */ + protected int month; + + /** + * The day. + */ + protected int day; + + /** + * The hour. + */ + protected int hour; + + /** + * The minute. + */ + protected int minute; + + /** + * The second. + */ + protected int second; + + /** + * Constructor that fills the date with values. + * + * @param year + * The year. + * @param month + * The month. + * @param day + * The day. + * @param hour + * The hour. + * @param minute + * The minute. + * @param second + * The second. + */ + public EGIZDate(int year, int month, int day, int hour, int minute, int second) + { + this.year = year; + this.month = month; + this.day = day; + this.hour = hour; + this.minute = minute; + this.second = second; + } + + /** + * Parses the date information from a given date value. + * + *

+ * Usually the date value is one extracted from the value of the SIG_DATE + * field. + *

+ * + * @param date_value + * The date value String. + * @return Returns the parsed EGIZDate. An IllegalArgumentException is thrown + * if the date String has an illegal format. + */ + public static EGIZDate parseFromString(String date_value) + { + // find the according RFC standard and cite it + + // BKU writes a Z after the date for some reason. + Pattern date_pattern = Pattern.compile("^\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d[Z]?$"); + Matcher date_matcher = date_pattern.matcher(date_value); + if (!date_matcher.matches()) + { + throw new IllegalArgumentException("The date_value (" + date_value + " has an illegal format."); + } + // for some strange reasons capture groups don't work + + int year = Integer.parseInt(date_value.substring(0, 4)); + int month = Integer.parseInt(date_value.substring(5, 7)); + int day = Integer.parseInt(date_value.substring(8, 10)); + int hour = Integer.parseInt(date_value.substring(11, 13)); + int minute = Integer.parseInt(date_value.substring(14, 16)); + int second = Integer.parseInt(date_value.substring(17, 19)); + + return new EGIZDate(year, month, day, hour, minute, second); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) + { + if (!(obj instanceof EGIZDate)) + { + return false; + } + + return toString().equals(obj.toString()); + } + + /** + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return toString().hashCode(); + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "parsed date = " + year + "-" + month + "-" + day + "T" + hour + ":" + minute + ":" + second; + } + + /** + * Converts the date to a long integer. + * + *

+ * An earlier date is lower than a later date. + *

+ *

+ * E.g. a date in 1999 will get a smaller number than a date in 2006. + *

+ * + * @return Returns the compareable long. + */ + protected long toCompareableLong() + { + return +this.year * 12 * 31 * 24 * 60 * 60 + this.month * 31 * 24 * 60 * 60 + this.day * 24 * 60 * 60 + this.hour * 60 * 60 + this.minute * 60 + this.second; + } + + /** + * Compares this EGIZDate to another EXIZDate. + * + * @param other + * The other EGIZDate. + * @return Returns negative if this date is earlier (lower) than the other + * date. Returns 0 if both dates are equal. Returns positive if this + * date is later (higher) than the other date. + */ + public int compareTo(EGIZDate other) + { + long diff = toCompareableLong() - other.toCompareableLong(); + return (int) diff; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/IncrementalUpdateInformation.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/IncrementalUpdateInformation.java new file mode 100644 index 0000000..cb983cb --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/IncrementalUpdateInformation.java @@ -0,0 +1,152 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: IncrementalUpdateInformation.java,v 1.2 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; +import java.util.List; + +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * This parameter object contains all useful inforamtion the binary incremental + * update methods need to create and replace a binary singature block. + * + *

+ * This class is basically used to transport information about the document from + * the prepareSign to the finishSign of the Signator. In future, this could be + * extended and encapsulated to task proprietary IUI instances. E.g. a + * BinarySignatorIUI, a TextualSignatorIUI, both implementing the core IUI + * interface, but encapsulating Binary or Textual specialities. + *

+ * + * @author wprinz + */ +public class IncrementalUpdateInformation implements Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -5904526956127108035L; + + /** + * The original PDF document. + */ + public byte[] original_document = null; + + /** + * The Singature type to be created. + */ + public String signature_type = null; + + /** + * The signed pdf document. + * + *

+ * This is the original document plus the incremental update block. + *

+ */ + public byte[] signed_pdf = null; + + /** + * The start index of this incremental update block. + */ + int start_index = -1; + + /** + * The indirect reference of the egiz dict. + */ + // PdfIndirectReference egiz_dict_ir = null; + public int egiz_dict_ir_number; + + public int egiz_dict_ir_generation; + + /** + * The List of ReplaceInfo objects specifying the byte ranges where the + * variable data has to be fille in. + */ + public List replaces = null; + + /** + * The List of StringInfo objects specifying the byte ranges that should + * be/were signed. + */ + public List byte_ranges = null; + + /** + * The indirect reference of the signature x-object. + */ + // public PdfIndirectReference temp_ir; + public int temp_ir_number; + + public int temp_ir_generation; + + /** + * The start index of the content stream of the signature x-object. + */ + public int content_stream_start = -1; + + /** + * The length of the content stream of the signature x-object. + */ + public int content_stream_length = -1; + + /** + * The document text for signing. + */ + public String document_text; + + /** + * The SignatureObject containing the variable values after the document text + * has been signed. + *

+ * These values have to be filled in. + *

+ */ + public SignatureObject signed_signature_object; + + /** + * The start of the /encodings array. + */ + public int enc_start = -1; + + /** + * The length of the /encodings array. + */ + public int enc_length = -1; + + /** + * The start of the first /Cert + */ + public int cert_start = -1; + + /** + * The length of the /cert placeholder. + */ + public int cert_length = -1; + + /** + * The list of strings of the KZ. + */ + public List kz_list; + + /** + * The table position. + */ + public TablePos pos; + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java new file mode 100644 index 0000000..bed1b65 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java @@ -0,0 +1,539 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PDFPage.java,v 1.5 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.pdfbox.cos.COSName; +import org.pdfbox.cos.COSStream; +import org.pdfbox.pdmodel.PDPage; +import org.pdfbox.pdmodel.PDResources; +import org.pdfbox.pdmodel.common.PDStream; +import org.pdfbox.pdmodel.graphics.xobject.PDXObject; +import org.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; +import org.pdfbox.util.Matrix; +import org.pdfbox.util.PDFOperator; +import org.pdfbox.util.PDFTextStripper; +import org.pdfbox.util.TextPosition; +import org.pdfbox.util.operator.OperatorProcessor; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; + +/** + * PDFPage is an inner class that is used to calculate the page length of a PDF + * Document page. It extends the PDFTextStripper class and implement one + * interested method: {@link PDFPage#showCharacter(TextPosition)}
+ * This method is called when processing the FileStream. By calling the method + * {@link org.pdfbox.util.PDFStreamEngine#processStream(org.pdfbox.pdmodel.PDPage, org.pdfbox.pdmodel.PDResources, org.pdfbox.cos.COSStream)} + * the implemented method showCharacter is called. + * + * @author wlackner + * @see PDFTextStripper + */ +public class PDFPage extends PDFTextStripper +{ + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(PDFPage.class); + + /** + * The maximum (lowest) y position of a character. + */ + protected float max_character_ypos = Float.NEGATIVE_INFINITY; + + /** + * The maximum (lowest y position of an image. + */ + protected float max_image_ypos = Float.NEGATIVE_INFINITY; + + /** + * The empty constructor. + * + * @throws IOException + */ + public PDFPage() throws IOException + { + super(); + + OperatorProcessor newInvoke = new MyInvoke(); + newInvoke.setContext(this); + operators.put("Do", newInvoke); + } + + // /** + // * You should override this method if you want to perform an action when a + // * string is being shown. + // * + // * @param string The string to display. + // * + // * @throws IOException If there is an error showing the string + // */ + // public void showString( byte[] string ) throws IOException + // { + // float spaceWidth = 0; + // float spacing = 0; + // StringBuffer stringResult = new StringBuffer(string.length); + // + // float characterDisplacement = 0; + // float spaceDisplacement = 0; + // + // PDGraphicsState graphicsState = getGraphicsState(); + // float fontSize = graphicsState.getTextState().getFontSize(); + // float horizontalScaling = + // graphicsState.getTextState().getHorizontalScalingPercent()/100f; + // float rise = graphicsState.getTextState().getRise(); + // final float wordSpacing = graphicsState.getTextState().getWordSpacing(); + // final float characterSpacing = + // graphicsState.getTextState().getCharacterSpacing(); + // float wordSpacingDisplacement = 0; + // + // PDFont font = graphicsState.getTextState().getFont(); + // + // //This will typically be 1000 but in the case of a type3 font + // //this might be a different number + // float glyphSpaceToTextSpaceFactor = 1f/font.getFontMatrix().getValue( 0, 0 + // ); + // Float averageWidth = (Float)fontToAverageWidths.get( font ); + // if( averageWidth == null ) + // { + // averageWidth = new Float( font.getAverageFontWidth() ); + // fontToAverageWidths.put( font, averageWidth ); + // } + // + // Matrix initialMatrix = new Matrix(); + // initialMatrix.setValue(0,0,1); + // initialMatrix.setValue(0,1,0); + // initialMatrix.setValue(0,2,0); + // initialMatrix.setValue(1,0,0); + // initialMatrix.setValue(1,1,1); + // initialMatrix.setValue(1,2,0); + // initialMatrix.setValue(2,0,0); + // initialMatrix.setValue(2,1,rise); + // initialMatrix.setValue(2,2,1); + // + // + // //this + // int codeLength = 1; + // Matrix ctm = graphicsState.getCurrentTransformationMatrix(); + // + // //lets see what the space displacement should be + // spaceDisplacement = (font.getFontWidth( SPACE_BYTES, 0, 1 + // )/glyphSpaceToTextSpaceFactor); + // if( spaceDisplacement == 0 ) + // { + // spaceDisplacement = + // (averageWidth.floatValue()/glyphSpaceToTextSpaceFactor); + // //The average space width appears to be higher than necessary + // //so lets make it a little bit smaller. + // spaceDisplacement *= .80f; + // if( log.isDebugEnabled() ) + // { + // log.debug( "Font: Space From Average=" + spaceDisplacement ); + // } + // } + // int pageRotation = page.findRotation(); + // + // // very strange.... the ctms are multiplied by right, but suddenly the + // textM is multiplied from the left. + // // but: PDF matrices are multiplied from left ==> ctm is wrong + // Matrix trm = initialMatrix.multiply( textMatrix ).multiply( ctm ); + // float x = trm.getValue(2,0); + // float y = trm.getValue(2,1); + // float flipped_y = -y + page.findMediaBox().getHeight(); + // if( pageRotation == 0 ) + // { + // trm.setValue( 2,1, flipped_y ); + // } + // else if( pageRotation == 90 ) + // { + // trm.setValue( 2,0, y ); + // trm.setValue( 2,1, x ); + // } + // else if( pageRotation == 270 ) + // { + // trm.setValue( 2,0, flipped_y ); + // trm.setValue( 2,1, x ); + // } + // for( int i=0; i this.max_character_ypos) + { + this.max_character_ypos = current_y; + //logger_.debug("text.character=" + character + ", y=" + current_y); + // System.err.println(character + "|" + current_y); + } + + // logger_.debug("text.character=" + character + ", y=" + current_y); + // System.err.println(character + "|" + current_y); + } + + // use this funtion getting an unsorted text output + // public void showString(byte[] string) { + // logger_.debug(new String(string)); + // } + + /** + * Returns the calculated page length. + * + * @return the max page length value + */ + public float getMaxPageLength() + { + float max_ypos = Float.NEGATIVE_INFINITY; + + if (this.max_character_ypos > this.max_image_ypos) + { + max_ypos = this.max_character_ypos; + } + else + { + max_ypos = this.max_image_ypos; + } + + return max_ypos; + } + + public class MyInvoke extends OperatorProcessor + { + + public void process(PDFOperator operator, List arguments) throws IOException + { + COSName name = (COSName) arguments.get(0); + logger_.debug(""); + + // PDResources res = context.getResources(); + + Map xobjects = context.getXObjects(); + PDXObject xobject = (PDXObject) xobjects.get(name.getName()); + + PDStream stream = xobject.getPDStream(); + COSStream cos_stream = stream.getStream(); + + COSName subtype = (COSName) cos_stream.getDictionaryObject(COSName.SUBTYPE); + if (subtype.equals(COSName.IMAGE)) + { + logger_.debug("XObject Image"); + + Matrix ctm = context.getGraphicsState().getCurrentTransformationMatrix(); + logger_.debug("ctm = " + ctm); + + Pos [] coordinates = new Pos [] { + new Pos(0, 0, 1), + new Pos(1, 0, 1), + new Pos(0, 1, 1), + new Pos(1, 1, 1) }; + + Pos [] transformed_coordinates = transtormCoordinates(coordinates, ctm); + + float actual_lowest_point = Float.NaN; + + int pageRotation = page.findRotation(); + logger_.debug("PageRotation = " + pageRotation); + if (pageRotation == 0) + { + float min_y = findMinY(transformed_coordinates); + logger_.debug("min_y = " + min_y); + float page_height = page.findMediaBox().getHeight(); + logger_.debug("page_height = " + page_height); + + actual_lowest_point = page_height - min_y; + } + if (pageRotation == 90) + { + float max_x = findMaxX(transformed_coordinates); + logger_.debug("max_x = " + max_x); +// float page_width = page.findMediaBox().getWidth(); +// logger_.debug("page_width = " + page_width); + + actual_lowest_point = max_x; + } + if (pageRotation == 180) + { + float min_y = findMinY(transformed_coordinates); + logger_.debug("min_y = " + min_y); + actual_lowest_point = min_y; + } + if (pageRotation == 270) + { + float min_x = findMinX(transformed_coordinates); + logger_.debug("min_x = " + min_x); +// float page_width = page.findMediaBox().getWidth(); +// logger_.debug("page_width = " + page_width); + + actual_lowest_point = min_x; + } + + + logger_.debug("actual_lowest_point = " + actual_lowest_point); + + if (actual_lowest_point > PDFPage.this.max_image_ypos) + { + PDFPage.this.max_image_ypos = actual_lowest_point; + } + + return; + } + + if (xobject instanceof PDXObjectForm) + { + PDXObjectForm form = (PDXObjectForm) xobject; + COSStream invoke = (COSStream) form.getCOSObject(); + PDResources pdResources = form.getResources(); + PDPage page = context.getCurrentPage(); + if (pdResources == null) + { + pdResources = page.findResources(); + } + + getContext().processSubStream(page, pdResources, invoke); + } + } + } + + public static Pos [] transtormCoordinates (Pos [] coordinates, Matrix m) + { + Pos [] transformed = new Pos [coordinates.length]; + for (int i = 0; i < coordinates.length; i++) + { + transformed[i] = transtormCoordinate(coordinates[i], m); + } + return transformed; + } + + public static Pos transtormCoordinate (Pos pos, Matrix m) + { + Pos transformed = new Pos(); + transformed.x = pos.x * m.getValue(0, 0) + pos.y * m.getValue(1, 0) + pos.z * m.getValue(2, 0); + transformed.y = pos.x * m.getValue(0, 1) + pos.y * m.getValue(1, 1) + pos.z * m.getValue(2, 1); + transformed.z = pos.x * m.getValue(0, 2) + pos.y * m.getValue(1, 2) + pos.z * m.getValue(2, 2); + + logger_.debug(" transformed " + pos + " --> " + transformed); + return transformed; + } + + public static float findMinY (Pos [] coordinates) + { + float min = Float.POSITIVE_INFINITY; + for (int i = 0; i < coordinates.length; i++) + { + if (coordinates[i].y < min) + { + min = coordinates[i].y; + } + } + return min; + } + public static float findMaxX (Pos [] coordinates) + { + float max = Float.NEGATIVE_INFINITY; + for (int i = 0; i < coordinates.length; i++) + { + if (coordinates[i].x > max) + { + max = coordinates[i].x; + } + } + return max; + } + public static float findMinX (Pos [] coordinates) + { + float min = Float.POSITIVE_INFINITY; + for (int i = 0; i < coordinates.length; i++) + { + if (coordinates[i].x < min) + { + min = coordinates[i].x; + } + } + return min; + } + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureCreation.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureCreation.java new file mode 100644 index 0000000..453103b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureCreation.java @@ -0,0 +1,170 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: PDFSignatureCreation.java,v 1.6 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +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.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * This class provides wrapper methods to get an access to abstract PDF documents (PDFSignator). + * There exists many open source libraries and commercial libraries that can implement the abstract + * interface.
+ * This class is to load the corresponding implementation of an abstract PDFSignator class. Therefor + * it seams to be a factory. The factory settings are read from the configuration file calling the + * SettingsReader. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + */ +public class PDFSignatureCreation { + /** + * The abstract signature object + */ + private SignatureObject sigObject_ = null; + /** + * The abstract pdf siganture object + */ + private PDFSignatureObject pdfSigObject_ = null; + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + /** + * The factory class prefix + */ + private final static String CLASS_PREFIX = ".PDFSignatureObject"; + /** + * The factory class prefix of the default library + */ + protected final static String DEFAULT_LIBRARY = "IText"; + /** + * The settings key defined in the settings file + * + * @see SettingsReader + */ + protected final static String SETTINGS_KEY = "pdf.signature.library"; + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(PDFSignatureCreation.class); + + /** + * Load the configuration settings. Load the corresponding class implementation for the abstract + * PDFSignature class. Init with a signature object. + * + * @param sigObject the native signature object + * @throws PDFDocumentException ErrorCode:101 + */ + public PDFSignatureCreation(SignatureObject sigObject) throws PDFDocumentException { + try { + loadSettings(); + } catch (PDFDocumentException e) { + e.setErrorCode(101); + throw e; + } + sigObject_ = sigObject; + } + + /** + * Load the factory implementation. This method trys to load the configured PDF library. + * + * @throws PDFDocumentException + */ + private PDFSignatureObject createPDFSignatureObject() throws PDFDocumentException { + PDFSignatureObject pdf_sig_object = null; + String class_name = this.getClass().getPackage().getName() + getClassName(); + Class pdf_sig_obj_class = null; + try { + pdf_sig_obj_class = Class.forName(class_name); + } catch (ClassNotFoundException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Class not found:" + class_name); + } + throw new PDFDocumentException(203, "Can not load pdf signator library", e); + } + try { + pdf_sig_object = (PDFSignatureObject) pdf_sig_obj_class.newInstance(); + } catch (InstantiationException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Can not instantiate:" + class_name); + } + throw new PDFDocumentException(203, "Can not load pdf signator library", e); + } catch (IllegalAccessException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Can not access:" + class_name); + } + throw new PDFDocumentException(203, "Can not load pdf signator library", e); + } + return pdf_sig_object; + } + + /** + * load the class settings + * + * @throws PDFDocumentException + * @see SettingsReader + */ + private void loadSettings() throws PDFDocumentException { + if (settings_ == null) { + try { + settings_ = SettingsReader.getInstance(); + } catch (SettingsException e) { + String log_message = "Can not load pdf signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new PDFDocumentException(101, log_message, e); + } + } + } + + /** + * Read the class postfix from the configuration file + * + * @return the full qualified class name + */ + private String getClassName() { + String extract_class = settings_.getSetting(SETTINGS_KEY, DEFAULT_LIBRARY); + return CLASS_PREFIX + extract_class; + } + + /** + * Creates a new pdf signature object using the configured pdf library. + * + * @return a new pdf signature object + * @throws PDFDocumentException ErrorCode:203 + */ + public PDFSignatureObject getPDFSignatureObject() throws PDFDocumentException { + if (pdfSigObject_ == null) { + try { + pdfSigObject_ = createPDFSignatureObject(); + } catch (PDFDocumentException e) { + e.setErrorCode(203); + throw e; + } + pdfSigObject_.setSignatorObject(sigObject_); + } + return pdfSigObject_; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObject.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObject.java new file mode 100644 index 0000000..3584820 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObject.java @@ -0,0 +1,50 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: PDFSignatureObject.java,v 1.3 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * Defines an interface to get access to PDF documents. There exists many open source libraries and + * commercial libraries. + * + * @author wlackner + */ +public interface PDFSignatureObject { + public void setSignatorObject(SignatureObject signatorObject); + + /** + * Converts the current abstract signature object in a pdf signature object implementation + * + * @return the converted pdf signature object + * @throws PDFDocumentException + */ + public Object getSignatureObject() throws PDFDocumentException; + + /** + * Converts a abstract signature object in a pdf signature object implementation + * + * @param signatorObject the abstract signatorObject to convert + * @return the converted pdf signature object + * @throws PDFDocumentException + */ + public Object getSignatureObject(SignatureObject signatorObject) throws PDFDocumentException; +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java new file mode 100644 index 0000000..56b5f86 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PDFSignatureObjectIText.java,v 1.5 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ErrorCodeException; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.table.Entry; +import at.knowcenter.wag.egov.egiz.table.Style; +import at.knowcenter.wag.egov.egiz.table.Table; + +import com.lowagie.text.BadElementException; +import com.lowagie.text.Element; +import com.lowagie.text.Font; +import com.lowagie.text.Image; +import com.lowagie.text.Phrase; +import com.lowagie.text.pdf.PdfPCell; +import com.lowagie.text.pdf.PdfPTable; + +/** + * This class is the IText implementation of the PDFSignatureObject interface. + * The class takes an abstract definition of a signature object and convert them + * into a pdf table that is used to sign a pdf document. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.sig.SignatureObject + * @see at.knowcenter.wag.egov.egiz.table.Table + * @see at.knowcenter.wag.egov.egiz.table.Entry + * @see at.knowcenter.wag.egov.egiz.table.Style + * @see com.lowagie.text.pdf.PdfPTable + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + */ +public class PDFSignatureObjectIText implements PDFSignatureObject +{ + + /** + * The default font definition + */ + private static Font DEFAULT_FONT = new Font(Font.HELVETICA, 8, Font.NORMAL); + + /** + * The abstract signature object + */ + private SignatureObject sigObject_ = null; + + /** + * The IText pdf table object + */ + private PdfPTable pdfSigObject_ = null; + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(PDFSignatureObjectIText.class); + + /** + * Map the style align definitions to IText's align statements + */ + private static HashMap alignMap_ = new HashMap(); + + /** + * Map the font definitions to IText's font statements + */ + private static HashMap fontMap_ = new HashMap(); + + /** + * The empty constructor. It loads the ui definitions from signature tables + * and init the align map. + * + * @throws PDFDocumentException + */ + public PDFSignatureObjectIText() throws PDFDocumentException + { + loadSettings(); + initStyleMaps(); + } + + /** + * load the class settings + * + * @throws PDFDocumentException + * @see SettingsReader + */ + private void loadSettings() throws PDFDocumentException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load pdf signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new PDFDocumentException(101, log_message, e); + } + } + } + + /** + * This method initialize the style maps. It maps the style style definitions + * to IText styles. + */ + private void initStyleMaps() + { + alignMap_.put(Style.TOP, new Integer(Element.ALIGN_TOP)); + alignMap_.put(Style.MIDDLE, new Integer(Element.ALIGN_MIDDLE)); + alignMap_.put(Style.BOTTOM, new Integer(Element.ALIGN_BOTTOM)); + alignMap_.put(Style.LEFT, new Integer(Element.ALIGN_LEFT)); + alignMap_.put(Style.CENTER, new Integer(Element.ALIGN_CENTER)); + alignMap_.put(Style.RIGHT, new Integer(Element.ALIGN_RIGHT)); + + fontMap_.put(Style.HELVETICA, new Integer(Font.HELVETICA)); + fontMap_.put(Style.TIMES_ROMAN, new Integer(Font.TIMES_ROMAN)); + fontMap_.put(Style.COURIER, new Integer(Font.COURIER)); + fontMap_.put(Style.NORMAL, new Integer(Font.NORMAL)); + fontMap_.put(Style.BOLD, new Integer(Font.BOLD)); + fontMap_.put(Style.ITALIC, new Integer(Font.ITALIC)); + fontMap_.put(Style.BOLDITALIC, new Integer(Font.BOLDITALIC)); + fontMap_.put(Style.UNDERLINE, new Integer(Font.UNDERLINE)); + fontMap_.put(Style.STRIKETHRU, new Integer(Font.STRIKETHRU)); + } + + /** + * Set the abstract signature definition. + * + * @param signatorObject + * the abstract signator object + * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#setSignatorObject(at.knowcenter.wag.egov.egiz.sig.SignatureObject) + */ + public void setSignatorObject(SignatureObject signatorObject) + { + sigObject_ = signatorObject; + } + + /** + * This method maps the table cell definitions to the pdfCell element. + * + * @param pdfCell + * the pdf cell to be styled + * @param cellStyle + * the abstract style definition + * @see com.lowagie.text.pdf.PdfPCell + * @see at.knowcenter.wag.egov.egiz.table.Style + */ + private void setCellStyle(PdfPCell pdfCell, Style cellStyle) + { + if (cellStyle != null) + { + if (cellStyle.getBgColor() != null) + { + pdfCell.setBackgroundColor(cellStyle.getBgColor()); + } + pdfCell.setPadding(cellStyle.getPadding()); + if (cellStyle.getBorder() > 0) + { + pdfCell.setBorderWidth(cellStyle.getBorder()); + } + else + { + pdfCell.setBorder(0); + } + if (cellStyle.getVAlign() != null) + { + int align = ((Integer) alignMap_.get(cellStyle.getVAlign())).intValue(); + pdfCell.setVerticalAlignment(align); + } + if (cellStyle.getHAlign() != null) + { + int align = ((Integer) alignMap_.get(cellStyle.getHAlign())).intValue(); + pdfCell.setHorizontalAlignment(align); + } + } + } + + /** + * This method maps the cell font definition to the iText Font Object + * + * @param fontString + * @return the corresponding iText Font Object + * @see com.lowagie.text.Font + */ + private Font getCellFont(String fontString) + { + Font font = DEFAULT_FONT; + if (fontString == null) + { + return font; + } + Object cache_font = fontMap_.get(fontString); + if (cache_font != null) + { + return (Font) cache_font; + } + String[] font_arr = fontString.split(","); + if (font_arr.length != 3) + { + return font; + } + Object font_face = fontMap_.get(font_arr[0]); + if (font_face == null) + { + return font; + } + Object font_weight = fontMap_.get(font_arr[2]); + if (font_weight == null) + { + return font; + } + int face = ((Integer) font_face).intValue(); + float height = Float.parseFloat(font_arr[1]); + int weight = ((Integer) font_weight).intValue(); + + font = new Font(face, height, weight); + fontMap_.put(fontString, font); + return font; + } + + /** + * This method visualize an abstract table cell into a corresponding pdf table + * cell. The new pdf table cell is redered and get the style information from + * the abstract cell. Following types can be rendered: + *
    + *
  • text statements
  • + *
  • images
  • + *
  • tables
  • + *
+ * + * @param abstractCell + * the abstract cell definition + * @return the new redererd pdf table cell + * @throws PDFDocumentException + * ErrorCode:220, 221, 222 + * @see com.lowagie.text.pdf.PdfPCell + * @see at.knowcenter.wag.egov.egiz.table.Entry + */ + private PdfPCell renderCell(Entry abstractCell) throws PDFDocumentException + { + PdfPCell pdf_cell = null; + Style cell_style = abstractCell.getStyle(); + switch (abstractCell.getType()) + { + case Entry.TYPE_CAPTION: + case Entry.TYPE_VALUE: + String text = (String) abstractCell.getValue(); + if (text == null) + { + text = ""; + } + String font_string = cell_style.getFont(); + if (abstractCell.getType() == Entry.TYPE_VALUE && cell_style.getValueFont() != null) + { + font_string = cell_style.getValueFont(); + } + Font cell_font = getCellFont(font_string); + Phrase text_phrase = new Phrase(text, cell_font); + pdf_cell = new PdfPCell(text_phrase); + setCellStyle(pdf_cell, cell_style); + break; + case Entry.TYPE_IMAGE: + try + { + String img_ref = (String) abstractCell.getValue(); + String img_location = SettingsReader.relocateFile(img_ref); + File img_file = new File (img_location); + if (!img_file.exists()) + { + logger_.debug("Image file \"" + img_file.getCanonicalPath() + "\" doesn't exist."); + throw new PDFDocumentException(220, "Image file \"" + img_file.getCanonicalPath() + "\" doesn't exist."); + } + Image image = Image.getInstance(img_location); + pdf_cell = new PdfPCell(image, true); + setCellStyle(pdf_cell, cell_style); + } + catch (BadElementException e) + { + if (logger_.isDebugEnabled()) + { + if (logger_.isDebugEnabled()) + { + e.printStackTrace(); + } + } + if (logger_.isEnabledFor(Level.ERROR)) + { + logger_.error("BadElementException:" + e.getMessage()); + } + PDFDocumentException pde = new PDFDocumentException(220, "PDF table can not created"); + throw pde; + } + catch (MalformedURLException e) + { + if (logger_.isDebugEnabled()) + { + e.printStackTrace(); + } + if (logger_.isEnabledFor(Level.ERROR)) + { + logger_.error("MalformedURLException:" + e.getMessage()); + } + PDFDocumentException pde = new PDFDocumentException(221, "PDF table can not created"); + throw pde; + } + catch (IOException e) + { + if (logger_.isDebugEnabled()) + { + e.printStackTrace(); + } + if (logger_.isEnabledFor(Level.ERROR)) + { + logger_.error("Error Code:222 " + ErrorCodeException.getErrorCodeMessage(222) + ". IOException:" + e.getMessage()); + } + PDFDocumentException pde = new PDFDocumentException(222, "PDF table can not created: Image can not loaded"); + throw pde; + } + break; + case Entry.TYPE_TABLE: + Table table = (Table) abstractCell.getValue(); + // inherit the style from the parent table + Style inherit_style = Style.doInherit(table.getStyle(), cell_style); + table.setStyle(inherit_style); + PdfPTable pdf_table = renderTable(table); + pdf_cell = new PdfPCell(pdf_table); + break; + } + return pdf_cell; + } + + /** + * This method visualize an abstract table into a corresponding pdf table. The + * new pdf table is redered and get the style information from the abstract + * cell. + * + * @param abstractTable + * the abstract table definition + * @return the new redererd pdf table cell + * @throws PDFDocumentException + * ErrorCode:220, 221, 222, 223 + * @see com.lowagie.text.pdf.PdfPTable + * @see at.knowcenter.wag.egov.egiz.table.Table + */ + private PdfPTable renderTable(Table abstractTable) throws PDFDocumentException + { + if (abstractTable == null) + { + PDFDocumentException pde = new PDFDocumentException(223, "Table is not defined."); + throw pde; + } + PdfPTable pdf_table = null; + float[] cols = abstractTable.getColsRelativeWith(); + int max_cols = abstractTable.getMaxCols(); + if (cols == null) + { + cols = new float[max_cols]; + // set the column ratio for all columns to 1 + for (int cols_idx = 0; cols_idx < cols.length; cols_idx++) + { + cols[cols_idx] = 1; + } + } + pdf_table = new PdfPTable(cols); + pdf_table.setWidthPercentage(abstractTable.getWidth()); + Style table_style = abstractTable.getStyle(); + setCellStyle(pdf_table.getDefaultCell(), table_style); + + ArrayList rows = abstractTable.getRows(); + for (int row_idx = 0; row_idx < rows.size(); row_idx++) + { + ArrayList row = (ArrayList) rows.get(row_idx); + // logger_.debug("## Row:" + row_idx + " ## of table:" + + // abstractTable.getName()); + for (int entry_idx = 0; entry_idx < row.size(); entry_idx++) + { + Entry cell = (Entry) row.get(entry_idx); + Style inherit_style = Style.doInherit(cell.getStyle(), table_style); + cell.setStyle(inherit_style); + // logger_.debug(cell.toString()); + PdfPCell pdf_cell = renderCell(cell); + if (cell.getColSpan() > 1) + { + pdf_cell.setColspan(cell.getColSpan()); + } + if (cell.isNoWrap()) + { + pdf_cell.setNoWrap(true); + } + // System.err.println("valign:" + pdf_cell.getVerticalAlignment() + " + // halign:" + + // pdf_cell.getHorizontalAlignment()); + pdf_table.addCell(pdf_cell); + } + } + // logger_.debug("render table:" + abstractTable.getName()); + return pdf_table; + } + + /** + * This method creates the pdf table object. It takes the abstract table + * definition from the signature object and render the abstract table. + * + * @param sigObject + * the signature object, the base for the abstract table definition + * @return R + * @throws PDFDocumentException + * ErrorCode:220, 221, 222, 223 + */ + private PdfPTable createPDFSignatureObject(SignatureObject sigObject) throws PDFDocumentException + { + Table table = sigObject.getAbstractTable(); + PdfPTable pdf_table = renderTable(table); + return pdf_table; + } + + /* + * This method search for the table definitions in the settings file an init + * @param sigObject + */ + /* + * private void initTableSettings(SignatureObject sigObject) { String sig_type = + * sigObject.getSignationType(); String table_key = SignatureObject.SIG_OBJ + + * sig_type + ".table."; ArrayList main_rows = settings_.getKeys(table_key + + * "main"); } + */ + + /** + * Converts the current abstract signature object in a pdf signature object + * implementation + * + * @return the converted pdf signature object + * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#getSignatureObject() + */ + public Object getSignatureObject() throws PDFDocumentException + { + if (pdfSigObject_ == null) + { + pdfSigObject_ = (PdfPTable) getSignatureObject(sigObject_); + } + return pdfSigObject_; + } + + /** + * Converts a abstract signature object in a pdf signature object + * implementation + * + * @param sigObject + * the abstract signatorObject to convert + * @return the converted pdf signature object + * @throws PDFDocumentException + * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#getSignatureObject(at.knowcenter.wag.egov.egiz.sig.SignatureObject) + */ + public Object getSignatureObject(SignatureObject sigObject) throws PDFDocumentException + { + // initTableSettings(sigObject); + return createPDFSignatureObject(sigObject); + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java new file mode 100644 index 0000000..8fa3b35 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PDFUtilities.java,v 1.3 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.pdfbox.pdfparser.PDFParser; +import org.pdfbox.pdmodel.PDDocument; +import org.pdfbox.pdmodel.PDPage; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; + +import com.lowagie.text.DocumentException; + +/** + * Contains useful helpers for accessing PDF documents. + * + * @author wprinz + */ +public abstract class PDFUtilities +{ + public static float calculateLastPageLength(final byte[] pdf) throws PDFDocumentException + { + try + { + ByteArrayInputStream original_bais = new ByteArrayInputStream(pdf); + byte [] normalized_pdf = TextualSignature.normalizePDF(original_bais); + + ByteArrayInputStream bais = new ByteArrayInputStream(normalized_pdf); + + PDFParser parser = new PDFParser(bais); + File temporary_dir = SettingsReader.getTemporaryDirectory(); + parser.setTempDirectory(temporary_dir); + parser.parse(); + + PDDocument pdfDocument_ = parser.getPDDocument(); + float last_page_length = calculateLastPageLength(pdfDocument_); + pdfDocument_.close(); + + return last_page_length; + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + catch (DocumentException e) + { + throw new PDFDocumentException(201, e); + } + } + + public static float calculateLastPageLength(PDDocument document) throws IOException + { + int last_page_id = document.getNumberOfPages(); + List allPages = document.getDocumentCatalog().getAllPages(); + PDPage last_page = (PDPage) allPages.get(last_page_id - 1); + + return calculatePageLength(last_page); + } + + public static float calculatePageLength(PDPage page) throws IOException + { + // logger_.debug("Last Page id:" + last_page_id); + // PDPage last_page = (PDPage) allPages.get(0); + PDFPage my_page = new PDFPage(); + my_page.processStream(page, page.findResources(), page.getContents().getStream()); + return my_page.getMaxPageLength(); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Placeholder.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Placeholder.java new file mode 100644 index 0000000..b9c3306 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Placeholder.java @@ -0,0 +1,552 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: Placeholder.java,v 1.5 2006/10/31 08:17:50 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.codec.net.URLCodec; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PlaceholderException; +import at.knowcenter.wag.exactparser.ByteArrayUtils; + +/** + * Helper class that provides functionality for dealing with placeholders and + * replacements in pdf. + * + * @author wprinz + */ +public abstract class Placeholder +{ + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(Placeholder.class); + + /** + * Escapes the String to be a suitable Literal String.. + * + * @param data + * The String to be escaped. + * @return Returns the escaped PDF String. + */ + public static byte[] escapePDFString(byte[] data) + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < data.length; i++) + { + byte[] escaped_bytes = escapeByte(data[i]); + baos.write(escaped_bytes); + } + return baos.toByteArray(); + } + catch (IOException e) + { + e.printStackTrace(); + return null; + } + } + + /** + * Unescapes the PDF String. + * + * @param data + * The escaped String. + * @return Returns the unescaped String. + */ + public static byte[] unescapePDFString(byte[] data) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < data.length; i++) + { + if (data[i] == '\\' && data[i + 1] == '\\') + { + baos.write('\\'); + i++; + continue; + } + if (data[i] == '\\' && data[i + 1] == '(') + + { + baos.write('('); + i++; + continue; + } + if (data[i] == '\\' && data[i + 1] == ')') + { + baos.write(')'); + i++; + continue; + } + baos.write(data[i]); + } + return baos.toByteArray(); + } + + /** + * Reconstructs the string from a partition of placeholders. + * + * @param pdf + * The PDF to read the string from. + * @param sis + * The list of StringInfo objects that specify the bytes of the + * string in the pdf. + * @return Returns the extracted and reconverted string. + * @throws IOException + * Forwarded exception. + */ + public static String reconstructStringFromPartition(byte[] pdf, List sis, + byte[] enc) throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + Iterator it = sis.iterator(); + while (it.hasNext()) + { + StringInfo si = (StringInfo) it.next(); + + for (int i = si.string_start; i < si.string_start + si.string_length; i++) + { + if (pdf[i] != 0) + { + baos.write(pdf[i]); + } + } + } + + baos.close(); + byte[] bytes = baos.toByteArray(); + + byte[] unescaped_bytes = unescapePDFString(bytes); + + if (!ByteArrayUtils.compareByteArrays(enc, 0, BinarySignature.ENCODING_WIN) && !ByteArrayUtils.compareByteArrays(enc, 0, BinarySignature.ENCODING_URL)) + { + String enc_str = new String(enc, "US-ASCII"); + logger_.warn("The encoding " + enc_str + " is not known by this application - trying to proceed anyways."); + } + + String text = new String(unescaped_bytes, "windows-1252"); + + String str = text; + if (ByteArrayUtils.compareByteArrays(enc, 0, BinarySignature.ENCODING_URL)) + { + str = unapplyURLEncoding(str); + } + + return str; + } + + /** + * Prepares the given String to a byte array that can be substituted into the + * placeholder. + * + * @param text + * The text to be prepared for substitution. + * @return Returns the prepared byte array. + */ + public static byte[] applyWinAnsiEncoding(String text) + { + // text = text.replace("\\", "\\\\"); + // text = text.replace("(", "\\("); + // text = text.replace(")", "\\)"); + + byte[] replace_bytes; + try + { + replace_bytes = text.getBytes("windows-1252");// CP1252 = WinAnsiEncoding + + // test the opposite way: + // String restored_string = new String (replace_bytes, "windows-1252"); + // if (!restored_string.equals(text)) + // { + // String url_encoded = URLEncoder.encode(text); + // replace_bytes = url_encoded.getBytes("windows-1252"); + // } + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + return null; + } + return replace_bytes; + } + + /** + * Unapplies the WinAnsi encoding. + * + * @param replace_bytes + * The bytes. + * @return Returns the decoded String. + */ + public static String unapplyWinAnsiEncoding(byte[] replace_bytes) + { + try + { + String text = new String(replace_bytes, "windows-1252"); + + return text; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + return null; + } + + } + + /** + * Applies the URL encoding to the text. + * + * @param text + * The text + * @return Returns the URL and WinAnsi encoded text. + */ + public static byte[] applyURLEncoding(String text) + { + URLCodec utf8_url_codec = new URLCodec("UTF-8"); + String url_encoded = null; + try + { + url_encoded = utf8_url_codec.encode(text, "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("Couldn't url encode : " + text, e); + } + // String url_encoded = URLEncoder.encode(text); + return applyWinAnsiEncoding(url_encoded); + } + + /** + * Unapplies the WinAnsi and URL encoding. + * + * @param winansi_str + * The Winansi and URL text. + * @return Returns the decoded text. + */ + public static String unapplyURLEncoding(String winansi_str) + { + URLCodec utf8_url_codec = new URLCodec("UTF-8"); + String url_decoded = null; + try + { + url_decoded = utf8_url_codec.decode(winansi_str, "UTF-8"); + } + catch (Exception e) + { + throw new RuntimeException("Couldn't url decode : " + winansi_str, e); + } + // String url_decoded = URLDecoder.decode(winansi_str); + return url_decoded; + } + + /** + * Restores the String from a previously prepared byte array. + * + * @param pdf_string + * The byte array. + * @return Returns the unprepared String. + */ + public static String unprepareAndUnescapeString(byte[] pdf_string) + { + try + { + String text = new String(pdf_string, "windows-1252"); + + // This makes problems when "+" appears. + // if (isURLEncoded(text)) + // { + // text = URLDecoder.decode(text); + // } + + text = text.replace("\\)", ")"); + text = text.replace("\\(", "("); + text = text.replace("\\\\", "\\"); + + return text; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + return null; + } + } + + /** + * Checks the presence of typical URL encoded characters to tell if the string + * is URL encoded. + * + *

+ * This heuristic checks if there are any non URL encoded characters in the + * String, like ASCII control characters, which aren't allowed in the + * URLEncoding characterset. + *

+ * + * @param text + * The text under suspicion. + * @return Returns true if the String is URL encoded, false otherwise. + */ + protected static boolean isURLEncoded(String text) + { + if (text.indexOf(' ') >= 0) + { + return false; + } + for (int i = 0; i < text.length(); i++) + { + char c = text.charAt(i); + if (0x00 <= c && c <= 0x1f) + { + return false; + } + if (c == 0x7F) + { + return false; + } + if (0x80 <= c) + { + return false; + } + } + return true; + } + + /** + * Tells, if a break can occur behind the given character. + * + * @param character + * The character. + * @return Returns true, if a break may occur behind the character, false + * otherwise. + */ + protected static boolean canBreakAfter(byte character) + { + return (character == ' ' || character == ',' || character == ';'); + } + + /** + * Scans the given PDF content stream for literal PDF strings. + * + * @param pdf + * The PDF. + * @param stream_start + * The start of the content stream to be scanned. + * @param stream_next + * The end of the content stream. + * @return Returns a list of StringInfo objects specifying the strings that + * could be found. + */ + public static List parseStrings(byte[] pdf, int stream_start, int stream_next) + { + List strings = new ArrayList(); + StringInfo cur_string = null; + for (int i = stream_start; i < stream_next; i++) + { + byte cur_byte = pdf[i]; + + if (cur_byte == '(' && pdf[i - 1] != '\\') + { + cur_string = new StringInfo(); + cur_string.pdf = pdf; + cur_string.string_start = i + 1; + cur_string.string_length = -1; + // logger_.debug("String start = " + cur_string.string_start); + continue; + } + if (cur_byte == ')' && pdf[i - 1] != '\\') + { + cur_string.string_length = i - cur_string.string_start; + // logger_.debug("String length = " + cur_string.string_length); + strings.add(cur_string); + + cur_string = null; + continue; + } + } + + return strings; + } + + /** + * Escapes the data byte if necessary. + * + *

+ * Before bytes can be written into the pdf Strings, they have to be escaped. + * Special care has to be taken that escaped sequences are not split due to + * line breaks. This could have fatal consequences and usually renders the + * whole document invalid. + *

+ * + * @param data + * The data byte to be escaped. + * @return Returns a new byte array escaping the data byte. If the byte needs + * not to be escaped, this new array will contain only the original + * data byte. + */ + public static byte[] escapeByte(byte data) + { + if (data == '\\') + { + return new byte[] { '\\', '\\' }; + } + if (data == '(') + { + return new byte[] { '\\', '(' }; + } + if (data == ')') + { + return new byte[] { '\\', ')' }; + } + return new byte[] { data }; + } + + /** + * Replaces the placeholder with the given String breaking lines with a given + * tolerance. + * + * @param pdf + * The PDF. + * @param sis + * The list of StringInfo objects describing the positions where the + * String should be filled in. + * @param replace_bytes + * The unescaped bytes to be filled in. Escaping is performed by this + * method. + * @param tolerance + * The tolerance for line wrapping. The tolerance counts from the end + * of a StringInfo backwards to its start. If a word that starts + * within the tolerance doesn't fit, it is wrapped into the next + * line. + * @throws PDFDocumentException + * Forwarded exception. + */ + public static void replacePlaceholderWithTolerance(byte[] pdf, List sis, + byte[] replace_bytes, int tolerance) throws PDFDocumentException + { + try + { + // String rep_str = new String(replace_bytes); + + SplitStrings ss = new SplitStrings(pdf, sis); + + int read_index = 0; + while (read_index < replace_bytes.length) + { + if (!ss.isValidLine()) + { + break; + } + + byte[] token = readToken(replace_bytes, read_index); + // String token_str = new String(token); + byte[] escaped_token = escapeToken(token); + + if (ss.fits(escaped_token)) + { + ss.write(escaped_token); + read_index += token.length; + continue; + } + else + { + if (ss.getAvailable() < tolerance) + { + ss.newline(); + continue; + } + else + { + // break the token + for (; read_index < replace_bytes.length; read_index++) + { + byte data = replace_bytes[read_index]; + + byte[] escaped_data = escapeByte(data); + + if (ss.fits(escaped_data)) + { + ss.write(escaped_data); + } + else + { + ss.newline(); + break; + } + } + continue; + + } + } + } + ss.fillRest(); + + if (read_index < replace_bytes.length) + { + logger_.error("The replace string was longer than the reserved placeholder."); + throw new PlaceholderException(null, replace_bytes.length - read_index); + } + + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + + } + + protected static byte[] readToken(byte[] bytes, int index) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (; index < bytes.length; index++) + { + byte data = bytes[index]; + + // byte [] escaped_data = escapeByte(data); + baos.write(data); + + if (canBreakAfter(data)) + { + break; + } + } + + return baos.toByteArray(); + } + + protected static byte[] escapeToken(byte[] token) throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + for (int i = 0; i < token.length; i++) + { + byte[] escaped_data = escapeByte(token[i]); + baos.write(escaped_data); + } + + return baos.toByteArray(); + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Pos.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Pos.java new file mode 100644 index 0000000..4bc1a1a --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Pos.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: Pos.java,v 1.1 2006/08/25 17:10:08 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +/** + * Encapsulation of a position on a PDF page. + * + * @author wprinz + */ +public class Pos +{ + + public float x; + + public float y; + + public float z; + + /** + * Default constructor. + */ + public Pos() + { + } + + /** + * Constructor that sets the coordinates. + * @param xx + * @param yy + * @param zz + */ + public Pos(float xx, float yy, float zz) + { + this.x = xx; + this.y = yy; + this.z = zz; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "(" + this.x + "," + this.y + "," + this.z + ")"; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ReplaceInfo.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ReplaceInfo.java new file mode 100644 index 0000000..849d224 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ReplaceInfo.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ReplaceInfo.java,v 1.1 2006/08/25 17:10:08 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; +import java.util.List; + +import at.knowcenter.wag.egov.egiz.sig.SignatureFieldDefinition; + +/** + * Holds the information requeired to replace a certain value in the document + * completely. + * + * @author wprinz + */ +public class ReplaceInfo implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 7307210282876750431L; + + /** + * The field definition of this value. + */ + public SignatureFieldDefinition sfd = null; + + /** + * The value itself. + */ + public String value = null; + + /** + * The list of Strings this value must be splitted to. + */ + public List replaces = null; + + /** + * The brev of this value. + */ + public byte[] brev = null; + + /** + * The encoding of this value. + */ + public byte[] enc = null; + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SignatureHolder.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SignatureHolder.java new file mode 100644 index 0000000..d7fcce9 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SignatureHolder.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignatureHolder.java,v 1.3 2006/10/11 07:57:58 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * Data structure that holds the information of one signature block, which is + * the signed/signable text and the corresponding SignatureObject. + * + *

+ * Signators and Verifiactors should implement own classes for this interface + * that generate the text to be signed from the underlying data. For example a + * binary signature holder could generate the text to be signed by Base64 + * encoding the binary data. Furthermore this allows to cache the text to be + * signed. + *

+ * + * @author wprinz + */ +public interface SignatureHolder +{ + + /** + * Returns the signed text (verification) or the to-be-signed signable text + * (signation). + * + *

+ * Note that this text must be the one that was actually signed. This text is + * directly passed to the connector for signation/verification. No + * normalization or modification will be / must be done to this text between + * reading out from the signature holder and passing the text to the + * connector. + *

+ * + * @return Returns the signed text or the to-be-signed signable text. + */ + public String getSignedText(); + + /** + * + * @return Returns the SignatureObject containing the issuer, serial number, + * etc. + */ + public SignatureObject getSignatureObject(); + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SplitStrings.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SplitStrings.java new file mode 100644 index 0000000..e3f75f1 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SplitStrings.java @@ -0,0 +1,162 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SplitStrings.java,v 1.1 2006/08/30 14:02:35 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.util.List; + + +/** + * Class that helps filling out the placeholders. + * + *

+ * This class treats a sequence of placeholder StringInfos like a continuous + * data area that can be filled out regarding the boundaries. + *

+ * + * @author wprinz + */ +public class SplitStrings +{ + /** + * The byte used to fill unused bytes in the placeholders. + */ + public static final byte FILL_BYTE = 0; + + /** + * The underlying PDF. + */ + protected byte[] pdf = null; + + /** + * The strings to be filled out. + */ + protected StringInfo[] strings = null; + + /** + * The current string which is written to. + */ + protected int cur_string = 0; + + /** + * The current write position within the current string. + */ + protected int cur_pos = 0; + + /** + * Constructor. + * + * @param pdf + * The underlying PDF. + * @param strings + * The strings to be filled out. + */ + public SplitStrings(byte[] pdf, List strings) + { + this.pdf = pdf; + this.strings = new StringInfo[strings.size()]; + for (int i = 0; i < strings.size(); i++) + { + StringInfo si = (StringInfo) strings.get(i); + this.strings[i] = si; + } + } + + /** + * Returns how many bytes are still available in the current string. + * + * @return Returns the number of bytes that are still available. (positive + * integer, or zero if none are available) + */ + public int getAvailable() + { + return this.strings[this.cur_string].string_length - this.cur_pos; + } + + /** + * Tells, if the whole data would fit into the current string. + * + * @param data + * The data to be matched for fitting + * @return Returns true, if the whole data fits, false otherwise. + */ + public boolean fits(byte[] data) + { + return getAvailable() >= data.length; + } + + /** + * Writes the data into the current string. + * + *

+ * Note that the data must fit in. + *

+ * @param data The data to be written. + */ + public void write(byte[] data) + { + if (!fits(data)) + { + throw new IllegalArgumentException("The data doesn't fit in."); + } + + System.arraycopy(data, 0, pdf, this.strings[this.cur_string].string_start + this.cur_pos, data.length); + + this.cur_pos += data.length; + } + + /** + * Fills the current string with the fill character and moves on to the next + * string. + * + */ + public void newline() + { + int end = this.strings[this.cur_string].string_start + this.strings[this.cur_string].string_length; + for (int i = this.strings[this.cur_string].string_start + this.cur_pos; i < end; i++) + { + pdf[i] = FILL_BYTE; + } + + this.cur_string++; + this.cur_pos = 0; + } + + /** + * Fills all rest bytes with the fill character. + * + *

+ * This should be called when everything is finished to fill all strings properly. + *

+ */ + public void fillRest() + { + while (this.cur_string < this.strings.length) + { + newline(); + } + } + + /** + * Tells, if the current line is valid. + * @return Returns true, if this is a line that can be written to. + */ + public boolean isValidLine () + { + return this.cur_string < this.strings.length; + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StringInfo.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StringInfo.java new file mode 100644 index 0000000..5933e4b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StringInfo.java @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: StringInfo.java,v 1.2 2006/10/11 07:57:58 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; + +/** + * Specifies a certain data area within the pdf. + * + *

+ * Actually this is a byte range, which is used to hold the placeholder ranges + * for later replacement. + *

+ * + * @author wprinz + */ +public class StringInfo implements Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = 5834801907046737048L; + + /** + * The PDF document this range belongs to. + */ + protected byte[] pdf = null; + + /** + * The start offset of the range. + */ + public int string_start = -1; + + /** + * The length of the range. + */ + public int string_length = -1; + + /** + * Copies the bytes of this range to a new byte array. + * + * @return Returns the new byte array. + */ + public byte[] copyStringBytes() + { + byte[] bytes = new byte[this.string_length]; + System.arraycopy(this.pdf, this.string_start, bytes, 0, this.string_length); + return bytes; + } + + /** + * Converts the range into a String. + * + * @return Returns the String. + * @throws UnsupportedEncodingException + * Forwarded exception. + */ + public String getString(String encoding) throws UnsupportedEncodingException + { + byte[] bytes = copyStringBytes(); + return new String(bytes, encoding); + } + + public String toString() + { + try + { + return "(" + this.string_start + "," + this.string_length + ")" + getString("ISO-8859-1"); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + return "(" + this.string_start + "," + this.string_length + ")"; + } + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java new file mode 100644 index 0000000..ba55cdf --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: TablePos.java,v 1.1 2006/08/25 17:10:08 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; + +/** + * Class that holds the exact position where the table should be written to the + * document. + * + * @author wprinz + */ +public class TablePos implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -5299027706623518059L; + + /** + * The page on which the block should be displayed. + */ + public int page = 0; + + /** + * The x position. + */ + public float pos_x = 0.0f; + + /** + * The y position. + */ + public float pos_y = 0.0f; + + /** + * The width of the block. + */ + public float width = 0.0f; + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java new file mode 100644 index 0000000..140a6c3 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java @@ -0,0 +1,177 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: TextualSignature.java,v 1.4 2006/10/31 08:12:45 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import org.pdfbox.pdfparser.PDFParser; +import org.pdfbox.pdmodel.PDDocument; +import org.pdfbox.util.PDFTextStripper; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; + +import com.lowagie.text.Document; +import com.lowagie.text.DocumentException; +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfImportedPage; +import com.lowagie.text.pdf.PdfReader; +import com.lowagie.text.pdf.PdfWriter; + +/** + * Contains helper function for textual signatures. + * + * @author wprinz + */ +public class TextualSignature +{ + + /** + * Extracts the document text from a given pdf. + * + * @param pdf_stream + * The pdf_input stream. + * @return Returns the extracted document text. + * @throws PresentableException + * Forwarded exception. + */ + public static String extractTextTextual(InputStream pdf_stream) throws PresentableException + { + try + { + // logger_.debug("===================================================="); + // logger_.debug("extractText:"); + + // For text extraction, create a temporary object with iText just as the + // one + // created + // when being signed, but of course without adding content. + + + byte[] bytes = normalizePDF(pdf_stream); + + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + + PDFParser parser = new PDFParser(bais); + File temporary_dir = SettingsReader.getTemporaryDirectory(); + parser.setTempDirectory(temporary_dir); + parser.parse(); + + PDDocument doc = parser.getPDDocument(); + + PDFTextStripper stripper = new PDFTextStripper(); + stripper.setSortByPosition(false); + // stripper.setStartPage(4); + // stripper.setEndPage(4); + String text = stripper.getText(doc); + + doc.close(); + + // logger_.debug("text.length = " + text.length()); + // logger_.debug("===================================================="); + + return text; + + } + catch (Exception e) + { + throw new PresentableException(e); + } + } + + /** + * Normalizes a given binary PDF to a version PDFbox can handle correctly. + * + *

+ * PDFbox has serious problems with documents that use incremental updates or + * XObject forms. Therefor use this to remove incremental updates and create a + * streamlined document. + *

+ * + *

+ * Note that this has nothing to do with text normalization. It just unifies + * the PDF documents that are fed into PDFbox for text extraction and page + * length determination. + *

+ * + * @param input_pdf + * The input pdf to be normalized. + * @return Returns the normalized pdf. + * @throws IOException + * @throws DocumentException + */ + public static byte[] normalizePDF(InputStream input_pdf) throws IOException, DocumentException + { + PdfReader reader = new PdfReader(input_pdf); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // For some reason the Reader -> ImportPage -> Writer mechanism produces + // problems en mass. + // The text extractor may not be able to extract proper text from + // documents + // created with + // this method (although it works when a Table is appended)... very + // fragile. + + Document document = new Document(); + + PdfWriter writer = PdfWriter.getInstance(document, baos); + document.open(); + + PdfContentByte cb = writer.getDirectContent(); + for (int page_num = 1; page_num <= reader.getNumberOfPages(); page_num++) + { + Rectangle new_size = reader.getPageSize(page_num); + document.setPageSize(new_size); + document.newPage(); + + PdfImportedPage page = writer.getImportedPage(reader, page_num); + + // note that this will add an xobject form to the doc. + // the xobject form contains the content of the page. + cb.addTemplate(page, 0, 0); + + // wprinz: debugging + // cb.beginText(); + // cb.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, + // BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 14); + // cb.showText("page " + page_num); + // cb.endText(); + // wprinz: end debugging + } + + document.close(); + + // for (int i = 1; i <= reader.getNumberOfPages(); i++) + // { + // Rectangle rect = reader.getBoxSize(i, "bleed"); + // logger_.debug("rect[" + i + "] = " + rect); + // } + + baos.close(); + byte[] normalizedPDF = baos.toByteArray(); + + return normalizedPDF; + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignatureHolder.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignatureHolder.java new file mode 100644 index 0000000..fd56125 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignatureHolder.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: TextualSignatureHolder.java,v 1.1 2006/10/11 07:58:17 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; + +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * Data structure that holds the information of one signature block, which is + * the signed/signable text and the corresponding SignatureObject. + * + * @author wprinz + */ +public class TextualSignatureHolder implements Serializable, SignatureHolder +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7208103904479272760L; + + /** + * The signed text of this object. + * + *

+ * This is the value that will be signed by the Connector. + *

+ */ + private String signed_text = null; + + /** + * The signature object. + */ + private SignatureObject signature_object = null; + + public TextualSignatureHolder(String text, SignatureObject so) + { + this.signed_text = text; + this.signature_object = so; + } + + /** + * @see at.knowcenter.wag.egov.egiz.pdf.SignatureHolder#getSignedText() + */ + public String getSignedText() + { + return this.signed_text; + } + + /** + * @see at.knowcenter.wag.egov.egiz.pdf.SignatureHolder#getSignatureObject() + */ + public SignatureObject getSignatureObject() + { + return this.signature_object; + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Utils.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Utils.java new file mode 100644 index 0000000..c075d45 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Utils.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: Utils.java,v 1.3 2006/10/31 08:13:02 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Abstract class that contains helpful utility functions used by the digital + * signatures. + * + * @author wprinz + */ +public abstract class Utils +{ + + /** + * Extracts the pure content text from a given content stream. + * + *

+ * The pure content text is just an assembly of all strings that occur within the content stream in + * stream order. + * Each of these strings will be set on a new line. + *

+ * + * @param stream_bytes The content stream. + * @return Returns the extracted string. + * @throws IOException Forwarded exception. + */ + public static String extractPureTextFromContentStream( + final byte[] stream_bytes) throws IOException + { + + // logger_.debug("stream_bytes:"); + // logger_.debug(new String(stream_bytes, "US-ASCII")); + // logger_.debug(":end of stream_bytes"); + + final byte OPEN = '('; + final byte CLOSE = ')'; + + StringWriter strwrtr = new StringWriter(); + PrintWriter printer = new PrintWriter(strwrtr); + int open_index = -1; + int close_index = -1; + for (int i = 0; i < stream_bytes.length; i++) + { + if (stream_bytes[i] == OPEN) + { + open_index = i; + continue; + } + if (stream_bytes[i] == CLOSE) + { + close_index = i; + + // logger_.debug("open = " + open_index + ", close = " + + // close_index); + + int len = close_index - open_index - 1; + // logger_.debug("len = " + len); + + byte[] bytes = new byte[len]; + System.arraycopy(stream_bytes, open_index + 1, bytes, 0, len); + + String str = new String(bytes, "ISO-8859-1"); + // logger_.debug("string = " + str); + + printer.println(str); + + continue; + } + } + strwrtr.close(); + String signature_text = new String(strwrtr.getBuffer()); + // logger_.debug(signature_text); + + return signature_text; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java new file mode 100644 index 0000000..a3d8128 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: Connector.java,v 1.3 2006/10/11 07:54:03 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * The basic interface for all connectors. + * + * @author wprinz + */ +public interface Connector +{ + + /** + * Performs a sign. + * + * @param sig_type + * The signature type/profile. + * @param user_name + * The user name for user logging. + * @param text_to_sign + * The text to be signed. + * @return Returns the signed SignatureObject. + * @throws SignatureException + * F.e. + */ + public SignatureObject doSign(String sig_type, String user_name, + String text_to_sign) throws SignatureException; + + /** + * Performs a verify. + * + * @param signed_text + * The signed text to be verified. + * @param sig_obj + * The Signature object. + * @return Returns the SignatureResponse. + * @throws SignatureException + * F.e. + */ + public SignatureResponse doVerify(String signed_text, SignatureObject sig_obj) throws SignatureException; + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java new file mode 100644 index 0000000..f24f3a5 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java @@ -0,0 +1,326 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ConnectorFactory.java,v 1.4 2006/10/31 08:18:12 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.lang.reflect.Field; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.connectors.A1Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorConfigurationKeys; +import at.knowcenter.wag.egov.egiz.sig.connectors.MOAConnector; + +/** + * This is a factory for creating the appropriate connector according to the + * connector identifier. + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorInformation + * @author wprinz + */ +public abstract class ConnectorFactory +{ + /** + * The name of the field that holds the Connector implementation's unique + * identifier. + * + *

+ * This must be a public static final String on the Connector implementation + * class. + *

+ */ + protected static final String CONNECTOR_INFORMATION_FIELD_NAME = "CONNECTOR_INFORMATION"; + + /** + * The list of available Connector implementations. + * + *

+ * Note that this could also be generated dynamically from a config file, + * preferably enveloped by a Singleton. + *

+ */ + protected static Class[] AVAILABLE_CONNECTORS = { MOAConnector.class, + BKUConnector.class, A1Connector.class }; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(ConnectorFactory.class); + + /** + * Retrieves the ConnectorInformation from the connector Class. + * + * @param connector_class + * The connector Class. + * @return Returns the ConnectorInformation. + * @throws IllegalArgumentException + * F.e. + * @throws IllegalAccessException + * F.e. + * @throws SecurityException + * F.e. + * @throws NoSuchFieldException + * F.e. + */ + protected static ConnectorInformation getConnectorInformationFromClass( + Class connector_class) throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException + { + Field type_field = connector_class.getField(CONNECTOR_INFORMATION_FIELD_NAME); + ConnectorInformation connector_information = (ConnectorInformation) type_field.get(null); + return connector_information; + } + + /** + * Gathers the ConnectorInformation objects of all registered connectors. + * + *

+ * This is used by the user interface to provide a list of all available + * connectors. + *

+ * + * @return Returns the ConnectorInformation objects. + * @throws ConnectorFactoryException + * F.e. + */ + public static ConnectorInformation[] getConnectorInformationArray() throws ConnectorFactoryException + { + ConnectorInformation[] coninf = new ConnectorInformation[AVAILABLE_CONNECTORS.length]; + + for (int i = 0; i < coninf.length; i++) + { + try + { + coninf[i] = getConnectorInformationFromClass(AVAILABLE_CONNECTORS[i]); + } + catch (Exception e) + { + throw new ConnectorFactoryException(e); + } + } + + return coninf; + } + + /** + * Retrieves the connector Class belonging to the connector id. + * + * @param connector_identifier + * The connector id. + * @return Returns the corresponding connector class. + * @throws ConnectorFactoryException + * Thrown, if the id is invalid. + */ + protected static Class getConnectorClass(String connector_identifier) throws ConnectorFactoryException + { + ConnectorInformation[] conids = getConnectorInformationArray(); + for (int i = 0; i < conids.length; i++) + { + String connector_id = conids[i].getIdentifier(); + + if (connector_id.equals(connector_identifier)) + { + Class conn_class = AVAILABLE_CONNECTORS[i]; + + return conn_class; + } + } + + throw new ConnectorFactoryException("The connector '" + connector_identifier + "' couldn't be found in the list of available connectors."); + } + + /** + * Creates a new connector given by the connector_identifier. + * + * @param connector_identifier + * The connector identifier of the new connector. + * @return Returns the new connector. + * @throws ConnectorFactoryException + * F.e. + */ + public static Connector createConnector(String connector_identifier) throws ConnectorFactoryException + { + + Class conn_class = getConnectorClass(connector_identifier); + + try + { + Connector connector_obj = (Connector) conn_class.newInstance(); + return connector_obj; + } + catch (Exception e) + { + throw new ConnectorFactoryException(e); + } + } + + /** + * Tells, if the given connector identifier is valid. + * + * @param connector_identifier + * The connector identifier. + * @return Returns true, if the identifier is valid, false otherwise. + * @throws ConnectorFactoryException + * F.e. + */ + public static boolean isValidConnectorIdentifier(String connector_identifier) throws ConnectorFactoryException + { + ConnectorInformation[] conids = getConnectorInformationArray(); + for (int i = 0; i < conids.length; i++) + { + if (conids[i].getIdentifier().equals(connector_identifier)) + { + return true; + } + } + return false; + } + + /** + * Retrieves the availability of the connector from the flags specified in the + * config file. + * + * @param connector_identifier + * The connector. + * @param availability_key + * The key of the availability flag to be retrieved. + * @param default_value + * The default value to be used if the flag is not set in the config + * file. + * @return Returns true, if the flag was set to true, false, if the flag was + * set otherwise, or the default_value if the flag wasn't set at all. + * @throws ConnectorFactoryException + * Thrown, if the connector is invalid. + */ + protected static boolean getAvailabilityUsingDefault(String connector_identifier, + String availability_key, boolean default_value) throws ConnectorFactoryException + { + if (!isValidConnectorIdentifier(connector_identifier)) + { + throw new ConnectorFactoryException("The connector '" + connector_identifier + "' couldn't be found in the list of available connectors."); + } + + SettingsReader settings_ = null; + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new RuntimeException(e); + } + + String value = settings_.getValueFromKey(connector_identifier + "." + availability_key); + if (value == null) + { + return default_value; + } + return value.equals("true"); + } + + /** + * Tells, if the connector is available for being used in the Commandline + * (synchron) environment. + * + *

+ * A connector is available for commandline processing if it requires no + * active user interaction for being executed or if it handles the user + * interaction itself. + *

+ *

+ * A commandline connector is executed synchronously. The client waits until + * the Connector has finished. + *

+ *

+ * Usually a synchron connector can also be used in a web environment. + *

+ *

+ * Examples for commandline connectors are: MOA, BKU. A1 is not suitible for + * commandline because it requires HTTP/HTML interaction, log in, etc. + *

+ * + * @return Returns true, if the Connector is available for Commandline + * processing. + */ + public static boolean isAvailableForCommandline(String connector_identifier) throws ConnectorFactoryException + { + return getAvailabilityUsingDefault(connector_identifier, ConnectorConfigurationKeys.AVAILABLE_FOR_COMMANDLINE, false); + } + + /** + * Tells, if the Connector is available for being used in a Web (asynchron, + * local) environment. + * + *

+ * A connector is available for Web if it can be used in a web environment. + * Often a web connector is also a local connector. + *

+ *

+ * Typical examples are the local BKU and A1. The later requires HTML log in + * and session handling. + *

+ * + * @return Returns true, if the Connector is available for the Web + * application. + */ + public static boolean isAvailableForWeb(String connector_identifier) throws ConnectorFactoryException + { + return getAvailabilityUsingDefault(connector_identifier, ConnectorConfigurationKeys.AVAILABLE_FOR_WEB, false); + } + + /** + * Tells, if the given connector is local. + * + * @param connector_identifier + * The connector. + * @return Returns true, if the given connector is local, false otherwise. + * @throws ConnectorFactoryException + * F.e. + */ + public static boolean isConnectorLocal(String connector_identifier) throws ConnectorFactoryException + { + return connector_identifier.equals("bku") || connector_identifier.equals("a1"); + } + + /** + * Tells, if the given connector needs or produces SIG_IDs. + * + *

+ * This method is used when pre formatted signature blocks have to be created + * that have to know if there will be a SIG_ID field or not. + *

+ *

+ * Connectors like BKU produce SIG_IDs when signing that are needed when + * verifying. + *

+ * + * @param connector + * The connector. + * @return Returns true, if the given connector uses SIG_IDs, false otherwise. + */ + public static boolean needsSIG_ID(String connector) + { + return !connector.equals("moa"); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java new file mode 100644 index 0000000..5855fec --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ConnectorInformation.java,v 1.2 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +/** + * Holds the information of one connectior. + * + *

+ * An implementation of the Connector interface must provide a public static + * final ConnectorInformation field named + * ConnectorFactory#CONNECTOR_INFORMATION_FIELD_NAME that provides the + * information about this connector to the system. + *

+ * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * + * @author wprinz + */ +public class ConnectorInformation implements Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = 5692836392376853268L; + + /** + * The short identifier of the connector (e.g. "bku"). + */ + protected String connector_identifiert = null; + + /** + * The user suitable description of the connector (e.g. + * "Bürgerkartenumgebung"). + */ + protected String connector_description = null; + + /** + * Constructor that initializes this object. + * + * @param identifier + * The short identifier of the connector (e.g. "bku"). + * @param description + * The user suitable description of the connector (e.g. + * "Bürgerkartenumgebung"). + */ + public ConnectorInformation(String identifier, String description) + { + this.connector_identifiert = identifier; + this.connector_description = description; + } + + /** + * Returns the identifier of this connector. + * + * @return Returns the identifier of this connector. + */ + public String getIdentifier() + { + return this.connector_identifiert; + } + + /** + * Returns the description if this connector. + * + * @return Returns the description if this connector. + */ + public String getDescription() + { + return this.connector_description; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java new file mode 100644 index 0000000..7e0834e --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: DummyLDAPAPI.java,v 1.3 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.File; +import java.io.FileInputStream; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; + +/** + * This is just a dummy implementation until the real Egiz LDAP API is + * implemented. + * + * @author wprinz + */ +public class DummyLDAPAPI +{ + String url_ = null; + + public DummyLDAPAPI(String url) + { + this.url_ = url; + } + + public String getURL() + { + return this.url_; + } + + public byte[] loadCertificateFromLDAP(String serial_number, String issuer) + { + //logger.debug("LDAP: serial_number = " + serial_number); + //logger.debug("LDAP: issuer = " + issuer); + + byte[] data = null; + if (serial_number.equals("153868") && issuer.equals("CN=a-sign-TEST-Premium-Sig-01,OU=a-sign-TEST-Premium-Sig-01,O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH,C=AT")) + { + try + { + File test_file = new File(SettingsReader.CERT_PATH + File.separator + "ldap_test_cert.der"); + data = new byte[(int) test_file.length()]; + FileInputStream fis = new FileInputStream(test_file); + fis.read(data); + fis.close(); + } + catch (Exception e) + { + e.printStackTrace(); + data = null; + } + } + + return data; + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java new file mode 100644 index 0000000..13e0b65 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java @@ -0,0 +1,117 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: LocalConnector.java,v 1.2 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * A local connector is a refinement of a "normal" Connector that allows to + * explicitely do the request on a local client. + * + *

+ * Basically the sign and verify procedures of this connector are split into + * three groups: + *

+ *
    + *
  1. Prepare the request to the local service.
  2. + *
  3. Carry out the request on the local client.
  4. + *
  5. Analyze the response from the local client.
  6. + *
+ *

+ * Usually the preparation and the analyzation are carried out on the server, + * whereas the connection to the local service is made from the local client. + *

+ * + * @author wprinz + */ +public interface LocalConnector extends Connector +{ + /** + * Prepares the sign request string. + * + * @param user_name + * The user name. + * @param sign_text + * The text to be signed. + * @param signature_type + * The type of the signature. + * @return Returns the request string to be sent to the local service. + * @throws SignatureException + * F.e. + */ + public String prepareSignRequest(String user_name, String sign_text, + String signature_type) throws SignatureException; + + /** + * Prepares the verify request string. + * + * @param signed_text + * The signed text to be verified. + * @param signature_object + * The SignatureObject. + * @return Returns the request string. + * @throws SignatureException + * F.e. + */ + public String prepareVerifyRequest(String signed_text, + SignatureObject signature_object) throws SignatureException; + + /** + * Analyzes the sign response string. + * + * @param response_string + * The response string from the local service. + * @param signature_type + * The type of the signature. + * @return Returns the SignatureObject of the sign request. + * @throws SignatureException + * F.e. + */ + public SignatureObject analyzeSignResponse(String response_string, + String signature_type) throws SignatureException; + + /** + * Analyzes the verify response string. + * + * @param response_string + * The response string from the local service. + * @return Returns the SignatureResponse of the verify request. + * @throws SignatureException + * F.e. + */ + public SignatureResponse analyzeVerifyResponse(String response_string) throws SignatureException; + + /** + * Returns the sign URL of the local service. + * + * @param profile + * The signature type the URL should be retrieved from. + * @return Returns the sign URL of the local service. + */ + public String getSignURL(String profile); + + /** + * Returns the verify URL of the local service. + * + * @param profile + * The signature type the URL should be retrieved from. + * @return Returns the verify URL of the local service. + */ + public String getVerifyURL(String profile); + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java new file mode 100644 index 0000000..1902458 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignatureBlock.java,v 1.4 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; + +/** + * This method is to analyse a signature block string. It searches for + * configured signature types while compairing defined key words with the text. + * + * @author wlackner + */ +public class SignatureBlock +{ + + /** + * Start index of the signature block text. + */ + private int startIndex_ = -1; + + /** + * End index of the signature block text. + */ + private int endIndex_ = -1; + + /** + * The type of the signature block. + */ + private String type_ = null; + + /** + * The signature type definition object. + */ + private SignatureTypeDefinition sigTypeDef_ = null; + + /** + * The signature block string. + */ + private String signatureString_ = null; + + /** + * The signature object build by the signature string using the signture + * definition. + */ + private SignatureObject signatureObject_ = null; + + /** + * A list of configured signature types. + */ + List signatureTypes_ = null; + + /** + * A list of found keys in the signature block string. + */ + Map foundKeys_ = new HashMap(); + + int maxSize_ = -1; + + /** + * The default constructor to analyse a signature block string. It uses a + * predefined signature type list to assign the text block to signature type. + * The analyse method have to be call separately --> + * separateBlockFromRawText() + * + * @param signatureTypes + */ + public SignatureBlock(List signatureTypes) + { + signatureTypes_ = signatureTypes; + } + + /** + * This method checks if all required keys are found in the signature block + * string. + * + * @param foundKeys + * the keys that are found in the singnature block string + * @return true if all required keys are found, false otherwise + */ + private boolean checkRequiredFields(Map foundKeys) + { + String[] req_keys = SignatureTypes.REQUIRED_SIG_KEYS; + for (int req_idx = 0; req_idx < req_keys.length; req_idx++) + { + String key = req_keys[req_idx]; + // SIG_ID could be optional --> only set in BKU signed documents + if (key.equals(SignatureTypes.SIG_ID)) + { + continue; + } + // logger.debug("check:" + key + "=" + foundKeys.get(key)); + if (foundKeys.get(key) == null) + { + return false; + } + } + return true; + } + + /** + * This method is the base method to analyse a raw text separating a signature + * block string from the raw text. It searches for corresponding signature + * types from back to front in the raw text. Therefore a revert list of + * multiple signations can be extracted calling this method more than one + * times. The method extracts the start and end postition of a found signature + * block and extracts all keys used in that block. If all required fields are + * found a successful separation is done and can be access calling the method + * getStartIndex, getEndIndex, getType, getSignatureObject. + * + * @param rawText + * the raw text to separate a signature block from + * @return true if a separation has done successful false if no signature + * block can be found + */ + public boolean separateBlockFromRawText(String rawText, boolean old_style) + { + endIndex_ = rawText.length(); + boolean found_type = false; + for (int sig_type_idx = 0; sig_type_idx < signatureTypes_.size(); sig_type_idx++) + { + int last_index = endIndex_; + SignatureTypeDefinition sig_type_def = (SignatureTypeDefinition) signatureTypes_.get(sig_type_idx); + //logger.debug("Try sep type:" + sig_type_def.getType()); + + Vector keys = sig_type_def.getRevertSortedKeys(); + Vector captions = sig_type_def.getRevertSortedCaptions(); + Map found_keys = new HashMap(); + for (int key_idx = 0; key_idx < keys.size(); key_idx++) + { + String key = (String) keys.get(key_idx); + if (old_style && key.equals(SignatureTypes.SIG_KZ)) + { + // If separating the old style way - skip The "Kennzeichnung" + // key, because it wasn't present in old profiles. + continue; + } + String caption = (String) captions.get(key_idx); + int found_idx = rawText.lastIndexOf(caption); + //logger.debug("Try find:" + sig_type_def.getType() + "." + key + "." + caption + " at=" + found_idx); + if (found_idx >= 0 && found_idx < last_index) + { + if (key.equals(SignatureTypes.SIG_ID)) + { + //logger.debug("store SIG_ID, but don't decrease last index:" + sig_type_def.getType() + "." + key + "." + caption + " at=" + found_idx); + found_keys.put(key, new Integer(found_idx)); + // don't decrease last index as SIG_ID is not necessarily persistent + } + else + { + //logger.debug("store:" + sig_type_def.getType() + "." + key + "." + caption + " at=" + found_idx); + found_keys.put(key, new Integer(found_idx)); + last_index = found_idx; + } + } + } + if (checkRequiredFields(found_keys) && found_keys.size() > maxSize_) + { + foundKeys_ = found_keys; + sigTypeDef_ = sig_type_def; + type_ = sig_type_def.getType(); + startIndex_ = last_index; + signatureString_ = rawText.substring(startIndex_, endIndex_); + maxSize_ = found_keys.size(); + found_type = true; + } + } + return found_type; + } + + /** + * @return Returns the endIndex. + */ + public int getEndIndex() + { + return endIndex_; + } + + /** + * @return Returns the signatureObject of the separated signature block. + * @throws SignatureException + */ + public SignatureObject getSignatureObject() throws SignatureException + { + if (signatureObject_ == null && foundKeys_ != null) + { + signatureObject_ = new SignatureObject(); + try + { + signatureObject_.setSigType(type_); + signatureObject_.initByType(); + } + catch (SignatureTypesException e) + { + SignatureException se = new SignatureException(101, "Can ot set signation type:" + type_, e); + throw se; + } + String sig_text = signatureString_; + Vector revert_keys = sigTypeDef_.getRevertSortedKeys(); + Vector revert_captions = sigTypeDef_.getRevertSortedCaptions(); + for (int key_idx = 0; key_idx < revert_keys.size(); key_idx++) + { + String key = (String) revert_keys.get(key_idx); + String caption = (String) revert_captions.get(key_idx); + int start_idx = sig_text.lastIndexOf(caption); + if (start_idx >= 0) + { + int sep_idx = start_idx + caption.length(); + // logger.debug(sig_text); + // logger.debug("caption:" + caption + " start_idx:" + start_idx + // + " length:" + + // sig_text.length()); + String value = sig_text.substring(sep_idx); + // logger.debug("key:" + key + " value:" + value); + signatureObject_.setSigValueCaption(key, value, caption); + sig_text = sig_text.substring(0, start_idx); + } + } + } + return signatureObject_; + } + + /** + * @return Returns the startIndex. + */ + public int getStartIndex() + { + return startIndex_; + } + + /** + * @return Returns the type. + */ + public String getType() + { + return type_; + } + +// /** +// * @param endIndex +// * The endIndex to set. +// */ +// private void setEndIndex(int endIndex) +// { +// endIndex_ = endIndex; +// } +// +// /** +// * @param startIndex +// * The startIndex to set. +// */ +// private void setStartIndex(int startIndex) +// { +// startIndex_ = startIndex; +// } +// +// /** +// * @param type +// * The type to set. +// */ +// private void setType(String type) +// { +// type_ = type; +// } + + /** + * The standard toString method. Used for interal tests only. + */ + public String toString() + { + String strg = ""; + strg += "Type:" + type_ + "\n"; + strg += "Start index:" + startIndex_ + "\n"; + strg += "End index:" + endIndex_ + "\n"; + strg += signatureString_ + "\n"; + strg += sigTypeDef_ + "\n"; + try + { + strg += getSignatureObject().toString(); + } + catch (SignatureException e) + { + } + return strg; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java new file mode 100644 index 0000000..2782f2b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java @@ -0,0 +1,155 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: SignatureEntry.java,v 1.3 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +/** + * This class is to store a signature entry. The signature entry is 3-tupel. A key that is defined + * or declarated in the settings file, an optional caption or a value.
+ * An additional helper value is a marker for the start index of the key, if the key is found in an + * analysing process extracting captions and values from a raw signature text. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.sig.SignatureObject + */ +public class SignatureEntry implements Serializable { + + /** + * SVUID. + */ + private static final long serialVersionUID = 4640380069301731879L; + + /** + * The signature key. + */ + private String key_ = null; + /** + * The signature caption for the key found or set in the signature text. + */ + private String caption_ = null; + /** + * The signature value for the key found or set in the signature text. + */ + private String value_ = null; + /** + * The starting index position of the key if it is found in the signature text. + */ + private int startIndex_ = -1; + + /** + * The empty constructor. + */ + public SignatureEntry() { + } + + /** + * A new SignatureEntry init with the key. + * + * @param key + */ + public SignatureEntry(String key) { + key_ = key; + } + + /** + * Returns the caption off the current key. + * + * @return Returns the caption. + */ + public String getCaption() { + return caption_; + } + + /** + * Set the caption of the current key. + * + * @param caption The caption to set. + */ + public void setCaption(String caption) { + caption_ = caption; + } + + /** + * Return the current key. + * + * @return Returns the key. + */ + public String getKey() { + return key_; + } + + /** + * Set the current key. + * + * @param key The key to set. + */ + public void setKey(String key) { + key_ = key; + } + + /** + * Return the start position of the key that caption is found in the signature text. + * + * @return Returns the startIndex. + */ + public int getStartIndex() { + return startIndex_; + } + + /** + * Set the start position of the current key. + * + * @param startIndex The startIndex to set. + */ + public void setStartIndex(int startIndex) { + startIndex_ = startIndex; + } + + /** + * Return the value of the current key. + * + * @return Returns the value. + */ + public String getValue() { + return value_; + } + + /** + * Set the value of the current key. + * + * @param value The value to set. + */ + public void setValue(String value) { + value_ = value; + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() { + String the_string = ""; + the_string += "\n Key:" + key_; + the_string += "\nCaption:" + caption_; + the_string += "\n Value:" + value_; +// the_string += "\nStart I:" + startIndex_; + return the_string; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java new file mode 100644 index 0000000..eacf575 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignatureFieldDefinition.java,v 1.1 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +/** + * This class contains the information about one field in the signature block. + * + *

+ * E.g. Field "Issuer" could have the caption "Aussteller", the value null and + * the placeholder length of 500. + *

+ * + * @author wprinz + */ +public class SignatureFieldDefinition implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -46020173047777315L; + + /** + * The key identifier of this field. + */ + public String field_name = null; + + /** + * The static caption of the field. + */ + public String caption = null; + + /** + * The static value of the field. + * + *

+ * Null means that this field has no static value and must be filled out. + *

+ */ + protected String value = null; + + /** + * If the field is not static and has to be filled out, this gives the + * length of the placeholder that is reserved for filling out. + * + *

+ * This has to be large enough so that it can hold the whole value to be + * filled out. + *

+ */ + public int placeholder_length = -1; + + /** + * Stores the three byte abbreviation code of this field's field name. + */ + //public byte [] brev = null; + + public String toString() + { + return this.field_name + ": caption=" + this.caption + ", value=" + this.value + ", phlen=" + this.placeholder_length; + } + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java new file mode 100644 index 0000000..087ce4e --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java @@ -0,0 +1,1499 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignatureObject.java,v 1.7 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; + +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.InvalidIDException; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.table.Entry; +import at.knowcenter.wag.egov.egiz.table.Style; +import at.knowcenter.wag.egov.egiz.table.Table; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; +import at.knowcenter.wag.egov.egiz.tools.Normalizer; + +/** + * This class represents the abstract signature object. It contains all methods + * reading the definitions from the settings file, analyse them and build the + * abstract signature table.
+ * All values that build or used by the signation creation process, call the + * external services, can read or set separately. All other values are defined + * in the settings file. + * + * @author wlackner + */ +public class SignatureObject implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -3257189232362254713L; + + /** + * The system file separator char + */ + private static final String FILE_SEP = System.getProperty("file.separator"); + + /** + * The certificate extension + */ + private static final String CERT_FILE_EXTENSION = ".der"; + + /** + * certificate import dir + */ + private static final String CERT_ADD_DIR = "tobeadded"; + + /** + * The default style definition for images. + */ + private Style defaultImageStyle_ = new Style(); + + /** + * The default style definition for captions. + */ + private Style defaultCaptionStyle_ = new Style(); + + /** + * The default style definition for values. + */ + private Style defaultValueStyle_ = new Style(); + + /** + * Standard key get/set the signature meta informations + */ + public static final String SIG_META = "SIG_META"; + + /** + * Standard key get/set the certification value + */ + public static final String SIG_CER = "SIG_CER"; + + /** + * Standard key get/set the certification digest value + */ + public static final String SIG_CER_DIG = "SIG_CER_DIG"; + + private X509Cert x509Cert_ = null; + + // public static final String SIG_RES = "SIG_RES"; + // dummy value for debugging only + private String sigResponse_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SignatureObject.class); + + /** + * The normalizer reference + */ + private Normalizer normalizer_ = null; + + /** + * The settings reader reference + */ + private SettingsReader settings_ = null; + + // /** + // * The reference to the settings property tree + // */ + // private PropertyTree pTree_ = null; + /** + * The current signature type used reading and analysing the property tree + */ + private String sigType_ = null; + + /** + * Reference from signature key to there corresponding value + */ + private Hashtable sigEntries_ = new Hashtable(8); + + /** + * The abstract table representation + */ + private Table sigTable_ = null; + + // private HashMap sigIndexMap_ = new HashMap(); + + /** + * Path value storing and fetching the certificates + */ + private String certPath_ = null; + + /** + * the signature definition object + */ + private SignatureTypeDefinition signatureDefinition_ = null; + + /** + * The raw xml response from the connector that was used to set the values in + * this SignatureObject. + * + *

+ * This is set by the Connector so that signing Applications can use the + * returned XML values. + *

+ */ + protected String raw_signature_response = null; + + /** + * The empty constructor. It initilize the normlizer, load the settings and + * set the default styles. + * + * @throws SignatureException + * ErrorCode:101, 400 + */ + public SignatureObject() throws SignatureException + { + initNormalizer(); + loadSettings(); + setDefaultStyles(); + } + + /** + * This method initialize the normalizer + * + * @throws SignatureException + * ErrorCode:400 + */ + private void initNormalizer() throws SignatureException + { + try + { + normalizer_ = new Normalizer(); + } + catch (NormalizeException e) + { + SignatureException se = new SignatureException(400, "Normalizer can not be initialized", e); + throw se; + } + } + + /** + * This method load the signature definitions + * + * @throws SignatureException + * ErrorCode:101 + */ + private void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load pdf signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + SignatureException se = new SignatureException(101, log_message, e); + se.setErrorCode(101); + throw se; + } + } + // pTree_ = settings_.getPTree(); + + certPath_ = SettingsReader.CERT_PATH; + } + + /** + * This method set the default styles for images, captions and values. + */ + private void setDefaultStyles() + { + defaultImageStyle_.setPadding(3); + defaultImageStyle_.setHAlign(Style.CENTER); + defaultImageStyle_.setVAlign(Style.MIDDLE); + defaultImageStyle_.setBgColor(null); + + defaultCaptionStyle_.setHAlign(Style.CENTER); + defaultCaptionStyle_.setVAlign(Style.MIDDLE); + + defaultValueStyle_.setVAlign(Style.MIDDLE); + } + + /** + * Dummy getter Method for debugging only + * + * @return response string + */ + public String getSigResponse() + { + return sigResponse_; + } + + /** + * Dummy setter Method for debugging only + * + * @param sigRespone + * store the response string + */ + public void setSigResponse(String sigRespone) + { + sigResponse_ = sigRespone; + } + + /** + * This method set the signature type. + * + * @param sigType + * the signature type to be set + * @throws SignatureTypesException + */ + public void setSigType(String sigType) throws SignatureTypesException + { + SignatureTypes sig_types = SignatureTypes.getInstance(); + signatureDefinition_ = sig_types.getSignatureTypeDefinition(sigType_); + sigType_ = sigType; + } + + /** + * Returns the default signation type + * + * @return the key for the default signature definition, if the key is not + * found it returns null + */ + private String getDefaultSigType() + { + return settings_.getSetting(SignatureTypes.DEFAULT_TYPE, null); + } + + /** + * This method checks if a given signature key is realy a defined signature + * key. + * + * @param sigKey + * the key to check + * @return true if the key is correct, false if the given key is not defined + */ + public boolean isSigKey(String sigKey) + { + return signatureDefinition_.contains(sigKey); + } + + /** + * This method adds an signaton value to the entry cache. If a key is not in + * the cache a new signature entry is createad. Therefor the method return + * true.
+ * The value that has to be set would be normalized!
+ * If the key equals to SIG_VALUE all whitespaces are + * removed!
+ * + * @param key + * the key to be set + * @param value + * the value to be set + * @return true if a new signature value is created, + * false otherwise + */ + public boolean setSigValue(String key, String value) + { + SignatureEntry sig_entry = null; + boolean is_new = false; + if (sigEntries_.containsKey(key)) + { + sig_entry = (SignatureEntry) sigEntries_.get(key); + } + else + { + sig_entry = new SignatureEntry(key); + sigEntries_.put(key, sig_entry); + is_new = true; + } + value = normalizer_.normalize(value); + if (SignatureTypes.SIG_VALUE.equals(key) || SignatureTypes.SIG_ID.equals(key) || SignatureTypes.SIG_NUMBER.equals(key)) + { + value = removeAllWhiteSpaces(value); + } + sig_entry.setValue(value); + return is_new; + } + + public boolean setValueBruteForce(String key, String value) + { + SignatureEntry sig_entry = null; + boolean is_new = false; + if (sigEntries_.containsKey(key)) + { + sig_entry = (SignatureEntry) sigEntries_.get(key); + } + else + { + sig_entry = new SignatureEntry(key); + sigEntries_.put(key, sig_entry); + is_new = true; + } + sig_entry.setValue(value); + return is_new; + } + + /** + * Set the value and the caption to given key. + * + * @param key + * the key of the signature object + * @param value + * the value of the given key + * @param caption + * the caption of the given key + */ + public void setSigValueCaption(String key, String value, String caption) + { + setSigValue(key, value); + SignatureEntry sig_entry = (SignatureEntry) sigEntries_.get(key); + sig_entry.setCaption(caption); + } + + /** + * This method returns a value for a given signature key. If the key equals to + * SIG_NORM and the value is null the version + * string of the current normalizer is returned! + * + * @param key + * the key to get the value for + * @return a value for the given key + */ + public String getSigValue(String key) + { + String value = null; + if (sigEntries_.containsKey(key)) + { + value = ((SignatureEntry) sigEntries_.get(key)).getValue(); + } + if (value == null && SignatureTypes.SIG_NORM.equals(key)) + { + value = normalizer_.getVersion(); + } + return value; + } + + /** + * Sets the "Kennzeichnung". + * + * @param kz + * The "Kennzeichnung" to be set. + */ + public void setKZ(PdfASID kz) + { + setSigValue(SignatureTypes.SIG_KZ, kz.toString()); + } + + /** + * Returns the "Kennzeichnung" of this signature. + * + * @return Returns the "Kennzeichnung" of this signature. Returns null if + * there is no "Kennzeichnung" or it is not recognized by this + * application. + */ + public PdfASID getKZ() throws InvalidIDException + { + String kz_string = getSigValue(SignatureTypes.SIG_KZ); + if (kz_string == null) + { + return null; + } + PdfASID kz = null; + try + { + kz = new PdfASID(kz_string); + } + catch (InvalidIDException e) + { + e.printStackTrace(); + } + return kz; + } + + /** + * This method returns a caption for a given signature key. If the key exists + * and the coresponding value is null the key itself is + * returned as caption! If the key does not exist the method returns + * null. + * + * @param key + * the key to get the caption for + * @return a caption for the given key + */ + private String getSigCaption(String key) + { + String caption = null; + if (sigEntries_.containsKey(key)) + { + caption = ((SignatureEntry) sigEntries_.get(key)).getCaption(); + if (caption == null) + { + caption = key; + } + } + return caption; + } + + /** + * @return Returns the SignationType. + */ + public String getSignationType() + { + if (sigType_ == null) + { + sigType_ = getDefaultSigType(); + } + return sigType_; + } + + /** + * @return Returns the SignationDate. + */ + public String getSignationDate() + { + return getSigValue(SignatureTypes.SIG_DATE); + } + + /** + * @param sigDate + * The SignationDate to set. + */ + public void setSignationDate(String sigDate) + { + setSigValue(SignatureTypes.SIG_DATE, sigDate); + } + + /** + * @return Returns the SignationName. + */ + public String getSignationName() + { + return getSigValue(SignatureTypes.SIG_NAME); + } + + /** + * @param sigName + * The SignationName to set. + */ + public void setSignationName(String sigName) + { + setSigValue(SignatureTypes.SIG_NAME, sigName); + } + + /** + * @return Returns the SignationNormVersion. + */ + public String getSignationNormVersion() + { + return getSigValue(SignatureTypes.SIG_NORM); + } + + /** + * @param sigNormVersion + * The SignationNormVersion to set. + */ + public void setSignationNormVersion(String sigNormVersion) + { + setSigValue(SignatureTypes.SIG_NORM, sigNormVersion); + } + + /** + * @return Returns the SignationIssuer. + */ + public String getSignationIssuer() + { + String issuer = getSigValue(SignatureTypes.SIG_ISSUER); + X509Cert cert = loadCertificate(getSigValue(SignatureTypes.SIG_NUMBER), issuer); + if (cert != null) + { + setSigValue(SignatureTypes.SIG_ISSUER, cert.getIssuerName()); + setSigValue(SIG_CER, cert.getCertString()); + setSigValue(SIG_CER_DIG, cert.getCertDigest()); + x509Cert_ = cert; + } + issuer = getSigValue(SignatureTypes.SIG_ISSUER); + return issuer; + } + + /** + * @param sigIssuer + * The SignationIssuer to set. + */ + public void setSignationIssuer(String sigIssuer) + { + setSigValue(SignatureTypes.SIG_ISSUER, sigIssuer); + } + + /** + * @return Returns the SignationValue. + */ + public String getSignationValue() + { + return getSigValue(SignatureTypes.SIG_VALUE); + } + + /** + * @param sigValue + * The SignationValue to set. + */ + public void setSignationValue(String sigValue) + { + setSigValue(SignatureTypes.SIG_VALUE, sigValue); + } + + /** + * @return the reference to the signature label + */ + public String getOfficialSeal() + { + return getSigValue(SignatureTypes.SIG_LABEL); + } + + /** + * @param serialNumber + * The serial number of the signature to set + */ + public void setSignationSerialNumber(String serialNumber) + { + setSigValue(SignatureTypes.SIG_NUMBER, serialNumber); + } + + /** + * @return sigNumber the serial number of the signature + */ + public String getSignationSerialNumber() + { + return getSigValue(SignatureTypes.SIG_NUMBER); + } + + /** + * @param certDigest + * set the digest value for the X509Certificate + */ + public void setX509CertificateDigest(String certDigest) + { + setSigValue(SIG_CER_DIG, certDigest); + } + + /** + * This method load the current certificate getting the current SerialNumber + * and the current SignationIssuer.
+ * It stores back the SignationIssuer, X509Certificate and + * X509CertificateDigest + */ + private void loadCurrentCert() + { + X509Cert cert = loadCertificate(getSignationSerialNumber(), getSignationIssuer()); + if (cert != null) + { + setSigValue(SignatureTypes.SIG_ISSUER, cert.getIssuerName()); + setSigValue(SIG_CER, cert.getCertString()); + setSigValue(SIG_CER_DIG, cert.getCertDigest()); + x509Cert_ = cert; + } + } + + /** + * @return the current X509CertificateDigest value. + */ + public String getX509CertificateDigest() + { + String dig = getSigValue(SIG_CER_DIG); + if (dig == null) + { + loadCurrentCert(); + dig = getSigValue(SIG_CER_DIG); + } + return dig; + } + + /** + * @return the current X509v3 certificate string + */ + public String getX509CertificateString() + { + String cert = getSigValue(SIG_CER); + if (cert == null) + { + loadCurrentCert(); + cert = getSigValue(SIG_CER); + } + return cert; + } + + /** + * @param x509Certificate + * The X509v3 certificate of the signature to set + */ + public void setX509Certificate(String x509Certificate) + { + setSigValue(SIG_CER, x509Certificate); + storeCertificate(getSignationSerialNumber(), getSignationIssuer(), x509Certificate, getX509CertificateDigest()); + } + + /** + * return the 509v3 certificate of the given serialNumber and the given issuer + * string + * + * @param serialNumber + * the serialNumber which the certificates should load + * @param issuer + * the issuer which the certificates should load + * @return the X509v3 certificate string + */ + public String getX509CertificateString(String serialNumber, String issuer) + { + X509Cert cert = loadCertificate(serialNumber, issuer); + if (cert != null) + { + return cert.getCertString(); + } + return null; + } + + public X509Cert getX509Cert(String serialNumber, String issuer) + { + return loadCertificate(serialNumber, issuer); + } + + public X509Cert getX509Cert() + { + if (x509Cert_ == null) + { + loadCurrentCert(); + } + return x509Cert_; + } + + /** + * Set the signation id's build by a BKU signated SignatureObject. + * + * @param sigIds + * the string to store. + */ + public void setSignationIDs(String sigIds) + { + setSigValue(SignatureTypes.SIG_ID, sigIds); + } + + /** + * Set the signation id's build by a BKU signated SignatureObject. + * + * @param sigIds + * The sination id's are defined into five parts, that have the same + * base as prefix. Therefore the ids's are reduced by the base prefix + * and stored in the SignatureObject. + */ + public void setSignationIDs(String[] sigIds) + { + String join = ""; + String base = null; + for (int arr_idx = 0; arr_idx < sigIds.length; arr_idx++) + { + String id = sigIds[arr_idx]; + if (logger_.isDebugEnabled()) + { + logger_.debug("Set BKU id:" + id); + } + int id_idx = id.lastIndexOf("-"); + if (arr_idx == 0) + { + base = id.substring(0, id_idx); + } + String cur_id = id.substring(id_idx + 1); + join += "-" + cur_id; + } + setSignationIDs(base + "@" + join.substring(1)); + } + + /** + * Checks if the current SignatureObject is siganted by MOA. It checks if the + * current SignatureObject has a signation id value. + * + * @return true if no signation id value is found, false otherwise + */ + public boolean isMOASigned() + { + return getSignationIds() == null; + } + + /** + * Tells if this SignatureObject is textual. + * + * @return Returns true, if it is textual. + */ + public boolean isTextual() + { + PdfASID kz = null; + try + { + kz = getKZ(); + } + catch (InvalidIDException e) + { + e.printStackTrace(); + } + if (kz == null) + { + return true; // must be an old Signature + } + + boolean textual = kz.getType().equals(SignatorFactory.TYPE_TEXTUAL); + return textual; + } + + /** + * Tells, if this SignatureObject is binary. + * + * @return Returns true, if it is binary. + */ + public boolean isBinary() + { + PdfASID kz = null; + try + { + kz = getKZ(); + } + catch (InvalidIDException e) + { + e.printStackTrace(); + } + if (kz == null) + { + return false; // must be an old Signature + } + + boolean binary = kz.getType().equals(SignatorFactory.TYPE_BINARY); + return binary; + } + + /** + * Takes the signation id value of the current SignatureObject and split them + * into the corresponding id array added with the id-base. + * + * @return the id array + */ + public String[] getSignationIds() + { + String sig_ids = getSigValue(SignatureTypes.SIG_ID); + if (sig_ids == null || sig_ids.length() == 0) + { + return null; + } + + // int index = sig_ids.indexOf(PdfAS.IDS); + // if (index < 0) + // { + // return null; + // } + // sig_ids = sig_ids.substring(index + PdfAS.IDS.length()); + // + // if (sig_ids == null || sig_ids.length() == 0) + // { + // return null; + // } + + String[] ids_str = sig_ids.split("@"); + String base = ids_str[0]; + String[] ids = ids_str[1].split("-"); + String[] real_ids = new String[5]; + real_ids[0] = base + "-" + ids[0]; + real_ids[1] = "0-" + base + "-" + ids[1]; + real_ids[2] = "0-" + base + "-" + ids[2]; + real_ids[3] = "0-" + base + "-" + ids[3]; + real_ids[4] = "0-" + base + "-" + ids[4]; + if (logger_.isDebugEnabled()) + { + for (int id_idx = 0; id_idx < real_ids.length; id_idx++) + { + logger_.debug("Set BKU id:" + real_ids[id_idx]); + } + } + return real_ids; + } + + /** + * This method normalizes the issuer string to support unique issuer string + * for equition. Used to store and find corresponting certificates. + * Normalzing: normalizing the string using the normalizer, remove all white + * spaces, encode as base64 and replace all "/" chars with "_". + * + * @param issuer + * the issuer string to normalize + * @return the normalized issuer string + */ + private String getIssuerFileHash(String issuer) + { + try + { + if (issuer != null) + { + issuer = normalizer_.normalize(issuer); + issuer = removeAllWhiteSpaces(issuer); + // added the ("UTF-8") + issuer = CodingHelper.encodeBase64(CodingHelper.buildDigest(issuer.getBytes("UTF-8"))); + issuer = issuer.replaceAll("/", "_"); + } + return issuer; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + /** + * This method imports new certificates into the certstore path. + */ + private void addNewCertificates() + { + String cert_add_path = certPath_ + CERT_ADD_DIR; + File cert_add_dir = new File(cert_add_path); + if (cert_add_dir.isDirectory()) + { + File[] cert_files = cert_add_dir.listFiles(); + for (int cert_file_idx = 0; cert_file_idx < cert_files.length; cert_file_idx++) + { + File cert_file = cert_files[cert_file_idx]; + if (cert_file.isFile() && cert_file.canRead()) + { + X509Cert cert = X509Cert.initByFile(cert_file); + // System.err.println("isCert:" + cert.isX509Cert() + ":" + + // cert_file.getAbsolutePath()); + if (cert.isX509Cert()) + { + String issuer = cert.getIssuerName(); + String serial_number = cert.getSerialNumber(); + String iss_hash = getIssuerFileHash(issuer); + String cert_store_path = certPath_ + iss_hash; + + File cert_store_dir = new File(cert_store_path); + if (!cert_store_dir.exists()) + { + cert_store_dir.mkdir(); + } + if (cert_store_dir.isDirectory()) + { + String cert_file_name = cert_store_path + FILE_SEP + serial_number + CERT_FILE_EXTENSION; + // boolean store = + FileHelper.writeToFile(cert_file_name, cert.getCertString()); + // System.err.println("store:" + store + ":" + + // cert_file.getAbsolutePath()); + } + } + boolean deleted = cert_file.delete(); + if (deleted == false) + { + System.err.println("couldn't delete:" + cert_file.getAbsolutePath()); + } + } + } + } + } + + /** + * This method load a X509v3 certificate from the filesystem. The reference to + * the stored certificate is build by the serialNumber and the issuer string. + * The issuer string is normalized because if getting this value from a pdf + * extraction it can be splited into more sections or necessary spaces are + * removed. The real issuer value is stored in the certificates meta file. The + * certficate is devided into two files: certificate.der (the binary value) + * and the meta information used in SignatureObjects as well in + * SignatureImages of a signed pdf-document. The storing path of the + * certificate is build by: + *
    + *
  1. normalize the issuer string
  2. + *
  3. reduce all white spaces in the normalized issuer string
  4. + *
  5. build a hash value of this reduced string
  6. + *
  7. code this hash value as base64 value
  8. + *
  9. add the base64 normalized issuer hash value to the certificate base + * store path
  10. + *
  11. add the serialNumber to the cert path
  12. + *
  13. add the .der extension to get the certificate binary
  14. + *
  15. add the .txt extension to get the meta information of + * the certificate
  16. + *
+ * + * The certificate meta file is build by the base64 coded issuer string and + * the cert digest value devided by the @ char. + * + * @param serialNumber + * the file name of the certificate .der|.txt + * @param issuer + * the file path value of the certificate + * @return String array: [0]--> issuer string; [1]-->certificate binary; + * [2]--> cert digest value + */ + private X509Cert loadCertificate(String serialNumber, String issuer) + { + addNewCertificates(); + X509Cert cert = null; + if (issuer != null && serialNumber != null) + { + String iss_hash = getIssuerFileHash(issuer); + String cert_store_path = certPath_ + iss_hash; + String cert_file_name = cert_store_path + FILE_SEP + serialNumber + CERT_FILE_EXTENSION; + if (logger_.isDebugEnabled()) + { + logger_.debug("load certificate:" + cert_file_name); + } + cert = X509Cert.initByFilePath(cert_file_name); + + if (cert == null) + { + logger_.info("The certificate '" + issuer + "', '" + serialNumber + "' wasn't found in the local certificate store - connecting to LDAP."); + + // the certificate wasn't found in the local store + // - load it from the LDAP server. + String normalized_issuer = normalizer_.normalize(issuer); + + byte[] cert_data = loadCertificateFromLDAP(serialNumber, normalized_issuer); + if (cert_data == null) + { + logger_.info("The certificate '" + issuer + "', '" + serialNumber + "' wasn't found on the LDAP server either."); + + return null; + } + + storeNewCertificateInLocalStore(cert_data); + + // load the local cert + cert = X509Cert.initByFilePath(cert_file_name); + + if (cert == null) + { + logger_.debug("The certificate should be loaded here, but is null - something's wrong."); + } + } + } + return cert; + } + + /** + * This is an internal counter for added certificates. + */ + protected static int new_cert_num = 0; + + /** + * Writes the certificate data to a file and stores the file in the local + * certificate store. + * + * @param cert_data + * The binary certificate data. + */ + public void storeNewCertificateInLocalStore(byte[] cert_data) + { + // write the loaded certificate to the add directory + String cert_add_path = certPath_ + CERT_ADD_DIR; + File cert_add_dir = new File(cert_add_path); + if (!cert_add_dir.exists()) + { + cert_add_dir.mkdirs(); + } + File save_file = new File(cert_add_dir, "newcert_" + new_cert_num + ".der"); + new_cert_num++; + try + { + FileOutputStream fos = new FileOutputStream(save_file); + fos.write(cert_data); + fos.close(); + } + catch (IOException e) + { + e.printStackTrace(); + return; + } + + // add the new certificate to the local store + addNewCertificates(); + } + + /** + * Connects to the LDAP server to look for the certificate. + * + * @param serialNumber + * The serial number String of the certificate being sought. E.g. + * "123455676744123432". + * @param issuer + * The issuer String of the certificate being sought. + * + * @return Returns the DER certificate file as can be stored in the local + * repository. Returns null, if the document wasn't found on the + * server. + */ + protected byte[] loadCertificateFromLDAP(String serialNumber, String issuer) + { + String ldap_server_url = null; + try + { + ldap_server_url = settings_.getSetting("ldap.url"); + } + catch (SettingNotFoundException e) + { + e.printStackTrace(); + logger_.info("LDAP server url setting not found."); + return null; + } + logger_.debug("LDAP server url = " + ldap_server_url); + + // TODO connect to LDAP using the EGIZ API. + DummyLDAPAPI api = new DummyLDAPAPI(ldap_server_url); + byte[] cert = api.loadCertificateFromLDAP(serialNumber, issuer); + + return cert; + } + + /** + * This method stores a X509v3 certificate to the filesystem. The reference to + * the stored certificate is build by the serialNumber and the issuer string. + * The issuer string is normalized because if getting this value from a pdf + * extraction it can be splited into more sections or necessary spaces are + * removed. The real issuer value is stored in the certificates meta file. The + * certficate is devided into two files: certificate.der (the binary value) + * and the meta information used in SignatureObjects as well in + * SignatureImages of a signed pdf-document. The storing path of the + * certificate is build by: + *
    + *
  1. normalize the issuer string
  2. + *
  3. reduce all white spaces in the normalized issuer string
  4. + *
  5. build a hash value of this reduced string
  6. + *
  7. code this hash value as base64 value
  8. + *
  9. add the base64 normalized issuer hash value to the certificate base + * store path
  10. + *
  11. add the serialNumber to the cert path
  12. + *
  13. add the .der extension to get the certificate binary
  14. + *
  15. add the .txt extension to get the meta information of + * the certificate
  16. + *
+ * + * The certificate meta file is build by the base64 coded issuer string and + * the cert digest value devided by the @ char. + * + * @param serialNumber + * the file name of the certificate .der|.txt + * @param issuer + * the issuer string for the file path value of the certificate and + * for metainformation + * @param x509Certificate + * the x509v3 binary string + * @param x509Digest + * the digest value of the given x509Certificate + * @return true the certificate is stored completely, false otherwise + */ + private boolean storeCertificate(String serialNumber, String issuer, + String x509Certificate, String x509Digest) + { + boolean store_complete = false; + if (issuer != null && serialNumber != null) + { + // String issuer_b64 = CodingHelper.encodeBase64(issuer.getBytes()); + String iss_hash = getIssuerFileHash(issuer); + File cert_path_dir = new File(certPath_); + if (!cert_path_dir.exists()) + { + cert_path_dir.mkdir(); + } + String cert_store_path = certPath_ + iss_hash; + File cert_store_dir = new File(cert_store_path); + if (!cert_store_dir.exists()) + { + cert_store_dir.mkdir(); + } + if (cert_store_dir.isDirectory()) + { + String cert_file_name = cert_store_path + FILE_SEP + serialNumber + CERT_FILE_EXTENSION; + if (logger_.isInfoEnabled()) + { + logger_.info("store certificate:" + cert_file_name); + } + boolean store_cert_file = FileHelper.writeToFile(cert_file_name, x509Certificate); + store_complete = store_cert_file;// && store_cert_meta; + } + } + return store_complete; + } + + /** + * @return Returns the AbstractTable. + * @see at.knowcenter.wag.egov.egiz.table.Table + */ + public Table getAbstractTable() + { + if (sigTable_ == null) + { + sigTable_ = createSigTable(SignatureTypes.MAIN_TABLE); + } + return sigTable_; + } + + /** + * This method read the style definitions from the settings file. + * + * @param styleKey + * the key to read the style definitions + * @return the defined style informations + * @see at.knowcenter.wag.egov.egiz.table.Style + */ + private Style readStyle(String styleKey) + { + ArrayList styles = settings_.getKeys(styleKey); + Style style = new Style(); + for (int style_idx = 0; style_idx < styles.size(); style_idx++) + { + String style_id = (String) styles.get(style_idx); + String style_val = settings_.getSetting(styleKey + "." + style_id, null); + style.setStyle(style_id, style_val); + } + return style; + } + + /** + * This method creates an abstract signature table object. It takes all keys + * and values set by the signature object to create the corresponding abstract + * table object. The table definition is read from the settings file. + * + * @param tableKey + * is the name of the table definition in the settings file + * @return a new abstract signature table + * @see at.knowcenter.wag.egov.egiz.table.Style + * @see at.knowcenter.wag.egov.egiz.table.Table + * @see at.knowcenter.wag.egov.egiz.table.Entry + */ + private Table createSigTable(String tableKey) + { + String table_key_prefix = SignatureTypes.SIG_OBJ + getSignationType() + "." + SignatureTypes.TABLE; + String table_key = table_key_prefix + tableKey; + // String caption_prefix = SignatureTypes.SIG_OBJ + getSignationType() + + // ".key."; + // String value_prefix = SignatureTypes.SIG_OBJ + getSignationType() + + // ".value."; + // ArrayList table_def_keys = settings_.getKeys(table_key); + Vector table_def_keys = settings_.getSettingKeys(table_key); + if (table_def_keys == null) + { + return null; + } + Table sig_table = new Table(tableKey); + boolean found_style = false; + for (int table_key_idx = table_def_keys.size() - 1; table_key_idx >= 0; table_key_idx--) + { + String table_def = (String) table_def_keys.get(table_key_idx); + int dot_idx = (table_def.indexOf(".") > 0 ? table_def.indexOf(".") : table_def.length()); + table_def = table_def.substring(0, dot_idx); + String table_def_keys_prefix = table_key + "." + table_def; + String table_def_string = settings_.getSetting(table_def_keys_prefix, null); + if (table_def.matches("\\D*")) + { + // if the table key is not a number (row number index) + if (SignatureTypes.COLS_WITH.equals(table_def)) + { + String[] cols_s = table_def_string.split(" "); + float[] cols_f = new float[cols_s.length]; + for (int i = 0; i < cols_s.length; i++) + { + cols_f[i] = Float.parseFloat(cols_s[i]); + } + sig_table.setColsRelativeWith(cols_f); + } + if (SignatureTypes.STYLE.equals(table_def) && !found_style) + { + Style style = readStyle(table_def_keys_prefix); + sig_table.setStyle(style); + found_style = true; + } + continue; + } + if (table_def_string != null) + { + // analyse the row definition + String[] elems = table_def_string.split("\\|"); + ArrayList row = new ArrayList(); + for (int elem_idx = 0; elem_idx < elems.length; elem_idx++) + { + String elem = elems[elem_idx]; + String[] key_type = elem.split("-"); + if (key_type.length < 2) + { + return null; + } + String key = key_type[0]; + String type = key_type[1]; + if (SignatureTypes.TYPE_TABLE.equals(key)) + { + // add a table entry + Table table = createSigTable(type); + if (table != null) + { + Entry entry = new Entry(Entry.TYPE_TABLE, table, key); + row.add(entry); + } + } + if (SignatureTypes.TYPE_IMAGE.equals(type)) + { + // add an image entry + String value = getSigValue(key); + if (value != null) + { + Entry entry = new Entry(Entry.TYPE_IMAGE, value, key); + entry.setStyle(defaultImageStyle_); + row.add(entry); + } + } + if (SignatureTypes.TYPE_VALUE.equals(type)) + { + // add a single value entry + String value = getSigValue(key); + Entry entry = new Entry(Entry.TYPE_VALUE, value, key); + if (entry != null) + { + entry.setColSpan(2); + entry.setStyle(defaultCaptionStyle_); + row.add(entry); + } + } + if ((SignatureTypes.TYPE_VALUE + SignatureTypes.TYPE_CAPTION).equals(type) || (SignatureTypes.TYPE_CAPTION + SignatureTypes.TYPE_VALUE).equals(type)) + { + // add a caption value pair + String caption = getSigCaption(key); + String value = getSigValue(key); + if (value != null) + { + Entry c_entry = new Entry(Entry.TYPE_CAPTION, caption, key); + // c_entry.setNoWrap(true); + c_entry.setStyle(defaultCaptionStyle_); + + Entry v_entry = new Entry(Entry.TYPE_VALUE, value, key); + v_entry.setStyle(defaultValueStyle_); + if (c_entry != null && v_entry != null) + { + row.add(c_entry); + row.add(v_entry); + } + } + } + } + sig_table.addRow(table_def, row); + } + } + + return sig_table; + } + + /** + * This method inits the signature object by the given type. It loads the + * configured values and captions from the config.properties file. + */ + public void initByType() throws SignatureTypesException + { + if (sigType_ == null) + { + sigType_ = getDefaultSigType(); + } + SignatureTypes sig_types = SignatureTypes.getInstance(); + signatureDefinition_ = sig_types.getSignatureTypeDefinition(sigType_); + Map key_cap_map = signatureDefinition_.getKeyCaptionMap(); + if (key_cap_map != null) + { + Iterator key_cap = key_cap_map.entrySet().iterator(); + while (key_cap.hasNext()) + { + Map.Entry entry = (Map.Entry) key_cap.next(); + String key = (String) entry.getKey(); + String caption = (String) entry.getValue(); + SignatureEntry sig_entry = null; + if (sigEntries_.containsKey(key)) + { + sig_entry = (SignatureEntry) sigEntries_.get(key); + } + else + { + sig_entry = new SignatureEntry(key); + sigEntries_.put(key, sig_entry); + } + sig_entry.setCaption(caption); + } + } + + Map key_val_map = signatureDefinition_.getKeyValueMap(); + if (key_val_map != null) + { + Set key_val_set = key_val_map.entrySet(); + Iterator key_val = key_val_set.iterator(); + while (key_val.hasNext()) + { + Map.Entry entry = (Map.Entry) key_val.next(); + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + if (SignatureTypes.SIG_NORM.equals(key)) + { + try + { + normalizer_.setVersion(value); + } + catch (NormalizeException e) + { + throw new SignatureTypesException("Can not set normalizer Version:" + value); + } + } + // value = new String(CodingHelper.encodeUTF8(value)); + if (logger_.isDebugEnabled()) + { + logger_.debug("key:" + key + " value:" + value); + } + setSigValue(key, value); + } + } + } + + /** + * This method returns a signature entry object. + * + * @param key + * the corresponding key + * @return the signature entry object of the given key, null if the key does + * not exist + */ + public SignatureEntry getSigEntry(String key) + { + return (SignatureEntry) sigEntries_.get(key); + } + + /** + * This method is a helper function to remove all white spaces from a text. + * + * @param text + * the white spaces should remove from + * @return a text without white spaces + */ + private static String removeAllWhiteSpaces(String text) + { + return text.replaceAll("\\s", ""); + } + + public SignatureTypeDefinition getSignatureTypeDefinition() + { + return this.signatureDefinition_; + } + + /** + * + * @param placeholder + * @return Returns the list of SignatureFieldDefinitions that's values in the + * SignatureObject have been filled out with placeholders. + */ + public List fillValues(final char placeholder, boolean has_SIG_ID) + { + List variable_fields = new ArrayList(); + + List field_definitions = this.signatureDefinition_.getFieldDefinitions(); + Iterator it = field_definitions.iterator(); + while (it.hasNext()) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) it.next(); + String value_string = null; + if (sfd.placeholder_length > 0) + { + if (sfd.field_name.equals(SignatureTypes.SIG_ID) && has_SIG_ID == false) + { + setValueBruteForce(SignatureTypes.SIG_ID, null); + continue; + } + + char[] placeholder_chars = new char[sfd.placeholder_length]; + for (int i = 0; i < placeholder_chars.length; i++) + { + placeholder_chars[i] = placeholder; + } + value_string = new String(placeholder_chars); + + variable_fields.add(sfd); + + setSigValue(sfd.field_name, value_string); + } + } + + return variable_fields; + } + + /** + * Returns the raw signature response XML string as set by the signing + * Connector. + * + * @return Returns the XML response String. + */ + public String getRawSignatureResponse() + { + return this.raw_signature_response; + } + + /** + * Sets the raw signature response XML string. + * + *

+ * This should be used by the Connector to pass the response String to the + * signer. + *

+ * + * @param raw_response_string + * The new raw signature response string. + */ + public void setRawSignatureResponse(String raw_response_string) + { + this.raw_signature_response = raw_response_string; + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() + { + String strg = ""; + Iterator it = sigEntries_.values().iterator(); + while (it.hasNext()) + { + SignatureEntry sig_entry = (SignatureEntry) it.next(); + String key = sig_entry.getKey(); + String caption = sig_entry.getCaption(); + String value = sig_entry.getValue(); + strg += key + "=" + caption + ":" + value + "\n"; + } + strg += "Signation Type:" + getSignationType() + "\n"; + return strg; + } + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java new file mode 100644 index 0000000..f576e65 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignatureResponse.java,v 1.4 2006/08/03 07:43:04 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.PropertyTree; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * The response of a verification. + * + * @author wlackner + */ +public class SignatureResponse +{ + /** + * The siganture response config key + */ + private static String SIG_RESP_KEY = "signature.response."; + + /** + * Default response message + */ + private static String SIG_RESP_DEFAULT_INFO = "Es ist leider keine nähere Information verfügbar:"; + + /** + * Response value for x509SubjectName_ + */ + private String x509SubjectName_ = null; + + /** + * Response value for x509IssuerName + */ + private String x509IssuerName = null; + + /** + * Response value for x509SerialNumber + */ + private String x509SerialNumber = null; + + /** + * Response value for signatureCheckCode_ + */ + private String signatureCheckCode_ = null; + + /** + * Response value for signatureCheckInfo_ + */ + private String signatureCheckInfo_ = null; + + /** + * Response value for signatureManifestCheckCode_ + */ + private String signatureManifestCheckCode_ = null; + + /** + * Response value for signatureManifestCheckInfo_ + */ + private String signatureManifestCheckInfo_ = null; + + /** + * Response value for certificateCheckCode_ + */ + private String certificateCheckCode_ = null; + + /** + * Response value for certificateCheckInfo_ + */ + private String certificateCheckInfo_ = null; + + /** + * The X.509 certificated parsed from the response string. + */ + protected X509Cert certificate_ = null; + + // /** + // * Flag the marks that the response is an error response + // */ + // private boolean isError_ = false; + // + // /** + // * The error code of an external application + // */ + // private String errorCode_ = null; + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SignatureResponse.class); + + /** + * + * + */ + public SignatureResponse() + { + try + { + loadSettings(); + } + catch (SignatureException e) + { + logger_.warn(e.getMessage()); + } + } + + /** + * load the inital signature settings + * + * @throws SignatureException + * @see SettingsReader + */ + private void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + } + + /** + * @return Returns the certificateCheckCode. + */ + public String getCertificateCheckCode() + { + return certificateCheckCode_; + } + + /** + * @param certificateCheckCode + * The certificateCheckCode to set. + */ + public void setCertificateCheckCode(String certificateCheckCode) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setCertificateCheckCode:" + certificateCheckCode); + } + certificateCheckCode_ = certificateCheckCode; + } + + /** + * @return Returns the signatureCheckCode. + */ + public String getSignatureCheckCode() + { + return signatureCheckCode_; + } + + /** + * @param signatureCheckCode + * The signatureCheckCode to set. + */ + public void setSignatureCheckCode(String signatureCheckCode) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureCheckCode:" + signatureCheckCode); + } + signatureCheckCode_ = signatureCheckCode; + } + + /** + * @return Returns the signatureManifestCheckCode. + */ + public String getSignatureManifestCheckCode() + { + return signatureManifestCheckCode_; + } + + /** + * @param signatureManifestCheckCode + * The signatureManifestCheckCode to set. + */ + public void setSignatureManifestCheckCode(String signatureManifestCheckCode) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureManifestCheckCode:" + signatureManifestCheckCode); + } + signatureManifestCheckCode_ = signatureManifestCheckCode; + } + + /** + * @return Returns the x509IssuerName. + */ + public String getX509IssuerName() + { + return x509IssuerName; + } + + /** + * @param issuerName + * The x509IssuerName to set. + */ + public void setX509IssuerName(String issuerName) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setX509IssuerName:" + issuerName); + } + x509IssuerName = issuerName; + } + + /** + * @return Returns the x509SerialNumber. + */ + public String getX509SerialNumber() + { + return x509SerialNumber; + } + + /** + * @param serialNumber + * The x509SerialNumber to set. + */ + public void setX509SerialNumber(String serialNumber) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setX509SerialNumber:" + serialNumber); + } + x509SerialNumber = serialNumber; + } + + /** + * @return Returns the x509SubjectName. + */ + public String getX509SubjectName() + { + return x509SubjectName_; + } + + /** + * @param subjectName + * The x509SubjectName to set. + */ + public void setX509SubjectName(String subjectName) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setX509SubjectName:" + subjectName); + } + x509SubjectName_ = subjectName; + } + + /** + * @return Returns the certificateCheckInfo. + */ + public String getCertificateCheckInfo() + { + if (certificateCheckInfo_ == null) + { + if (settings_ != null) + { + certificateCheckInfo_ = settings_.getValueFromKey(SIG_RESP_KEY + "certificateCheckInfo." + getCertificateCheckCode()); + } + } + if (certificateCheckInfo_ == null) + { + certificateCheckInfo_ = SIG_RESP_DEFAULT_INFO + getCertificateCheckCode(); + } + return certificateCheckInfo_; + } + + /** + * @param certificateCheckInfo + * The certificateCheckInfo to set. + */ + public void setCertificateCheckInfo(String certificateCheckInfo) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setCertificateCheckInfo:" + certificateCheckInfo); + } + certificateCheckInfo_ = certificateCheckInfo; + } + + /** + * @return Returns the signatureCheckInfo. + */ + public String getSignatureCheckInfo() + { + if (signatureCheckInfo_ == null) + { + if (settings_ != null) + { + signatureCheckInfo_ = settings_.getValueFromKey(SIG_RESP_KEY + "signatureCheckInfo." + getSignatureCheckCode()); + } + } + if (signatureCheckInfo_ == null) + { + signatureCheckInfo_ = SIG_RESP_DEFAULT_INFO + getSignatureCheckCode(); + } + return signatureCheckInfo_; + } + + /** + * @param signatureCheckInfo + * The signatureCheckInfo to set. + */ + public void setSignatureCheckInfo(String signatureCheckInfo) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureCheckInfo:" + signatureCheckInfo); + } + signatureCheckInfo_ = signatureCheckInfo; + } + + /** + * @return Returns the signatureManifestCheckInfo. + */ + public String getSignatureManifestCheckInfo() + { + if (signatureManifestCheckInfo_ == null) + { + if (settings_ != null) + { + signatureManifestCheckInfo_ = settings_.getValueFromKey(SIG_RESP_KEY + "signatureManifestCheckInfo." + getSignatureManifestCheckCode()); + } + } + if (signatureManifestCheckInfo_ == null) + { + signatureManifestCheckInfo_ = SIG_RESP_DEFAULT_INFO + getSignatureManifestCheckCode(); + } + return signatureManifestCheckInfo_; + } + + /** + * @param signatureManifestCheckInfo + * The signatureManifestCheckInfo to set. + */ + public void setSignatureManifestCheckInfo(String signatureManifestCheckInfo) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureManifestCheckInfo:" + signatureManifestCheckInfo); + } + signatureManifestCheckInfo_ = signatureManifestCheckInfo; + } + + /** + * Returns the X.509 certificate of this response. + * + * @return Returns the X.509 certificate of this response. + */ + public X509Cert getCertificate() + { + return certificate_; + } + + /** + * Sets the X.509 certificate of this response. + * + * @param certificate + * The X.509 certificate to be set. + */ + public void setCertificate(X509Cert certificate) + { + this.certificate_ = certificate; + } + + /** + * Returns a list of Strings each stating one public property of the + * certificate. + * + *

+ * Such public properties are certificate extensions each being assigned an + * own OID. For example the public property "Verwaltungseigenschaft" has the + * OID "1.2.40.0.10.1.1.1". + *

+ *

+ * This methods reads out the list of possible properties from the config file + * and compares these to the extensions defined on the certificate. If they + * match, a String containing useful information about the property is added + * to the list returned. + *

+ * + * @return Returns the list of Strings representing the public properties of + * this certificate, if any. + * @throws SettingNotFoundException + */ + public List getPublicProperties() throws SettingNotFoundException + { + List props = new ArrayList(); + + SettingsReader settings = this.settings_; + + String root_oid = settings.getSetting("oid.root"); + + PropertyTree oids = settings.getPTree().getSubTree("oid"); + + Set non_critial_oids = this.certificate_.getX509Certificate().getNonCriticalExtensionOIDs(); + Iterator ext_it = non_critial_oids.iterator(); + while (ext_it.hasNext()) + { + String oid = (String) ext_it.next(); + + if (oid.startsWith(root_oid)) + { + String key = oid.replaceAll("\\.", "_"); + + String value = oids.getLastValue(key); + if (value == null) + { + value = oid; + } + + props.add(value); + } + } + + return props; + } + + /** + * The toString method + */ + public String toString() + { + String str = ""; + str += "\nSignator:" + getX509SubjectName(); + str += "\nAusteller:" + getX509IssuerName(); + str += "\nSeriennummer:" + getX509SerialNumber(); + str += "\nZertifikat-Code:" + getCertificateCheckCode() + "=" + getCertificateCheckInfo(); + str += "\nSignatur-Check-Code:" + getSignatureCheckCode() + "=" + getSignatureCheckInfo(); + str += "\nManifest-Check-Code:" + getSignatureManifestCheckCode() + "=" + getSignatureManifestCheckInfo(); + return str; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java new file mode 100644 index 0000000..3a210fa --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java @@ -0,0 +1,139 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: SignatureSeparator.java,v 1.4 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.List; +import java.util.Stack; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; + +/** + * This class separates all signature blocks in a raw text. + */ +public class SignatureSeparator { + /** + * The signature block stack. On top of the stack is the first signature block that can be + * extracted. First means nearest to the document text. + */ + private Stack signatureBlocks_ = null; + /** + * A list of signature type definitions. + */ + private List signatureTypes_ = null; + /** + * Indicator that shows that a raw text is signated + */ + private boolean hasSignatureBlock_ = false; + + /** + * The empty constructor. It loads all signature type infos to extract the signature block from + * the raw text. + * + * @throws SignatureTypesException + */ + public SignatureSeparator() throws SignatureTypesException { + SignatureTypes sig_types = SignatureTypes.getInstance(); + signatureTypes_ = sig_types.getSignatureTypeDefinitions(); + } + + /** + * This method takes a raw text as input and trys to separate all signature blocks. It returns + * true if a signature block is found. + * + * @param rawText + * @return true if a signature block is found false otherwise + */ + public boolean separateBlock(String rawText) { + signatureBlocks_ = new Stack(); + hasSignatureBlock_ = separateBlock(rawText, rawText.length()); + return hasSignatureBlock_; + } + + /** + * This method calls itself rekursively while signature blocks can be extracted. If a signature + * block is found (search from the bottom of the raw text) the raw text would be reduced by the + * length of the found signature block text. + * + * @param rawText the text to be separated + * @param endIndex the index to cut the tail from the raw text + * @return true if a signature block is found false otherwise + */ + private boolean separateBlock(String rawText, int endIndex) { + boolean found = false; + boolean can_separate = true; + while (can_separate) { + SignatureBlock sig_block = new SignatureBlock(signatureTypes_); + String raw_text = rawText.substring(0, endIndex); + can_separate = sig_block.separateBlockFromRawText(raw_text, true); + if (can_separate) { + signatureBlocks_.push(sig_block); + endIndex = sig_block.getStartIndex(); + found = true; + } + } + return found; + } + + /** + * This method returns the start index of the first signature block. It is used to separate the + * real document text from the signature block texts. + * + * @return the start index of the first signature block + */ + public int getStartIndex() { + int start_index = -1; + if (signatureBlocks_ != null && signatureBlocks_.size() > 0) { + SignatureBlock sig_block = (SignatureBlock) signatureBlocks_.peek(); + return sig_block.getStartIndex(); + } + return start_index; + } + + /** + * @return the first found signature object in the given raw text or null if the raw text does not + * contain any signature objects + */ + public SignatureObject getFirstSignatureObject() { + if (signatureBlocks_ != null && signatureBlocks_.size() > 0) { + SignatureBlock sig_block = (SignatureBlock) signatureBlocks_.peek(); + try { + return sig_block.getSignatureObject(); + } catch (SignatureException e) { + return null; + } + } + return null; + } + + /** + * @return all separated signature blocks as stack, first is on top + */ + public Stack getSignatureBlocks() { + return signatureBlocks_; + } + + /** + * @return true if a signature block is found false otherwise + */ + public boolean hasSignatureBlock() { + return hasSignatureBlock_; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java new file mode 100644 index 0000000..4b14019 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignatureTypeDefinition.java,v 1.3 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +public class SignatureTypeDefinition implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 1327407307346061147L; + + /** + * The type of this definition + */ + private String type_ = null; + + /** + * A map of all key to caption tupls. + */ + private Map keyCaptionMap_ = new HashMap(); + + /** + * A map of all key to value tupls. + */ + private Map keyValueMap_ = new HashMap(); + + /** + * A list of sorted keys + */ + private Vector sortedKeys_ = null; + + /** + * A list of sorted captions + */ + private Vector sortedCaptions_ = null; + + /** + * A revert of sorted keys + */ + private Vector revertSortedKeys_ = new Vector(); + + /** + * A revert list of sorted captions + */ + private Vector revertSortedCaptions_ = new Vector(); + + /** + * The settings reader reference + */ + private SettingsReader settings_ = null; + + /** + * The constructor of the signature type definition. It reads the configured + * table definition of the signature block and load the type definition of a + * given type. + * + * @param settings + * a SettingsReader instance + * @param type + * the signature type to load + * @throws SignatureException + * @see SettingsReader + */ + public SignatureTypeDefinition(SettingsReader settings, String type) throws SignatureException + { + settings_ = settings; + type_ = type; + readSigTable(SignatureTypes.MAIN_TABLE); + loadTypeDefinition(); + readFieldDefinitions(); + } + + /** + * Load the configured signature type definitions. It reads all key-captions + * tupls that are used in the signature table. It also reads all key-value + * tupls. + * + * @throws SignatureException + */ + private void loadTypeDefinition() throws SignatureException + { + if (sortedKeys_ == null) + { + sortKeys(); + } + + String key_prefix = SignatureTypes.SIG_OBJ + type_ + ".key"; + ArrayList keys = settings_.getKeys(key_prefix); + if (keys == null) + { + SignatureException se = new SignatureException(100, "There is no key defined for type:" + type_); + ; + throw se; + } + for (int key_idx = 0; key_idx < keys.size(); key_idx++) + { + String sig_key = (String) keys.get(key_idx); + String sig_key_val = settings_.getValueFromKey(key_prefix + "." + sig_key); + if (sortedKeys_.contains(sig_key)) + { + keyCaptionMap_.put(sig_key, sig_key_val); + } + } + String value_prefix = SignatureTypes.SIG_OBJ + type_ + ".value"; + ArrayList values = settings_.getKeys(value_prefix); + if (values != null) + { + for (int key_idx = 0; key_idx < values.size(); key_idx++) + { + String val_key = (String) values.get(key_idx); + String val_key_val = settings_.getValueFromKey(value_prefix + "." + val_key); + keyValueMap_.put(val_key, val_key_val); + } + } + } + + /** + * This method reads the table definition of singature type. It takes care + * about the linearization of the defined key-value pairs or sub tables. The + * linearisation is done reading a table from left to right and top to bottom. + * A sub table is alwais a normal cell element in the linearisation prozess. + * If a sub table exists therefore the linearisation of the subtable is taken + * es cell element in the parent table. t This method stores a revert sorted + * linearisation list of used keys in the table. This method is called + * recursivley if defined nested tables. + * + * @param tableKey + * the name of the table definition + */ + private void readSigTable(String tableKey) + { + // System.err.println("read table:" + type_ + "." + tableKey); + String table_key_prefix = SignatureTypes.SIG_OBJ + type_ + "." + SignatureTypes.TABLE; + String table_key = table_key_prefix + tableKey; + String key_prefix = SignatureTypes.SIG_OBJ + type_ + ".key."; + + // ArrayList table_def_keys = settings_.getKeys(table_key); + Vector table_def_keys = settings_.getSettingKeys(table_key); + if (table_def_keys != null) + { + for (int table_key_idx = 0; table_key_idx < table_def_keys.size(); table_key_idx++) + { + String table_row_id = (String) table_def_keys.get(table_key_idx); + String table_def_keys_name = table_key + "." + table_row_id; + String table_def_string = settings_.getValueFromKey(table_def_keys_name); + if (table_row_id.matches("\\D*")) + { + continue; + } + if (table_def_string != null) + { + // analyse the row definition + String[] elems = table_def_string.split("\\|"); + // ArrayList row = new ArrayList(); + int elem_idx = elems.length; + while (elem_idx > 0) + { + elem_idx--; + String elem = elems[elem_idx]; + String[] key_type = elem.split("-"); + if (key_type.length < 2) + { + return; + } + String key = key_type[0]; + String type = key_type[1]; + // System.err.println("key:" + type_ + "." + tableKey + + // "." + key + "=" + type); + + if (SignatureTypes.TYPE_TABLE.equals(key)) + { + // read sub table + readSigTable(type); + } + if (SignatureTypes.TYPE_IMAGE.equals(type)) + { + // ignore images + } + if (SignatureTypes.TYPE_VALUE.equals(type)) + { + String sig_key_val = settings_.getValueFromKey(key_prefix + key); + if (sig_key_val != null) + { + revertSortedKeys_.add(key); + revertSortedCaptions_.add(sig_key_val); + } + // ignore values without caption + } + if ((SignatureTypes.TYPE_VALUE + SignatureTypes.TYPE_CAPTION).equals(type) || (SignatureTypes.TYPE_CAPTION + SignatureTypes.TYPE_VALUE).equals(type)) + { + String sig_key_val = settings_.getValueFromKey(key_prefix + key); + if (sig_key_val != null) + { + revertSortedKeys_.add(key); + revertSortedCaptions_.add(sig_key_val); + } + } + } + } + } + } + } + + /** + * @return Returns the keys. + */ + public Map getKeyCaptionMap() + { + return keyCaptionMap_; + } + + /** + * @return Returns the keyValueMap. + */ + public Map getKeyValueMap() + { + return keyValueMap_; + } + + /** + * Returns a caption to a given key + * + * @param key + * @return the caption or null if the key is not found + */ + public String getCaptionFromKey(String key) + { + return (String) keyCaptionMap_.get(key); + } + + /** + * Returns a value to given key + * + * @param key + * @return the value or null if the key is not found + */ + public String getValueFromKey(String key) + { + return (String) keyValueMap_.get(key); + } + + /** + * @return Returns the sortedKeys. + */ + public Vector getSortedKeys() + { + if (sortedKeys_ == null) + { + sortKeys(); + } + return sortedKeys_; + } + + /** + * @return Returns the sortedCaptions. + */ + public Vector getSortedCaptions() + { + if (sortedCaptions_ == null) + { + sortKeys(); + } + return sortedCaptions_; + } + + /** + * @return Returns the revertSortedCaptions. + */ + public Vector getRevertSortedCaptions() + { + return revertSortedCaptions_; + } + + /** + * @return Returns the revertSortedKeys. + */ + public Vector getRevertSortedKeys() + { + return revertSortedKeys_; + } + + /** + * This method sort the reverted sorted key-caption and key-value lists. + * + */ + private void sortKeys() + { + // String key_prefix = SignatureTypes.SIG_OBJ + type_ + ".key."; + sortedKeys_ = new Vector(revertSortedKeys_.size()); + sortedCaptions_ = new Vector(revertSortedCaptions_.size()); + for (int key_idx = revertSortedKeys_.size() - 1; key_idx >= 0; key_idx--) + { + sortedKeys_.add(revertSortedKeys_.get(key_idx)); + sortedCaptions_.add(revertSortedCaptions_.get(key_idx)); + } + } + + /** + * This method checks if a given key is defined. + * + * @param key + * to find + * @return true if the key is find false otherwise + */ + public boolean contains(String key) + { + return (keyValueMap_.get(key) != null); + } + + /** + * The standard toString method. Used for internal tests only. + */ + public String toString() + { + String strg = this.type_ + "\n"; + Vector sk = getSortedKeys(); + Vector sc = getSortedCaptions(); + for (int i = 0; i < sk.size(); i++) + { + strg += sk.get(i) + "=" + sc.get(i) + "\n"; + } + return strg; + } + + /** + * @return Returns the signature type string. + */ + public String getType() + { + return type_; + } + + /** + * @return Returns the signature type description. + */ + public String getDescription() + { + String descr_key = SignatureTypes.SIG_OBJ + type_ + ".description"; + return settings_.getValueFromKey(descr_key); + } + + protected String getSettingsKeyBase() + { + return SignatureTypes.SIG_OBJ + type_; + } + + /** + * Gets the field definition of the given Field. + * + * @param field_name + * The name of the field. + * @return Returns the field's definition. + */ + public SignatureFieldDefinition readFieldDefinition(String field_name) + { + SignatureFieldDefinition sfd = new SignatureFieldDefinition(); + + sfd.field_name = field_name; + sfd.caption = this.settings_.getValueFromKey(getSettingsKeyBase() + ".key." + field_name); + sfd.value = this.settings_.getValueFromKey(getSettingsKeyBase() + type_ + ".value." + field_name); + sfd.placeholder_length = -1; + String phlen_str = this.settings_.getValueFromKey(getSettingsKeyBase() + ".phlength." + field_name); + if (phlen_str == null) + { + phlen_str = this.settings_.getValueFromKey("defaults.phlength." + field_name); + } + if (phlen_str != null) + { + sfd.placeholder_length = Integer.parseInt(phlen_str); + } + + return sfd; + } + + List field_definitions_ = null; + + protected void readFieldDefinitions() + { + this.field_definitions_ = new ArrayList(); + for (int i = 0; i < this.sortedKeys_.size(); i++) + { + String key = (String) this.sortedKeys_.get(i); + SignatureFieldDefinition sfd = readFieldDefinition(key); + //sfd.brev = SignatureTypes.ALL_SIG_BREV[i]; + this.field_definitions_.add(sfd); + } + } + + /** + * Returns the list of field definitions of this Signature profile. + * @return Returns the list of field definitions of this Signature profile. + */ + public List getFieldDefinitions() + { + return this.field_definitions_; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java new file mode 100644 index 0000000..0350129 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignatureTypes.java,v 1.5 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.table.Style; +import at.knowcenter.wag.exactparser.ByteArrayUtils; + +public class SignatureTypes +{ + + /** + * The settings key prefix for signature definitions. "sig_obj." + */ + public static final String SIG_OBJ = "sig_obj."; + + /** + * The settings key prefix for signature object types + */ + public static final String TYPES = SIG_OBJ + "types"; + + /** + * The settings key prefix for the default signature object type + */ + public static final String DEFAULT_TYPE = SIG_OBJ + "type.default"; + + /** + * The settings key postfix for the type description + */ + public static final String SIG_DESCR = "description"; + + /** + * The state value activating an signature definition + */ + private static final String STATE_ON = "on"; + + // /** + // * The state value de activating an signature definition + // */ + // private static final String STATE_OFF = "off"; + + /** + * The settings key prefix for the signature table object definition + */ + public static final String TABLE = "table."; + + /** + * The settings key sub prefix getting the main table definition + */ + public static final String MAIN_TABLE = "main"; + + /** + * The settings value refering to a table + */ + public final static String TYPE_TABLE = "TABLE"; + + /** + * The settings value refering to an image + */ + public final static String TYPE_IMAGE = "i"; + + /** + * The settings value refering to a text caption + */ + public final static String TYPE_CAPTION = "c"; + + /** + * The settings value refering to a text value + */ + public final static String TYPE_VALUE = "v"; + + /** + * The settings key sub prefix getting the width of columns for a table + * definition + */ + public final static String COLS_WITH = "ColsWidth"; + + /** + * The settings key sub prefix getting the style definition + */ + public final static String STYLE = "Style"; + + /** + * The default style definition for images. + */ + private Style defaultImageStyle_ = new Style(); + + /** + * The default style definition for captions. + */ + private Style defaultCaptionStyle_ = new Style(); + + /** + * The default style definition for values. + */ + private Style defaultValueStyle_ = new Style(); + + /** + * Standard key get/set the singature name + */ + public static final String SIG_NAME = "SIG_NAME"; + + /** + * Standard key get/set the signature date + */ + public static final String SIG_DATE = "SIG_DATE"; + + /** + * Standard key get/set the signator issuer + */ + public static final String SIG_ISSUER = "SIG_ISSUER"; + + /** + * Standard key get/set the siganture value + */ + public static final String SIG_VALUE = "SIG_VALUE"; + + /** + * Standard key get/set the normalisation method used + */ + public static final String SIG_NORM = "SIG_NORM"; + + /** + * Standard key get/set the signation id's used by BKU signated documents + */ + public static final String SIG_ID = "SIG_ID"; + + /** + * The EGIZ Algorithm "Kennzeichnung". + */ + public static final String SIG_KZ = "SIG_KZ"; + + /** + * Standard key get/set the reference to the signature label (image mark) + */ + public static final String SIG_LABEL = "SIG_LABEL"; + + /** + * Standard key get/set the serial number of the signature + */ + public static final String SIG_NUMBER = "SIG_NUMBER"; + + // public static final String SIG_TYPE = "SIG_TYPE"; + /** + * Standard key get/set the signature meta informations + */ + public static final String SIG_META = "SIG_META"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SignatureTypes.class); + + // /** + // * The normalizer reference + // */ + // private Normalizer normalizer_ = null; + + /** + * The settings reader reference + */ + private SettingsReader settings_ = null; + + // /** + // * The reference to the settings property tree + // */ + // private PropertyTree pTree_ = null; + + // /** + // * The current signature type used reading and analysing the property tree + // */ + // private String sigType_ = null; + + // /** + // * List of all keys used in the current signature definition + // */ + // private ArrayList sigKeys_ = null; + + /** + * Array of required signature keys + */ + // public static String[] REQUIRED_SIG_KEYS = new String[]{SIG_NAME, SIG_DATE, + // SIG_ISSUER, SIG_VALUE, SIG_NUMBER, SIG_ID}; + public static String[] REQUIRED_SIG_KEYS = new String[] { SIG_DATE, + SIG_ISSUER, SIG_VALUE, SIG_NUMBER, SIG_ID }; + + /** + * Tells, if the given key is a required key. + *

+ * Note that the SIG_KZ is a required key. + *

+ * @param key The key to be tested if it is a required key. + * @return Returns true, if the key is required, false otherwise. + */ + public static boolean isRequiredKey (String key) + { + if (key.equals(SIG_KZ)) + { + return true; + } + + for (int i = 0; i < REQUIRED_SIG_KEYS.length; i++) + { + if (key.equals(REQUIRED_SIG_KEYS[i])) + { + return true; + } + } + return false; + } + + public static String[] ALL_SIG_KEYS = new String[] { SIG_NAME, SIG_DATE, + SIG_ISSUER, SIG_VALUE, SIG_NORM, SIG_ID, SIG_LABEL, SIG_NUMBER, SIG_META }; + + public static byte [][] ALL_SIG_BREV = new byte[][] { { 'n', 'a', 'm' }, + { 'd', 'a', 't' }, { 'i', 's', 's' }, { 'v', 'a', 'l' }, + { 'n', 'o', 'r' }, { 's', 'i', 'd' }, { 'l', 'a', 'b' }, + { 's', 'n', 'r' }, { 'm', 'e', 't' } }; + + // /** + // * Sorted representation of keys defined in rows + // */ + // private ArrayList sortedSigKeys_ = new ArrayList(); + + // /** + // * Reference from signature key to there corresponding value + // */ + // private Hashtable sigEntries_ = new Hashtable(8); + + /** + * A list of all configured signature type definitions + */ + private List signatureTypeDefinitions_ = new Vector(); + + /** + * A type-name to type-definition map + */ + private Map typeDefMap_ = new HashMap(); + + // /** + // * A map of required keys used to reconstruct a signature block + // */ + // private static HashMap requiredSigKeys_ = new HashMap(); + + /** + * A plain list of signature type names + */ + ArrayList typeList_ = new ArrayList(4); + + /** + * Used as singleton to read the singnature type definitions only one times of + * a session + */ + private static SignatureTypes instance_ = null; + + /** + * This is the private constructor method to provide a singleton instance of + * this class. It inits a normalizer, the settings reader, read the default + * styles and load the configured signature types. + * + * @throws SignatureTypesException + * @see SettingsReader + */ + private SignatureTypes() throws SignatureTypesException + { + try + { + loadSettings(); + } + catch (SettingsException e) + { + throw new SignatureTypesException(e); + } + setDefaultStyles(); + loadSignatureTypes(); + } + + /** + * This static method returns the stored instance of this class. If the + * singleton does not exist, this method creates a new singleton and gives + * this instance back to the caller. + * + * @return the stored instance of this class + * @throws SignatureTypesException + */ + public static SignatureTypes getInstance() throws SignatureTypesException + { + if (instance_ == null) + { + instance_ = new SignatureTypes(); + } + return instance_; + } + + /** + * This method load the signature definitions + * + * @throws SettingsException + * + * @throws SettingsException + * ErrorCode:101 + */ + private void loadSettings() throws SettingsException + { + if (settings_ == null) + { + settings_ = SettingsReader.getInstance(); + } + // pTree_ = settings_.getPTree(); + } + + /** + * This method set the default styles for images, captions and values. + */ + private void setDefaultStyles() + { + defaultImageStyle_.setPadding(3); + defaultImageStyle_.setHAlign(Style.CENTER); + defaultImageStyle_.setVAlign(Style.MIDDLE); + defaultImageStyle_.setBgColor(new Color(255, 255, 255)); + + defaultCaptionStyle_.setHAlign(Style.CENTER); + defaultCaptionStyle_.setVAlign(Style.MIDDLE); + + defaultValueStyle_.setVAlign(Style.MIDDLE); + } + + /** + * This method load the configured signature types. It stores the definition + * representations only if the type is set to ON. It stores the type + * definition object, the definition map and the simple type name list. + */ + private void loadSignatureTypes() + { + if (settings_ != null) + { + ArrayList types = settings_.getKeys(TYPES); + for (int type_idx = 0; type_idx < types.size(); type_idx++) + { + String type = (String) types.get(type_idx); + if (STATE_ON.equals(settings_.getSetting(TYPES + "." + type, null))) + { + SignatureTypeDefinition sig_type_def; + try + { + sig_type_def = new SignatureTypeDefinition(settings_, type); + signatureTypeDefinitions_.add(sig_type_def); + typeDefMap_.put(type, sig_type_def); + typeList_.add(type); + } + catch (SignatureException e) + { + if (logger_.isDebugEnabled()) + { + logger_.debug(e.getMessage()); + } + e.printStackTrace(); + } + } + } + } + } + + /** + * @return a arrayList (String) of signature types + */ + public ArrayList getSignatureTypes() + { + return typeList_; + } + + /** + * @return a list of signature type definitions + */ + public List getSignatureTypeDefinitions() + { + return signatureTypeDefinitions_; + } + + /** + * This method returns the corresponding signature type definition to a given + * type key + * + * @param type + * the key to get the signature type definition + * @return the stored signature type definition + */ + public SignatureTypeDefinition getSignatureTypeDefinition(String type) + { + return (SignatureTypeDefinition) typeDefMap_.get(type); + } + + public static String convertBrevToType (final byte [] brev) + { + for (int i = 0; i < ALL_SIG_BREV.length; i++) + { + if (ByteArrayUtils.compareByteArrays(ALL_SIG_BREV[i], 0, brev)) + { + return ALL_SIG_KEYS[i]; + } + } + return null; + } + + public static byte [] convertTypeToBrev (final String type) + { + for (int i = 0; i < ALL_SIG_KEYS.length; i++) + { + if (ALL_SIG_KEYS.equals(type)) + { + return ALL_SIG_BREV[i]; + } + } + return null; + } + + /** + * The standard toString method. Used for testing only. + * + * @return the string representation of the class + */ + public String toString() + { + String strg = ""; + for (int i = 0; i < signatureTypeDefinitions_.size(); i++) + { + SignatureTypeDefinition std = (SignatureTypeDefinition) signatureTypeDefinitions_.get(i); + strg += "----------TYPE:" + std.getType() + "----------\n"; + strg += std.toString(); + } + return strg; + } + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java new file mode 100644 index 0000000..64631cb --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: X509Cert.java,v 1.4 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.Serializable; +import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +public class X509Cert implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 6945327015386694557L; + + /** + * The x509 certificate binary string Base64 coded + */ + private String certString_ = null; + + /** + * The name value of the issuer + */ + private String issuerName_ = null; + + /** + * The serial number of the certificate + */ + private String serialNumber_ = null; + + /** + * The digest value of the certificate + */ + private String certDigest_ = null; + + /** + * The name value of the subject + */ + private String subjectName_ = null; + + /** + * The X509Certificate object + */ + private X509Certificate x509Cert_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(X509Cert.class); + + /** + * The empty constructor not acessible from outside --> use the static init + * methods instead + */ + private X509Cert() + { + } + + /** + * Normalize the base64 coded .cer or .der string. Remove the begin and end + * statement and remove all whitespaces in the string. The result string + * (base64) is used by reconstructing the certiface sign by the verification + * process. + * + * @param certString + * the string to normalize + * @return the normalized cert string + */ + private static String normalizeCertString(String certString) + { + certString = certString.replaceAll("-----BEGIN CERTIFICATE-----", ""); + certString = certString.replaceAll("-----END CERTIFICATE-----", ""); + certString = certString.replaceAll("\\s", ""); + return certString; + } + + /** + * This method initialzes a X509Certificate by a string value. It must be + * coded Base64 or as plain binary stream. + * + * @param certString + * the certificate string to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByString(String certString) + { + if (certString == null) + { + return null; + } + certString = normalizeCertString(certString); + X509Cert x509_cert = new X509Cert(); + x509_cert.setCertString(certString); + try + { + byte[] b64_dec = certString.getBytes("US-ASCII"); + if (CodingHelper.isB64(b64_dec)) + { + b64_dec = CodingHelper.decodeBase64(b64_dec); + } + else + { + b64_dec = CodingHelper.encodeBase64(b64_dec).getBytes("US-ASCII"); + } + ByteArrayInputStream bais = new ByteArrayInputStream(b64_dec); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + x509_cert.setX509Cert(cert); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().getName(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + } + catch (java.security.cert.CertificateException ce) + { + // nothing to do, cause certString is not X509 conformc + ce.printStackTrace(); + } + catch (IOException ioe) + { + // nothing to do, cause certString is not X509 conform + ioe.printStackTrace(); + } + return x509_cert; + } + + public static X509Cert initByByteArray(byte[] data) + { + X509Cert x509_cert = new X509Cert(); + try + { + ByteArrayInputStream bais = new ByteArrayInputStream(data); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + + x509_cert.setX509Cert(cert); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().getName(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + } + catch (java.security.cert.CertificateException ce) + { + // nothing to do, cause certString is not X509 conformc + ce.printStackTrace(); + } + catch (IOException ioe) + { + // nothing to do, cause certString is not X509 conform + ioe.printStackTrace(); + } + + return x509_cert; + } + + /** + * This method initialzes a X509Certificate by a file path value. The file + * must be a plain binary file like .cer format. + * + * @param filePath + * the certificate file to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByFilePath(String filePath) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("Add cert file:" + filePath); + } + if (filePath == null) + { + return null; + } + X509Cert x509_cert = new X509Cert(); + try + { + FileInputStream fis = new FileInputStream(filePath); + X509Certificate cert = null; + try + { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + cert = (X509Certificate) cf.generateCertificate(fis); + } + catch (java.security.cert.CertificateException ce) + { + fis.close(); + String cert_string = FileHelper.readFromFile(filePath); + return initByString(cert_string); + } + fis.close(); + x509_cert.setX509Cert(cert); + String cert_string = FileHelper.readFromFile(filePath); + x509_cert.setCertString(normalizeCertString(cert_string)); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().getName(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + } + catch (IOException ioe) + { + String cert_string = FileHelper.readFromFile(filePath); + return initByString(cert_string); + } + return x509_cert; + + } + + /** + * This method initialzes a X509Certificate by a file value. The file must be + * a plain binary file like .cer format. + * + * @param certFile + * the certificate file to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByFile(File certFile) + { + return initByFilePath(certFile.getAbsolutePath()); + } + + /** + * This method checks if a certificate file is X509 conform. + * + * @return true if a certificate file is X509 conform, false otherwise + */ + public boolean isX509Cert() + { + return x509Cert_ != null; + } + + /** + * @return Returns the certificate digest value. + */ + public String getCertDigest() + { + if (certDigest_ == null) + { + if (certString_ != null) + { + byte[] cert_b64 = CodingHelper.decodeBase64(certString_); + byte[] cert_hash = CodingHelper.buildDigest(cert_b64); + certDigest_ = new String(CodingHelper.encodeBase64(cert_hash)); + } + } + return certDigest_; + } + + /** + * @return Returns the certificate Base64 binary string. + */ + public String getCertString() + { + return certString_; + } + + /** + * @return Returns the issuer string. + */ + public String getIssuerName() + { + return issuerName_; + } + + /** + * @return Returns the serial number. + */ + public String getSerialNumber() + { + return serialNumber_; + } + + /** + * @return Returns the real X509Certifcate object. + * @see X509Certificate + */ + public X509Certificate getX509Certificate() + { + return x509Cert_; + } + + /** + * @return Returns the subject name. + */ + public String getSubjectName() + { + return subjectName_; + } + + // /** + // * @param certDigest + // * The certDigest to set. + // */ + // private void setCertDigest(String certDigest) + // { + // certDigest_ = certDigest; + // } + + /** + * @param certString + * The certString to set. + */ + private void setCertString(String certString) + { + certString_ = certString; + } + + /** + * @param issuerString + * The issuerString to set. + */ + private void setIssuerName(String issuerString) + { + issuerName_ = issuerString; + } + + /** + * @param serialNumber + * The serialNumber to set. + */ + private void setSerialNumber(String serialNumber) + { + serialNumber_ = serialNumber; + } + + /** + * @param cert + * The x509Cert to set. + */ + private void setX509Cert(X509Certificate cert) + { + x509Cert_ = cert; + } + + /** + * @param subjectName + * The subjectName to set. + */ + private void setSubjectName(String subjectName) + { + subjectName_ = subjectName; + } + + public byte[] getTBSCertificate() throws CertificateEncodingException + { + return x509Cert_.getTBSCertificate(); + } + + public String getSigAlgName() + { + return x509Cert_.getSigAlgName(); + } + + public String getSigAlgOID() + { + return x509Cert_.getSigAlgOID(); + } + + public List getExtendedKeyUsage() + { + List list = null; + try + { + list = x509Cert_.getExtendedKeyUsage(); + if (list == null) + { + System.err.println("is realy null"); + } + } + catch (CertificateParsingException e) + { + e.printStackTrace(); + } + return null; + } + + /** + * @return the public key of the X509Certificate + */ + public PublicKey getPublicKey() + { + return x509Cert_.getPublicKey(); + } + + /** + * This method checks, if a X509Certificate has a public key with the rsa + * algorithm. + * + * @return true if the public key is produced with rsa, false otherwise + */ + public boolean isRSA() + { + return (x509Cert_.getPublicKey().getAlgorithm()).indexOf("RSA") >= 0; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java new file mode 100644 index 0000000..9144966 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: A1Connector.java,v 1.2 2006/08/25 17:09:17 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; + +/** + * @author wprinz + */ +public class A1Connector extends BKUConnector +{ + /** + * ConnectorInformation that identifies this Connector to the system. + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * @see ConnectorInformation + */ + public static final ConnectorInformation CONNECTOR_INFORMATION = new ConnectorInformation("a1", "A-1"); + + /** + * Constructor. + * + * @throws SignatureException + * F.e. + */ + public A1Connector() throws SignatureException + { + super(); + } + + /** + * Overrides the type of the BKUConnector to use the A1 settings. + */ + protected String getType() + { + return CONNECTOR_INFORMATION.getIdentifier(); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java new file mode 100644 index 0000000..96fa81b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java @@ -0,0 +1,813 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: BKUConnector.java,v 1.5 2006/10/31 08:18:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.io.UnsupportedEncodingException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.LocalConnector; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +/** + * Connector for communicating with BKU. + * + * @author wlackner + * @author wprinz + */ +public class BKUConnector implements LocalConnector +{ + /** + * ConnectorInformation that identifies this Connector to the system. + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * @see ConnectorInformation + */ + public static final ConnectorInformation CONNECTOR_INFORMATION = new ConnectorInformation("bku", "BKU"); + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(BKUConnector.class); + + /** + * The empty constructor + */ + public BKUConnector() throws SignatureException + { + loadSettings(); + } + + /** + * load the inital signature settings + * + * @see SettingsReader + */ + private void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + } + + /** + * This method calls the BKU signing a given text. The signaton type is to + * used initializing the corresponding SigantureObject. The initialized + * SignatureObject is filled out by the parsed BKU-Response.
+ * If an error request is send back from BKU, an error message is generated an + * an exception is thrown. + * + * @param sigType + * the type of the SignatureObject that should be returned + * @param userName + * the name of the user calling this method + * @param signText + * the text that shoulf be signed from BKU + * @return the complete SingatureObject of the given type filled by values + * from the BKU-Request + * @throws SignatureException + * @see SignatureObject + */ + public SignatureObject doSign(String sigType, String userName, String signText) throws SignatureException + { + String request_string = prepareSignRequest(userName, signText, sigType); + + String sign_url = getSignURL(sigType); + String response_string = sendRequest(sign_url, request_string); + + return analyzeSignResponse(response_string, sigType); + } + + /** + * This method generates the BKU verify prozess. It checks if the given + * SignatureObject is signed by MOA or BKU. The verify template string is + * filled out by the corresponding method. + * + * @param normalizedText + * the normalized text to verify + * @param sigObject + * the SignatureObject holding the singature values + * @return a SignatureResponse object if the verify prozess does not fails + * @throws SignatureException + * @see SignatureResponse + */ + public SignatureResponse doVerify(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + String request_string = prepareVerifyRequest(normalizedText, sigObject); + + String verify_url = getVerifyURL(sigObject.getSignationType()); + String response_string = sendRequest(verify_url, request_string); + + return analyzeVerifyResponse(response_string); + } + + /** + * This method parses the BKU-Response string. It separates the + * SignatureValue, X509IssuerName, SigningTime, X509SerialNumber, + * X509Certificate, CertDigest, DigestValue and the signation id-s. If the + * X509Certificate is extracted it would be stored in the certificates + * directory. + * + * @param xmlResponse + * the response string from the BKU sign-request + * @param sigObj + * the SignatureObject that should be filled + * @throws SignatureException + * ErrorCode (303, 304) + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + private void parseCreateXMLResponse(String xmlResponse, SignatureObject sigObj) throws SignatureException + { + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); + Pattern sig_val_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); + Pattern sig_tim_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>"); + Pattern ser_num_p_e = Pattern.compile(""); + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); + Pattern sig_cer_p_e = Pattern.compile(""); + + Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>"); + Pattern sig_cer_d_p_e = Pattern.compile(""); + Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>"); + Pattern dig_val_p_e = Pattern.compile(""); + + Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse); + Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse); + Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse); + + String sig_val = ""; + String iss_nam = ""; + String ser_num = ""; + String sig_tim = ""; + String sig_cer = ""; + String sig_dig = ""; + + // SignatureValue + if (sig_val_m_s.find() && sig_val_m_e.find()) + { + sig_val = xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start()); + sig_val = sig_val.replaceAll("\\s", ""); + sigObj.setSignationValue(sig_val); + } + // X509IssuerName + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sigObj.setSignationIssuer(iss_nam); + } + // X509SerialNumber + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sigObj.setSignationSerialNumber(ser_num); + } + // SigningTime + if (sig_tim_m_s.find() && sig_tim_m_e.find()) + { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + sigObj.setSignationDate(sig_tim); + } + // CertDigest + if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find()) + { + String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), sig_cer_d_m_e.start()); + Matcher dig_val_m_s = dig_val_p_s.matcher(cert_digest); + Matcher dig_val_m_e = dig_val_p_e.matcher(cert_digest); + if (dig_val_m_s.find() && dig_val_m_e.find()) + { + sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start()); + sigObj.setX509CertificateDigest(sig_dig); + } + } + // extract Subject Name from X509Certificate + if (sig_cer_m_s.find() && sig_cer_m_e.find()) + { + sig_cer = xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start()); + sig_cer = sig_cer.replaceAll("\\s", ""); + sigObj.setX509Certificate(sig_cer); + X509Cert cert = X509Cert.initByString(sig_cer); + if (cert.isX509Cert()) + { + sigObj.setX509Certificate(cert.getCertString()); + String serial_num = cert.getSerialNumber(); + String subject_name = cert.getSubjectName(); + if (!ser_num.equals(serial_num)) + { + SignatureException se = new SignatureException(303, "Serialnumber of certificate and tag X509SerialNumber differs!"); + throw se; + } + sigObj.setSignationName(subject_name); + } + } + + // extract Signature Id's + String[] ids = new String[5]; + ids[0] = extractId(xmlResponse, "signature-"); + ids[1] = extractId(xmlResponse, "signed-data-reference-"); + ids[2] = extractId(xmlResponse, "signed-data-object-"); + ids[3] = extractId(xmlResponse, "etsi-data-reference-"); + ids[4] = extractId(xmlResponse, "etsi-data-object-"); + sigObj.setSignationIDs(ids); + } + + /** + * This emthod extracts id-values from a text. The id is given by the name. + * + * @param text + * the id-value that should extract from + * @param name + * the id-key + * @return the value of the given key in the text + */ + private String extractId(String text, String name) + { + String id = null; + int start_idx = text.indexOf(name) + name.length(); + int end_idx = text.indexOf("\"", start_idx); + id = text.substring(start_idx, end_idx); + if (logger_.isDebugEnabled()) + { + logger_.debug("extract id:" + name + id); + } + return id; + } + + /** + * This method reads the verify template from the file system and fills out + * the template with the SignatureObject values. + * + * @param normalizedText + * the normalized text to veryfied + * @param sigObject + * the SignatureObject holding the singature values + * @return the filled verify template string + * @throws SignatureException + * ErrorCode (311, 312, 313) + * @see SignatureObject + * @see CodingHelper + */ + public String getVerifyTemplate(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + try + { + if (normalizedText == null || normalizedText.length() == 0) + { + SignatureException se = new SignatureException(311, "Document can not be verified because normalized text is empty."); + throw se; + } + if (sigObject == null) + { + SignatureException se = new SignatureException(312, "Document can not be verified because no signature object are set."); + throw se; + } + + String verify_template = getVerifyTemplateFileName(sigObject.getSignationType()); + String sig_prop_filename = getSigPropFileName(sigObject.getSignationType()); + + String ver_temp_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_template)); + String sig_prop_str = FileHelper.readFromFile(SettingsReader.relocateFile(sig_prop_filename)); + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_template); + logger_.debug(sig_prop_filename); + } + + String x509_cert_string = sigObject.getX509CertificateString(); + if (x509_cert_string == null) + { + SignatureException se = new SignatureException(313, "Document certificate is not defined."); + throw se; + } + String cert_alg = settings_.getValueFromKey("cert.alg.ecdsa"); + X509Cert x509_cert = sigObject.getX509Cert(); + if (x509_cert.isRSA()) + { + cert_alg = settings_.getValueFromKey("cert.alg.rsa"); + } + + String[] ids = sigObject.getSignationIds(); + sig_prop_str = sig_prop_str.replaceFirst("SigningTimeReplace", sigObject.getSignationDate()); + + String issuer_name = sigObject.getSignationIssuer(); + // The issuer is already unicode, so it mustn't be encoded again. + //byte[] issuer_name = CodingHelper.encodeUTF8(sigObject.getSignationIssuer()); + // new String(issuer_name); // this would double encode the String, not to mention the missing encoding + sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", issuer_name); + + sig_prop_str = sig_prop_str.replaceFirst("X509SerialNumberReplace", sigObject.getSignationSerialNumber()); + sig_prop_str = sig_prop_str.replaceFirst("DigestValueX509CertificateReplace", sigObject.getX509CertificateDigest()); + sig_prop_str = sig_prop_str.replaceFirst("SigIdReplace", ids[0]); + sig_prop_str = sig_prop_str.replaceFirst("SigDataRefReplace", ids[1]); + + ver_temp_str = ver_temp_str.replaceFirst("CertAlgReplace", cert_alg); + ver_temp_str = ver_temp_str.replaceFirst("TemplateQualifyingPropertiesReplace", sig_prop_str); + byte[] sig_prop_code = CodingHelper.buildDigest(sig_prop_str.getBytes("UTF-8")); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedPropertiesReplace", sig_prop_hash); + if (logger_.isDebugEnabled()) + { + logger_.debug("build digest from QualifyingProperties:start"); + //logger_.debug("DATA :" + sig_prop_str); + logger_.debug("DIGEST:" + sig_prop_hash); + logger_.debug("build digest from QualifyingProperties:end"); + } + + ver_temp_str = ver_temp_str.replaceFirst("SignatureValueReplace", sigObject.getSignationValue()); + ver_temp_str = ver_temp_str.replaceFirst("X509CertificateReplace", x509_cert_string); + byte[] data_value = normalizedText.getBytes("UTF-8"); + byte[] data_value_hash = CodingHelper.buildDigest(data_value); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + // String object_data = new String(data_value); + if (logger_.isDebugEnabled()) + { + logger_.debug("build digest from data object:start"); + //logger_.debug("DATA :" + normalizedText); + logger_.debug("DIGEST:" + object_data_hash); + logger_.debug("build digest from data object:end"); + } + + //String raw_b64 = CodingHelper.encodeUTF8AsBase64(normalizedText); + String raw_b64 = CodingHelper.encodeBase64(data_value); + + ver_temp_str = ver_temp_str.replaceFirst("Base64ContentReplace", raw_b64); + ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedDataReplace", object_data_hash); + + ver_temp_str = ver_temp_str.replaceAll("SigIdReplace", ids[0]); + ver_temp_str = ver_temp_str.replaceAll("SigDataRefReplace", ids[1]); + ver_temp_str = ver_temp_str.replaceAll("SigDataObjURIReplace", ids[2]); + ver_temp_str = ver_temp_str.replaceAll("EtsiDataRefReplace", ids[3]); + ver_temp_str = ver_temp_str.replaceAll("EtsiDataObjURIReplace", ids[4]); + if (logger_.isDebugEnabled()) + { + //logger_.debug("VERIFY REQUEST:" + ver_temp_str); + } + + return ver_temp_str; + } + catch (UnsupportedEncodingException e) + { + throw new SignatureException(310, e); + } + } + + /** + * This method parses the verify response string and return a + * SignatureResponse object. The SignatureResponse object is filled out by the + * response values from the BKU-response. + * + * @param xmlResponse + * the response values from the BKU-verify request + * @return SignatureResponse object + * @see SignatureResponse + */ + private SignatureResponse parseVerifyXMLResponse(String xmlResponse) + { + if (logger_.isInfoEnabled()) + { + logger_.info("Try parsing the verify response"); + } + + Pattern sub_nam_p_s = Pattern.compile(""); + Pattern sub_nam_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile(""); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile(""); + Pattern ser_num_p_e = Pattern.compile(""); + + Pattern sig_chk_p_s = Pattern.compile(""); + Pattern sig_chk_p_e = Pattern.compile(""); + Pattern man_chk_p_s = Pattern.compile(""); + Pattern man_chk_p_e = Pattern.compile(""); + Pattern cer_chk_p_s = Pattern.compile(""); + Pattern cer_chk_p_e = Pattern.compile(""); + + Pattern code_p_s = Pattern.compile(""); + Pattern code_p_e = Pattern.compile(""); + Pattern info_p_s = Pattern.compile(""); + Pattern info_p_e = Pattern.compile(""); + + Pattern cert_p_s = Pattern.compile(""); + Pattern cert_p_e = Pattern.compile(""); + + Matcher sub_nam_m_s = sub_nam_p_s.matcher(xmlResponse); + Matcher sub_nam_m_e = sub_nam_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + + Matcher sig_chk_m_s = sig_chk_p_s.matcher(xmlResponse); + Matcher sig_chk_m_e = sig_chk_p_e.matcher(xmlResponse); + Matcher man_chk_m_s = man_chk_p_s.matcher(xmlResponse); + Matcher man_chk_m_e = man_chk_p_e.matcher(xmlResponse); + Matcher cer_chk_m_s = cer_chk_p_s.matcher(xmlResponse); + Matcher cer_chk_m_e = cer_chk_p_e.matcher(xmlResponse); + + Matcher cert_m_s = cert_p_s.matcher(xmlResponse); + Matcher cert_m_e = cert_p_e.matcher(xmlResponse); + + SignatureResponse sig_res = new SignatureResponse(); + if (sub_nam_m_s.find() && sub_nam_m_e.find()) + { + String sub_nam = xmlResponse.substring(sub_nam_m_s.end(), sub_nam_m_e.start()); + sig_res.setX509SubjectName(sub_nam); + } + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + String iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sig_res.setX509IssuerName(iss_nam); + } + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + String ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sig_res.setX509SerialNumber(ser_num); + } + if (sig_chk_m_s.find() && sig_chk_m_e.find()) + { + String sig_chk = xmlResponse.substring(sig_chk_m_s.end(), sig_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(sig_chk); + Matcher code_m_e = code_p_e.matcher(sig_chk); + Matcher info_m_s = info_p_s.matcher(sig_chk); + Matcher info_m_e = info_p_e.matcher(sig_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = sig_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = sig_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setSignatureCheckInfo(info); + } + } + if (man_chk_m_s.find() && man_chk_m_e.find()) + { + String man_chk = xmlResponse.substring(man_chk_m_s.end(), man_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(man_chk); + Matcher code_m_e = code_p_e.matcher(man_chk); + Matcher info_m_s = info_p_s.matcher(man_chk); + Matcher info_m_e = info_p_e.matcher(man_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = man_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureManifestCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = man_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setSignatureManifestCheckInfo(info); + } + } + if (cer_chk_m_s.find() && cer_chk_m_e.find()) + { + String cer_chk = xmlResponse.substring(cer_chk_m_s.end(), cer_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(cer_chk); + Matcher code_m_e = code_p_e.matcher(cer_chk); + Matcher info_m_s = info_p_s.matcher(cer_chk); + Matcher info_m_e = info_p_e.matcher(cer_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = cer_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setCertificateCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = cer_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setCertificateCheckInfo(info); + } + } + if (cert_m_s.find() && cert_m_e.find()) + { + String cert_string = xmlResponse.substring(cert_m_s.end(), cert_m_e.start()); + + X509Cert resp_cert = X509Cert.initByString(cert_string); + sig_res.setCertificate(resp_cert); + } + + return sig_res; + } + + public String prepareSignRequest(String userName, String signText, + String signType) throws SignatureException + { + if (logger_.isInfoEnabled()) + { + logger_.info("Call " + getType() + " connector from user:" + userName); + } + String keybox_identifier = getSignKeyboxIdentifier(signType); + String sign_request_filename = getSignRequestTemplateFileName(signType); + + String sign_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + if (logger_.isDebugEnabled()) + { + //logger_.debug(sign_request_filename + "_signText.xml :" + signText); + } + String raw_b64 = CodingHelper.encodeUTF8AsBase64(signText); + if (sign_req_str == null || raw_b64 == null) + { + throw new SignatureException(300, "Can not read the create xml request template"); + } + sign_req_str = sign_req_str.replaceFirst("KeyboxIdentifierReplace", keybox_identifier); + sign_req_str = sign_req_str.replaceFirst("Base64ContentReplace", raw_b64); + if (logger_.isDebugEnabled()) + { + //logger_.debug(sign_request_filename + "_request.xml :"+ sign_req_str); + } + + return sign_req_str; + } + + public String prepareVerifyRequest(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + String verify_request = getVerifyRequestTemplateFileName(sigObject.getSignationType()); + String verify_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request)); + + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_request); + } + + String verify_template_str = null; + if (sigObject.isMOASigned()) + { + MOAConnector moa_conn = new MOAConnector(); + // get the MOA-template + verify_template_str = moa_conn.getVerifyTemplate(normalizedText, sigObject); + } + else + { + // get the BKU-template + verify_template_str = getVerifyTemplate(normalizedText, sigObject); + } + verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str); + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_request + "_request.xml : " + verify_req_str); + } + + return verify_req_str; + } + + /** + * Sends the request to the given URL. + * + * @param url + * The URL. + * @param request_string + * The request string. + * @return Returns the response string. + * @throws SignatureException + * F.e. + */ + protected String sendRequest(String url, String request_string) throws SignatureException + { + try + { + String response_string = BKUPostConnection.doPostRequest(url, request_string); + return response_string; + } + catch (Exception e) + { + SignatureException se = new SignatureException(320, e); + throw se; + } + } + + public SignatureObject analyzeSignResponse(String response_string, + String sigType) throws SignatureException + { + //String sign_request_filename = getSignRequestTemplateFileName(sigType); + + SignatureObject sig_obj = new SignatureObject(); + sig_obj.setRawSignatureResponse(response_string); + try + { + sig_obj.setSigType(sigType); + sig_obj.initByType(); + } + catch (SignatureTypesException e) + { + SignatureException se = new SignatureException(300, "Cannot init signature object with type:" + sigType, e); + throw se; + } + if (logger_.isDebugEnabled()) + { + logger_.debug("Signature Type is:" + sig_obj.getSignationType()); + } + + if (!response_string.equals("")) + { + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + // System.err.println(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + //logger_.debug(sign_request_filename + "_response.xml : " + response_string); + logger_.error("BKU Error response: " + response_string); + } + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + SignatureException se = new SignatureException(0, "BKUSigExc"); + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + se.setExternalErrorCode(error_code); + if (erm_m_s.find() && erm_m_e.find()) + { + String error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + se.setExternalErrorMessage(error_mess); + } + throw se; + } + else + { + if (logger_.isDebugEnabled()) + { + //logger_.debug(sign_request_filename + "_response.xml : " + response_string); + } + parseCreateXMLResponse(response_string, sig_obj); + } + } + sig_obj.setSigResponse(response_string); + return sig_obj; + } + + public SignatureResponse analyzeVerifyResponse(String response_string) throws SignatureException + { + if (!response_string.equals("")) + { + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + //logger_.debug(getType() + "_response.xml : " + response_string); + logger_.error(getType() + "_response.xml : " + response_string); + } + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + SignatureException se = new SignatureException(0, "BKUSigExc"); + if (erc_m_s.find() && erc_m_e.find()) + { + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + se.setExternalErrorCode(error_code); + } + if (erm_m_s.find() && erm_m_e.find()) + { + String error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + se.setExternalErrorMessage(error_mess); + } + throw se; + } + else + { + if (logger_.isDebugEnabled()) + { + //logger_.debug(getType() + "_response.xml : " + response_string); + } + return parseVerifyXMLResponse(response_string); + } + } + return null; + } + + protected String getConnectorValueFromProfile(String profile, String key) + { + String value = settings_.getValueFromKey("sig_obj." + profile + "." + key); + if (value == null) + { + value = settings_.getValueFromKey(key); + } + return value; + } + + public String getSignURL(String profile) + { + final String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignRequestTemplateFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignKeyboxIdentifier(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".KeyboxIdentifier"; + return getConnectorValueFromProfile(profile, key); + } + + public String getVerifyURL(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyRequestTemplateFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyTemplateFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSigPropFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template.SP"; + return getConnectorValueFromProfile(profile, key); + } + + /** + * Returns the type of this BKU-like connector. + * + *

+ * All settings keys will be prefixed by this type. So to reuse the BKU + * connector, a deriving class has to implement this method specifying an own + * type. + *

+ * + * @return Returns the type of this BKU-like connector. + */ + protected String getType() + { + return CONNECTOR_INFORMATION.getIdentifier(); + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java new file mode 100644 index 0000000..773b248 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: BKUPostConnection.java,v 1.3 2006/10/11 07:56:10 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.io.IOException; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; + +/** + * @author wprinz + */ +public abstract class BKUPostConnection +{ + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(BKUPostConnection.class); + + /** + * This method connects the BKU server getting the request and the url. The + * request is an XML Message send and recieve by the HttpClient module. The + * Response message of the BKU server is is send back to the calling method. + * + * @param url + * the URL which the BKU server is running + * @param request + * the request string (XML) to send. + * @return the response string (XML) of the BKU server + * @throws IOException + * @throws HttpException + * ErrorCode:320 + */ + public static String doPostRequest(String url, String request) throws HttpException, IOException + { + + PostMethod post_method = new PostMethod(url); + + // It is very important to specify the charset of the content (the request) + // as UTF-8 this way. + // The HttpClient will then perform the URL encoding assuming that the + // request is UTF-8 as the BKU expects. + // If the MethodParams are omitted, the HttpClient will assume that the + // request is ISO-8859-1 and thereby the BKU cannot properly decode it. + HttpMethodParams method_params = new HttpMethodParams(); + method_params.setContentCharset("UTF-8"); + post_method.setParams(method_params); + + // This is just a hint: do not set the content-type this way or the BKU will + // assume it as text/XML, but the HttpClient sends it as URL-encoded. + // The HttpClient will automatically generate the proper Content-Type: + // application/x-www-form-urlencoded + // post.addRequestHeader(new Header("Content-Type", + // "text/xml;charset=UTF-8")); + + NameValuePair[] data = { new NameValuePair("XMLRequest", request) }; + post_method.setRequestBody(data); + + HttpClient http_client = new HttpClient(); + int method_response = http_client.executeMethod(post_method); + logger_.debug("method_response = " + method_response); + + byte[] response_body = post_method.getResponseBody(); + String response_string = new String(response_body, "UTF-8"); + + // Alternatively this could be used. + // The HttpClient is assumed to use the Content-Type provided by the + // response. + // String response_string = post.getResponseBodyAsString(); + + return response_string; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java new file mode 100644 index 0000000..a50dd1e --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java @@ -0,0 +1,35 @@ +/** + * + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +/** + * This class contains the key constants used by the Connectors to retrieve + * templates etc. from the Configuration. + * + * @author wprinz + */ +public abstract class ConnectorConfigurationKeys +{ + + /** + * The application mode sign + */ + public static final String VALUE_MODE_SIGN = "sign"; + + /** + * The application mode verify + */ + public static final String VALUE_MODE_VERIFY = "verify"; + + /** + * The key used to read out the available for web property. + */ + public static final String AVAILABLE_FOR_WEB = "available_for_web"; + + /** + * The key used to read out the available for commandline property. + */ + public static final String AVAILABLE_FOR_COMMANDLINE = "available_for_commandline"; + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java new file mode 100644 index 0000000..de1ee57 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java @@ -0,0 +1,880 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: MOAConnector.java,v 1.5 2006/10/31 08:18:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.rpc.Call; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceFactory; + +import org.apache.axis.message.SOAPBodyElement; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; +import org.w3c.dom.Document; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.exceptions.WebException; +import at.knowcenter.wag.egov.egiz.sig.Connector; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +/** + * Connector to access the MOA service. + * + * @author wlackner + * @author wprinz + */ +public class MOAConnector implements Connector +{ + /** + * ConnectorInformation that identifies this Connector to the system. + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * @see ConnectorInformation + */ + public static final ConnectorInformation CONNECTOR_INFORMATION = new ConnectorInformation("moa", "MOA"); + + /** + * The class type value. + * + *

+ * Just for convenience. + *

+ */ + private static final String TYPE = CONNECTOR_INFORMATION.getIdentifier(); + + /** + * The connector description. + */ + public static final String DESCRIPTION = "MOA"; + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * MOA siganture verification mode + */ + public static final String SERVICE_VERIFY = "SignatureVerification"; + + /** + * MOA siganture creation mode + */ + public static final String SERVICE_SIGN = "SignatureCreation"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(MOAConnector.class); + + /** + * The empty constructor + */ + public MOAConnector() throws SignatureException + { + loadSettings(); + } + + /** + * load the inital signature settings + * + * @see SettingsReader + */ + private void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + } + + /** + * This method calls the MOA signing a given text. The signaton type is to + * used initializing the corresponding SigantureObject. The initialized + * SignatureObject is filled out by the parsed MOA-Response.
+ * If an error request is send back from MOA, an error message is generated an + * an exception is thrown. + * + * @param sigType + * the type of the SignatureObject that should be returned + * @param userName + * the name of the user calling this method + * @param signText + * the text that shoulf be signed from MOA + * @return the complete SingatureObject of the given type filled by values + * from the MOA-Request + * @throws SignatureException + * ErrorCode 300 + * @see SignatureObject + */ + public SignatureObject doSign(String sigType, String userName, String signText) throws SignatureException + { + SignatureObject sig_obj = new SignatureObject(); + try + { + sig_obj.setSigType(sigType); + sig_obj.initByType(); + } + catch (SignatureTypesException e) + { + SignatureException se = new SignatureException(300, "Can ot init signature object with type:" + sigType, e); + throw se; + } + if (logger_.isDebugEnabled()) + { + logger_.debug("Signature Type is:" + sig_obj.getSignationType()); + } + if (logger_.isInfoEnabled()) + { + logger_.info("Call " + TYPE + " from user:" + userName); + } + + String url = getSignURL(sigType); + + String sign_request_filename = getSignRequestTemplateFileName(sigType); + String key_ident = getSignKeyIdentifier(sigType); + String sign_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + if (sign_req_str == null) + { + SignatureException se = new SignatureException(300, "File not found:" + sign_request_filename); + throw se; + } + + sign_req_str = sign_req_str.replaceFirst("KeyIdentifierReplace", key_ident); + if (logger_.isDebugEnabled()) + { + logger_.debug("error_signature_response = " + sign_req_str); + // FileHelper.writeToFile(sign_request_filename + "_signText.xml", + // signText); + } + // sign_req_str = sign_req_str.replaceFirst("XMLContentReplace", signText); + // now use the the base64 Template + signText = CodingHelper.encodeUTF8AsBase64(signText); + sign_req_str = sign_req_str.replaceFirst("Base64ContentReplace", signText); + if (logger_.isDebugEnabled()) + { + //logger_.debug(sign_req_str); + // FileHelper.writeToFile(sign_request_filename + "_request.xml", + // sign_req_str); + } + + String response_string = ""; + try + { + response_string = MOAConnector.connectMOA(sign_req_str, MOAConnector.SERVICE_SIGN, url); + sig_obj.setRawSignatureResponse(response_string); + } + catch (WebException we) + { + if (logger_.isDebugEnabled()) + { + we.printStackTrace(); + } + SignatureException se = new SignatureException(we.getErrorCode(), we); + throw se; + } + + if (!response_string.equals("")) + { + if (logger_.isInfoEnabled()) + { + logger_.info("get MOA response"); + } + Pattern erc_p_s = Pattern.compile(""); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + // System.err.println(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + logger_.error("error_signature_response = " + response_string); + // FileHelper.writeToFile(sign_request_filename + "_response.xml", + // response_string); + //logger_.error("Write error response to file:" + sign_request_filename + "_response.xml"); + } + Pattern erm_p_s = Pattern.compile(""); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + logger_.debug("error_code = " + error_code); + String error_mess = ""; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + logger_.debug(error_mess); + } + SignatureException se = new SignatureException(0, "MOASigExc ext error code = " + error_code + ", err_mess = " + error_mess); + se.setExternalErrorCode(error_code); + se.setExternalErrorMessage(error_mess); + throw se; + } + else + { + if (logger_.isDebugEnabled()) + { + logger_.debug("error_signature_response = " + response_string); + // FileHelper.writeToFile(sign_request_filename + "_response.xml", + // response_string); + } + parseCreateXMLResponse(response_string, sig_obj); + } + } + sig_obj.setSigResponse(response_string); + return sig_obj; + } + + /** + * This method parses the MOA-Response string. It separates the + * SignatureValue, X509IssuerName, SigningTime, X509SerialNumber, + * X509Certificate, CertDigest and DigestValues. If the X509Certificate is + * extracted it would be stored in the certificates directory. + * + * @param xmlResponse + * the response string from the MOA sign-request + * @param sigObj + * the SignatureObject that should be filled + * @throws SignatureException + * ErrorCode (303, 304) + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + private void parseCreateXMLResponse(String xmlResponse, SignatureObject sigObj) throws SignatureException + { + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); + Pattern sig_val_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); + Pattern sig_tim_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>"); + Pattern ser_num_p_e = Pattern.compile(""); + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); + Pattern sig_cer_p_e = Pattern.compile(""); + + Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>"); + Pattern sig_cer_d_p_e = Pattern.compile(""); + Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>"); + Pattern dig_val_p_e = Pattern.compile(""); + + Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse); + Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse); + Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse); + + String sig_val = ""; + String iss_nam = ""; + String ser_num = ""; + String sig_tim = ""; + String sig_cer = ""; + String sig_dig = ""; + + // SignatureValue + if (sig_val_m_s.find() && sig_val_m_e.find()) + { + sig_val = xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start()); + sig_val = sig_val.replaceAll("\\s", ""); + sigObj.setSignationValue(sig_val); + } + // X509IssuerName + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sigObj.setSignationIssuer(iss_nam); + } + // X509SerialNumber + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sigObj.setSignationSerialNumber(ser_num); + } + // SigningTime + if (sig_tim_m_s.find() && sig_tim_m_e.find()) + { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + sigObj.setSignationDate(sig_tim); + } + // CertDigest + if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find()) + { + String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), sig_cer_d_m_e.start()); + Matcher dig_val_m_s = dig_val_p_s.matcher(cert_digest); + Matcher dig_val_m_e = dig_val_p_e.matcher(cert_digest); + if (dig_val_m_s.find() && dig_val_m_e.find()) + { + sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start()); + sigObj.setX509CertificateDigest(sig_dig); + } + } + // extract Subject Name from X509Certificate + if (sig_cer_m_s.find() && sig_cer_m_e.find()) + { + sig_cer = xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start()); + sig_cer = sig_cer.replaceAll("\\s", ""); + X509Cert cert = X509Cert.initByString(sig_cer); + if (cert.isX509Cert()) + { + sigObj.setX509Certificate(cert.getCertString()); + String serial_num = cert.getSerialNumber(); + String subject_name = cert.getSubjectName(); + if (!ser_num.equals(serial_num)) + { + SignatureException se = new SignatureException(303, "Serialnumber of certificate and tag X509SerialNumber differs!"); + throw se; + } + sigObj.setSignationName(subject_name); + } + } + } + + /** + * This method reads the verify template from the file system and fills out + * the template with the SignatureObject values. + * + * @param normalizedText + * the normalized text to veryfied + * @param sigObject + * the SignatureObject holding the singature values + * @return the filled verify template string + * @throws SignatureException + * ErrorCode (311, 312, 313) + * @see SignatureObject + * @see CodingHelper + */ + public String getVerifyTemplate(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + try + { + if (normalizedText == null || normalizedText.length() == 0) + { + SignatureException se = new SignatureException(311, "Document can not be verified because normalized text is empty."); + throw se; + } + if (sigObject == null) + { + SignatureException se = new SignatureException(312, "Document can not be verified because no signature object are set."); + throw se; + } + String verify_template = getVerifyTemplateFileName(sigObject.getSignationType()); + String sig_prop_template = getSigPropFileName(sigObject.getSignationType()); + String verify_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_template)); + String sig_prop_str = FileHelper.readFromFile(SettingsReader.relocateFile(sig_prop_template)); + + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_template); + //logger_.debug(sig_prop_template); + } + + String x509Certificate = sigObject.getX509CertificateString(); + if (x509Certificate == null) + { + SignatureException se = new SignatureException(313, "Document certificate is not defined."); + throw se; + } + String cert_alg = settings_.getValueFromKey("cert.alg.ecdsa"); + X509Cert x509_cert = sigObject.getX509Cert(); + if (x509_cert.isRSA()) + { + cert_alg = settings_.getValueFromKey("cert.alg.rsa"); + } + + sig_prop_str = sig_prop_str.replaceFirst("SigningTimeReplace", sigObject.getSignationDate()); + // The issuer is already a valid Unicode String. + // No need to convert it - not to mention the missing encoding. + // byte[] issuer_name = + // CodingHelper.encodeUTF8(sigObject.getSignationIssuer()); + // new String(issuer_name) + sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", sigObject.getSignationIssuer()); + sig_prop_str = sig_prop_str.replaceFirst("X509SerialNumberReplace", sigObject.getSignationSerialNumber()); + sig_prop_str = sig_prop_str.replaceFirst("DigestValueX509CertificateReplace", sigObject.getX509CertificateDigest()); + + verify_req_str = verify_req_str.replaceFirst("CertAlgReplace", cert_alg); + verify_req_str = verify_req_str.replaceFirst("TemplateSignedPropertiesReplace", sig_prop_str); + byte[] sig_prop_code = CodingHelper.buildDigest(sig_prop_str.getBytes("UTF-8")); // added + // the + // ("UTF-8") + // encoding + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + verify_req_str = verify_req_str.replaceFirst("DigestValueSignedPropertiesReplace", sig_prop_hash); + if (logger_.isDebugEnabled()) + { + logger_.debug("build digest from SignedProperties:start"); + //logger_.debug("DATA :" + sig_prop_str); + logger_.debug("DIGEST:" + sig_prop_hash); + logger_.debug("build digest from SignedProperties:end"); + } + + verify_req_str = verify_req_str.replaceFirst("SignatureValueReplace", sigObject.getSignationValue()); + verify_req_str = verify_req_str.replaceFirst("X509CertificateReplace", x509Certificate); + byte[] data_value = normalizedText.getBytes("UTF-8"); + byte[] data_value_hash = CodingHelper.buildDigest(data_value); + // byte[] data_value_hash = + // CodingHelper.buildDigest(normalizedText.getBytes()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + //String object_data = normalizedText; // new String(data_value); + // System.err.println(object_data_hash); + // very_req_str = very_req_str.replaceFirst("ObjectDataReplace", + // object_data); + String raw_b64 = CodingHelper.encodeBase64(data_value); + verify_req_str = verify_req_str.replaceFirst("Base64ContentReplace", raw_b64); + + verify_req_str = verify_req_str.replaceFirst("DigestValueSignedDataReplace", object_data_hash); + if (logger_.isDebugEnabled()) + { + // FileHelper.writeToFile(verify_template + "_verifyText.xml", + // normalizedText); + logger_.debug("build digest from data object:start"); + //logger_.debug("DATA :" + object_data); + logger_.debug("DIGEST:" + object_data_hash); + logger_.debug("build digest from data object:end"); + } + return verify_req_str; + } + catch (UnsupportedEncodingException e) + { + throw new SignatureException(310, e); + } + } + + /** + * This method generates the MOA verify prozess. It checks if the given + * SignatureObject is signed by MOA or BKU. The verify template string is + * filled out by the corresponding method. + * + * @param normalizedText + * the normalized text to verify + * @param sigObject + * the SignatureObject holding the singature values + * @return a SignatureResponse object if the verify prozess does not fails + * @throws SignatureException + * @see SignatureResponse + */ + public SignatureResponse doVerify(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + String verify_url = getVerifyURL(sigObject.getSignationType()); // settings_.getValueFromKey(TYPE + // + "." + + // Signature.VALUE_MODE_VERIFY + // + + // ".url"); + String verify_request = getVerifyRequestTemplateFileName(sigObject.getSignationType()); // settings_.getValueFromKey(TYPE + // + + // "." + // + + // Signature.VALUE_MODE_VERIFY + // + + // ".request"); + String trust_profile = getVerifyTrustProfileID(sigObject.getSignationType()); + String verify_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request)); + + String verify_template_str = null; + if (sigObject.isMOASigned()) + { + verify_template_str = getVerifyTemplate(normalizedText, sigObject); + } + else + { + BKUConnector bku_conn = new BKUConnector(); + verify_template_str = bku_conn.getVerifyTemplate(normalizedText, sigObject); + } + verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str); + verify_req_str = verify_req_str.replaceFirst("TrustProfileIDReplace", trust_profile); + + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_req_str); + // FileHelper.writeToFile(verify_request + "_request.xml", + // verify_req_str); + } + String response_string = ""; + try + { + response_string = MOAConnector.connectMOA(verify_req_str, MOAConnector.SERVICE_VERIFY, verify_url); + } + catch (WebException we) + { + if (logger_.isDebugEnabled()) + { + we.printStackTrace(); + } + SignatureException se = new SignatureException(we.getErrorCode(), we); + throw se; + } + + if (!response_string.equals("")) + { + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + //logger_.debug(response_string); + // FileHelper.writeToFile(verify_request + "_response.xml", + // response_string); + logger_.error("Write error response to file:" + verify_request + "_response.xml"); + } + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + SignatureException se = new SignatureException(0, "MOASigExc2"); + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + se.setExternalErrorCode(error_code); + if (erm_m_s.find() && erm_m_e.find()) + { + String error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + se.setExternalErrorMessage(error_mess); + } + throw se; + } + else + { + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_request + "_response.xml " + response_string); + } + return parseVerifyXMLResponse(response_string); + } + } + return null; + } + + /** + * This method parses the verify response string and return a + * SignatureResponse object. The SignatureResponse object is filled out by the + * response values from the BKU-response. + * + * @param xmlResponse + * the response values from the MOA-verify request + * @return SignatureResponse object + * @see SignatureResponse + */ + private SignatureResponse parseVerifyXMLResponse(String xmlResponse) + { + if (logger_.isInfoEnabled()) + { + logger_.info("Try parsing the verify response"); + } + Pattern sub_nam_p_s = Pattern.compile(""); + Pattern sub_nam_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile(""); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile(""); + Pattern ser_num_p_e = Pattern.compile(""); + + Pattern sig_chk_p_s = Pattern.compile(""); + Pattern sig_chk_p_e = Pattern.compile(""); + Pattern man_chk_p_s = Pattern.compile(""); + Pattern man_chk_p_e = Pattern.compile(""); + Pattern cer_chk_p_s = Pattern.compile(""); + Pattern cer_chk_p_e = Pattern.compile(""); + + Pattern code_p_s = Pattern.compile(""); + Pattern code_p_e = Pattern.compile(""); + + Pattern cert_p_s = Pattern.compile(""); + Pattern cert_p_e = Pattern.compile(""); + + Matcher sub_nam_m_s = sub_nam_p_s.matcher(xmlResponse); + Matcher sub_nam_m_e = sub_nam_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + + Matcher sig_chk_m_s = sig_chk_p_s.matcher(xmlResponse); + Matcher sig_chk_m_e = sig_chk_p_e.matcher(xmlResponse); + Matcher man_chk_m_s = man_chk_p_s.matcher(xmlResponse); + Matcher man_chk_m_e = man_chk_p_e.matcher(xmlResponse); + Matcher cer_chk_m_s = cer_chk_p_s.matcher(xmlResponse); + Matcher cer_chk_m_e = cer_chk_p_e.matcher(xmlResponse); + + Matcher cert_m_s = cert_p_s.matcher(xmlResponse); + Matcher cert_m_e = cert_p_e.matcher(xmlResponse); + + SignatureResponse sig_res = new SignatureResponse(); + if (sub_nam_m_s.find() && sub_nam_m_e.find()) + { + String sub_nam = xmlResponse.substring(sub_nam_m_s.end(), sub_nam_m_e.start()); + sig_res.setX509SubjectName(sub_nam); + } + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + String iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sig_res.setX509IssuerName(iss_nam); + } + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + String ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sig_res.setX509SerialNumber(ser_num); + } + if (sig_chk_m_s.find() && sig_chk_m_e.find()) + { + String sig_chk = xmlResponse.substring(sig_chk_m_s.end(), sig_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(sig_chk); + Matcher code_m_e = code_p_e.matcher(sig_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = sig_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureCheckCode(code); + } + } + if (man_chk_m_s.find() && man_chk_m_e.find()) + { + String man_chk = xmlResponse.substring(man_chk_m_s.end(), man_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(man_chk); + Matcher code_m_e = code_p_e.matcher(man_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = man_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureManifestCheckCode(code); + } + } + if (cer_chk_m_s.find() && cer_chk_m_e.find()) + { + String cer_chk = xmlResponse.substring(cer_chk_m_s.end(), cer_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(cer_chk); + Matcher code_m_e = code_p_e.matcher(cer_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = cer_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setCertificateCheckCode(code); + } + } + if (cert_m_s.find() && cert_m_e.find()) + { + String cert_string = xmlResponse.substring(cert_m_s.end(), cert_m_e.start()); + + X509Cert resp_cert = X509Cert.initByString(cert_string); + sig_res.setCertificate(resp_cert); + } + + return sig_res; + } + + protected String getConnectorValueFromProfile(String profile, String key) + { + String value = settings_.getValueFromKey("sig_obj." + profile + "." + key); + if (value == null) + { + value = settings_.getValueFromKey(key); + } + return value; + } + + public String getSignURL(String profile) + { + final String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignRequestTemplateFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignKeyIdentifier(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".KeyIdentifier"; + return getConnectorValueFromProfile(profile, key); + } + + public String getVerifyURL(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyRequestTemplateFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyTemplateFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSigPropFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template.SP"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyTrustProfileID(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".TrustProfileID"; + return getConnectorValueFromProfile(profile, key); + } + + /** + * This method connects the moa server getting the requestString, the given + * serviseMode and the endpointUrl. The requestString is the envelope of the + * SOAP Message send and recieve by the AXIS module. The Response SOAP message + * of the MOA server is parsed by AXIS and the message envelope is send back + * to the calling method. + * + * @param requestString + * the request string (XML) to send. + * @param serviceMode + * the mode which connect to MOA + * @param endpointURL + * the URL which the MOA server is running + * @return the response string (XML) of the MOA server + * @throws WebException + */ + public static String connectMOA(String requestString, String serviceMode, + String endpointURL) throws WebException + { + try + { + if (logger_.isInfoEnabled()) + { + logger_.info(serviceMode); + logger_.info(endpointURL); + } + // Parser/DOMBuilder instanzieren + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + + // XML Datei in einen DOM-Baum umwandeln + ByteArrayInputStream bais = new ByteArrayInputStream(requestString.getBytes("UTF-8")); + Document xmlRequest = builder.parse(bais); + + // Call öffnen + Call call = null; + + // Neues BodyElement anlegen und mit dem DOM-Baum füllen + SOAPBodyElement body = new SOAPBodyElement(xmlRequest.getDocumentElement()); + SOAPBodyElement[] params = new SOAPBodyElement[] { body }; + + // AXIS-Server instanzieren + Service service = ServiceFactory.newInstance().createService(new QName(serviceMode)); + call = service.createCall(); + call.setTargetEndpointAddress(endpointURL); + + // Call auslösen und die Antworten speichern + if (logger_.isInfoEnabled()) + { + logger_.info("Calling MOA:" + endpointURL); + } + Vector responses = (Vector) call.invoke(params); + + // Erstes Body Element auslesen + SOAPBodyElement response = (SOAPBodyElement) responses.get(0); + + // Aus der Response den DOM-Baum lesen + Document root_response = response.getAsDocument(); + if (logger_.isInfoEnabled()) + { + logger_.info("Return from MOA:" + serviceMode); + } + + // XML-Formatierung konfiguieren + OutputFormat format = new OutputFormat((Document) root_response); + format.setLineSeparator("\n"); + format.setIndenting(false); + format.setPreserveSpace(true); + format.setOmitXMLDeclaration(false); + format.setEncoding("UTF-8"); + + // Ausgabe der Webservice-Antwort auf die Konsole + // XMLSerializer conSerializer = new XMLSerializer(System.out, format); + // conSerializer.serialize(root_response); + + // Ausgabe der Webservice-Antwort in Datei + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + XMLSerializer response_serializer = new XMLSerializer(baos, format); + response_serializer.serialize(root_response); + return baos.toString("UTF-8"); + } + catch (Exception e) + { + throw new WebException(330, e); + } + // serialize signature only + + // if + // (root_response.getDocumentElement().getLocalName().equals("CreateXMLSignatureResponse")) + // { + // Element signature = (Element) + // root_response.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", + // "Signature").item(0); + // String signatureFile = getProperty(mode + "Request").substring(0, + // getProperty(mode + + // "Request").lastIndexOf('.')) + ".Signature.xml"; + // fileSerializer = new XMLSerializer(new FileOutputStream(signatureFile), + // format); + // fileSerializer.serialize(signature); + // } + + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/table/Entry.java b/src/main/java/at/knowcenter/wag/egov/egiz/table/Entry.java new file mode 100644 index 0000000..3f2caa7 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/table/Entry.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: Entry.java,v 1.3 2006/08/25 17:08:19 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.table; + +import java.io.Serializable; + +/** + * This class implements a table entry for different types. A table entry can be + * styled and setting there column dimensions. The default value for the column + * dimension is 1. To declare the type of the entry use the public + * TYPE_ definitions. + * + * @author wlackner + */ +public class Entry implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7952755200668528348L; + + /** + * Type for a text entry. + */ + public final static int TYPE_CAPTION = 0; + + /** + * Type for a text entry. + */ + public final static int TYPE_VALUE = 1; + + /** + * Type for an image entry. + */ + public final static int TYPE_IMAGE = 2; + + /** + * Type for a table entry. + */ + public final static int TYPE_TABLE = 3; + + /** + * The type info holder, default value is 0! + */ + private int type_ = 0; + + /** + * The entry value. + */ + private Object value_ = null; + + /** + * The key value + */ + private String key_ = null; + + /** + * The entry style information. + */ + private Style style_ = null; + + /** + * The column dimension. + */ + private int colSpan_ = 1; + + /** + * Text wrap indicator, default is false. + */ + private boolean noWrap_ = false; + + /** + * The empty constructor. + */ + public Entry() + { + } + + /** + * A constructor setting the type and the value. + * + * @param type + * the entry type to set + * @param value + * the entry value to set + */ + public Entry(int type, Object value, String key) + { + type_ = type; + value_ = value; + key_ = key; + } + + /** + * @return Returns the entry style. + */ + public Style getStyle() + { + return style_; + } + + /** + * @param style + * The style to set. + */ + public void setStyle(Style style) + { + style_ = style; + } + + /** + * @return Returns the entry type. + */ + public int getType() + { + return type_; + } + + /** + * @param type + * The type to set. + */ + public void setType(int type) + { + type_ = type; + } + + /** + * @return Returns the entry value. + */ + public Object getValue() + { + return value_; + } + + /** + * @param value + * The value to set. + */ + public void setValue(Object value) + { + value_ = value; + } + + /** + * @return Returns the key. + */ + + public String getKey() + { + return key_; + } + + /** + * @param key + * The key to set. + */ + public void setKey(String key) + { + key_ = key; + } + + /** + * @return Returns the colSpan. + */ + public int getColSpan() + { + return colSpan_; + } + + /** + * @param colSpan + * The colSpan to set. + */ + public void setColSpan(int colSpan) + { + colSpan_ = colSpan; + } + + /** + * @return Returns the wrap indicator. + */ + public boolean isNoWrap() + { + return noWrap_; + } + + /** + * @param noWrap + * The wrap indicator to set. + */ + public void setNoWrap(boolean noWrap) + { + noWrap_ = noWrap; + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() + { + Object obj = getValue(); + String value = null; + if (obj != null) + { + value = obj.toString(); + } + return "Type:" + getType() + " Value:" + value + " ColSpan:" + getColSpan(); + } + +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/table/Style.java b/src/main/java/at/knowcenter/wag/egov/egiz/table/Style.java new file mode 100644 index 0000000..285361a --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/table/Style.java @@ -0,0 +1,368 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: Style.java,v 1.3 2006/08/25 17:08:19 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.table; + +import java.awt.Color; +import java.io.Serializable; + +/** + * This class implements an abstract style definiton used in tables or table entrys. Predefined + * values exists for valign and halign. Color definitions uses the native awt color declarations. + *
+ * The predefined keys are used in the setting definition file to style tables and table entries. + *
+ * It provides an static method to inherit style informations from a given style object. + * {@link at.knowcenter.wag.egov.egiz.table.Style#doInherit} + * + * + * @author wlackner + * @see java.awt.Color + */ +public class Style implements Serializable { + /** + * SVUID. + */ + private static final long serialVersionUID = 5855722896712428387L; + + /** + * valign statement key top + */ + public final static String TOP = "top"; + /** + * valign statement key middle + */ + public final static String MIDDLE = "middle"; + /** + * valign statement key bottom + */ + public final static String BOTTOM = "bottom"; + /** + * halign statement key left + */ + public final static String LEFT = "left"; + /** + * halign statement key center + */ + public final static String CENTER = "center"; + /** + * halign statement key right + */ + public final static String RIGHT = "right"; + + /** + * bgcolor key + */ + public final static String BGCOLOR = "bgcolor"; + /** + * halign key + */ + public final static String HALIGN = "halign"; + /** + * valign key + */ + public final static String VALIGN = "valign"; + /** + * padding key, default padding = 1 + */ + public final static String PADDING = "padding"; + /** + * border key, default border = 1;
+ * The border value is one value for all border lines of an entry or table!
+ * No separte definitions for top, right, bottom or left are possible. + */ + public final static String BORDER = "border"; + + /** + * Font key + */ + public final static String FONT = "font"; + + /** + * The value font key. + */ + public final static String VALUEFONT = "valuefont"; + + /** + * Font name HELVETICA + */ + public final static String HELVETICA = "HELVETICA"; + /** + * Font name TIMES_ROMAN + */ + public final static String TIMES_ROMAN = "TIMES_ROMAN"; + /** + * Font name COURIER + */ + public final static String COURIER = "COURIER"; + /** + * Font type NORMAL + */ + public final static String NORMAL = "NORMAL"; + /** + * Font type BOLD + */ + public final static String BOLD = "BOLD"; + /** + * Font type ITALIC + */ + public final static String ITALIC = "ITALIC"; + /** + * Font type BOLDITALIC + */ + public final static String BOLDITALIC = "BOLDITALIC"; + /** + * Font type UNDERLINE + */ + public final static String UNDERLINE = "UNDERLINE"; + /** + * Font type STRIKETHRU + */ + public final static String STRIKETHRU = "STRIKETHRU"; + + + /** + * all paddings initialized with the default padding value (1) + */ + private static final float DEFAULT_PADDING = 1; + /** + * all borders initialized with the default border value (1) + */ + private static final float DEFAULT_BORDER = 1; + /** + * The background color definition. + */ + private Color bgColor_ = null; + /** + * The current padding value -> initialized with the default padding value + */ + private float padding_ = DEFAULT_PADDING; + /** + * The current halign value -> initialized with left + */ + private String hAlign_ = LEFT; + /** + * The current valign value -> initialized with top + */ + private String vAlign_ = TOP; + /** + * The current border value -> initialized with the default border value + */ + private float border_ = DEFAULT_BORDER; + /** + * The font string of the style definition + */ + private String font_ = null; + /** + * The font string of the value font. + */ + private String valuefont_ = null; + + /** + * The empty constructor. + */ + public Style() { + } + + /** + * Set a style attribute. The style attribute must be one of the public definitions + * + * @param id the style attribute to set + * @param value the style value to set for the given attribute + */ + public void setStyle(String id, String value) { + if (BGCOLOR.equals(id)) { + String[] col_strg = value.split(" "); + if (col_strg.length == 3) { + int r = Integer.parseInt(col_strg[0]); + int g = Integer.parseInt(col_strg[1]); + int b = Integer.parseInt(col_strg[2]); + if (r < 256 && g < 256 && b < 256 && r >= 0 && g >= 0 && b >= 0) { + bgColor_ = new Color(r, g, b); + } + } + } + if (HALIGN.equals(id)) { + if (LEFT.equals(value) || CENTER.equals(value) || RIGHT.equals(value)) { + hAlign_ = value; + } + } + if (VALIGN.equals(id)) { + if (TOP.equals(value) || MIDDLE.equals(value) || BOTTOM.equals(value)) { + vAlign_ = value; + } + } + if (PADDING.equals(id)) { + padding_ = Float.parseFloat(value); + } + if (BORDER.equals(id)) { + border_ = Float.parseFloat(value); + } + if (FONT.equals(id)) { + font_ = value; + } + if (VALUEFONT.equals(id)) { + valuefont_ = value; + } + } + + /** + * @return Returns the bgColor. + */ + public Color getBgColor() { + return bgColor_; + } + + /** + * @param bgColor The bgColor to set. + */ + public void setBgColor(Color bgColor) { + bgColor_ = bgColor; + } + + /** + * @return Returns the hAlign. + */ + public String getHAlign() { + return hAlign_; + } + + /** + * @param align The hAlign to set. + */ + public void setHAlign(String align) { + hAlign_ = align; + } + + /** + * @return Returns the padding. + */ + public float getPadding() { + return padding_; + } + + /** + * @param padding The padding to set. + */ + public void setPadding(float padding) { + padding_ = padding; + } + + /** + * @return Returns the vAlign. + */ + public String getVAlign() { + return vAlign_; + } + + /** + * @param align The vAlign to set. + */ + public void setVAlign(String align) { + vAlign_ = align; + } + + /** + * @return Returns the border. + */ + public float getBorder() { + return border_; + } + + /** + * @param border The border to set. + */ + public void setBorder(float border) { + border_ = border; + } + + + /** + * @return Returns the font. + */ + public String getFont() { + return font_; + } + + /** + * @param font The font to set. + */ + public void setFont(String font) { + font_ = font; + } + + + /** + * Returns the value font. + * @return Returns the value font. + */ + public String getValueFont() + { + return valuefont_; + } + + /** + * Sets the value font. + * @param valuefont The value font to be set. + */ + public void setValueFont(String valuefont) + { + this.valuefont_ = valuefont; + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() { + return "bgcolor:" + getBgColor() + " halign:" + getHAlign() + " valign:" + getVAlign() + " padding:" + getPadding() + " border:" + getBorder() + " font:" + getFont() + " valuefont:" + getValueFont(); + } + + /** + * This method inherits all style attributes (values) from a given style object. A new style + * object is created if the base style object is null. If a value is not defined in the + * baseStyle object it would be inhert from the inheritStyle object. + * + * @param baseStyle the base style object that should be enhanced + * @param inhertStyle the style values that could inherit from + * @return an inherit style object + */ + public static Style doInherit(Style baseStyle, Style inhertStyle) { + if (baseStyle == null) { + baseStyle = new Style(); + } + if (inhertStyle != null) { + + if (baseStyle.getBgColor() == null) + baseStyle.setBgColor(inhertStyle.getBgColor()); + if (baseStyle.getBorder() == DEFAULT_BORDER) + baseStyle.setBorder(inhertStyle.getBorder()); + if (baseStyle.getHAlign() == null) + baseStyle.setHAlign(inhertStyle.getHAlign()); + if (baseStyle.getVAlign() == null) + baseStyle.setVAlign(inhertStyle.getVAlign()); + if (baseStyle.getPadding() == DEFAULT_PADDING) + baseStyle.setPadding(inhertStyle.getPadding()); + if (baseStyle.getFont() == null) + baseStyle.setFont(inhertStyle.getFont()); + if (baseStyle.getValueFont() == null) + baseStyle.setValueFont(inhertStyle.getValueFont()); + } + return baseStyle; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java b/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java new file mode 100644 index 0000000..ceea1f3 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: Table.java,v 1.2 2006/08/25 17:08:19 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.table; + +import java.io.Serializable; +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; + +/** + * This class implements an abstract table definition. The table contains table + * rows and the table rows contains the table entries. A table can be styled and + * a relative column width can be set. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.table.Style + * @see at.knowcenter.wag.egov.egiz.table.Entry + */ +public class Table implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 8488947943674086618L; + + /** + * The table column settings. + */ + private float[] colsRelativeWith_ = null; + + /** + * The row definitions. + */ + private Map rows_ = new HashMap(); + + /** + * The table width. + */ + private float width_ = 100; + + /** + * The table style. + */ + private Style style_ = null; + + /** + * Number of columns that are defined for the current table. + */ + private int maxCols_ = 0; + + /** + * A table name. + */ + private String name_ = null; + + /** + * The table constructor init by a table name. + * + * @param name + * the name for the table. + */ + public Table(String name) + { + name_ = name; + } + + /** + * The width of the columns are relative to each other. This means the values + * are summarized and divided into portions of columns used.
+ * Example: [1,4] means the second column is four times wider + * than the first column. + * + * @return Returns the relative width of the columns + */ + public float[] getColsRelativeWith() + { + return colsRelativeWith_; + } + + /** + * The width of the columns are relative to each other. This means the values + * are summarized and divided into portions of columns used.
+ * Example: [10,90] means the first colum consumes 10% and the + * second column consumes 90% of the table width.
+ * The relative width of the columns to set. + */ + public void setColsRelativeWith(float[] cols) + { + colsRelativeWith_ = cols; + } + + /** + * @return Returns the style. + */ + public Style getStyle() + { + return style_; + } + + /** + * @param style + * The style to set. + */ + public void setStyle(Style style) + { + style_ = style; + } + + /** + * @return Returns the width. + */ + public float getWidth() + { + return width_; + } + + /** + * @param width + * The width to set. + */ + public void setWidth(float width) + { + width_ = width; + } + + /** + * @return Returns the maxCols. + */ + public int getMaxCols() + { + return maxCols_; + } + + /** + * @return Returns the name. + */ + public String getName() + { + return name_; + } + + /** + * This method returns a sorted row list beginning with the row number 1. The + * entrys in a row also stored in a {@link ArrayList}. + * + * @return Returns the sorted (by row number) table rows. + */ + public ArrayList getRows() + { + ArrayList rows = new ArrayList(); + for (int row_idx = 1; row_idx <= rows_.size(); row_idx++) + { + ArrayList row = (ArrayList) rows_.get("" + row_idx); + rows.add(row); + } + return rows; + } + + /** + * Add a comlete table row to the current table. Be carefull usding the + * correct row number because no check is done if a row with the given row + * number does exist! In that case the stored row would be replaced! + * + * @param rowNumber + * the row number to store the row entries + * @param row + * the entry list to store + */ + public void addRow(String rowNumber, ArrayList row) + { + rows_.put(rowNumber, row); + if (row.size() > maxCols_) + { + maxCols_ = row.size(); + } + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() + { + String the_string = "\n#### TABLE " + name_ + " BEGIN #####"; + the_string += " Width:" + width_ + " max cols:" + maxCols_ + " cols:" + colsRelativeWith_; + the_string += "\nStyle:" + style_; + ArrayList rows = getRows(); + for (int row_idx = 0; row_idx < rows.size(); row_idx++) + { + ArrayList row = (ArrayList) rows.get(row_idx); + String row_prefix = "\n ++ ROW " + row_idx + " ++ "; + for (int entry_idx = 0; entry_idx < row.size(); entry_idx++) + { + the_string += row_prefix + ((Entry) row.get(entry_idx)).toString(); + } + } + the_string += "\n#### TABLE " + name_ + " END #####"; + return the_string; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/test/AbsTexTest.java b/src/main/java/at/knowcenter/wag/egov/egiz/test/AbsTexTest.java new file mode 100644 index 0000000..22b20ee --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/test/AbsTexTest.java @@ -0,0 +1,141 @@ +/** + * + */ +package at.knowcenter.wag.egov.egiz.test; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.pdf.AbsoluteTextSignature; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignature; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; + +/** + * Test file for testing the absolute text signature. + * @author wprinz + */ +public class AbsTexTest +{ + + /** + * The logger definition. + */ + private static final Logger logger = ConfigLogger.getLogger(AbsTexTest.class); + + /** + * @param args + * @throws IOException + * @throws PresentableException + */ + public static void main(String[] args) throws IOException, PresentableException + { + SettingsReader.initializeForCommandLine(); + PropertyConfigurator.configure(SettingsReader.CONFIG_PATH + "log4j.properties"); + + File BASE_DIR = new File("C:\\wprinz\\Filer\\egiz\\docs\\abstexsig"); + File original_file = new File(BASE_DIR, "AbsTexSig.pdf"); + File signed_file = new File(BASE_DIR, "AbsTexSig.pdf_out.pdf"); + File signed_signed_file = new File(BASE_DIR, "AbsTexSig.pdf_out.pdf_out.pdf"); + + File in = new File("C:\\wprinz\\Filer\\egiz\\docs\\Abnahmetests\\tests\\commandline\\alte_sig\\document4.pdf_asimoaold.pdf_out.pdf"); + byte[] pdf = readInFile(in); + + ByteArrayInputStream bais = new ByteArrayInputStream(pdf, 0, pdf.length); + String raw_text = TextualSignature.extractTextTextual(bais); + + String text = PdfAS.extractNormalizedTextTextual(pdf, pdf.length); + + writeTextToFile(raw_text, new File(BASE_DIR, "raw_text.utf8.txt")); + writeTextToFile(text, new File(BASE_DIR, "text.utf8.txt")); + + if (true) + { + return; + } + + String[] texts = new String[3]; + + byte[] original = readInFile(original_file); + byte[] signed = readInFile(signed_file); + byte[] signed2 = readInFile(signed_signed_file); + + texts[0] = PdfAS.extractNormalizedTextTextual(original, original.length); + texts[1] = PdfAS.extractNormalizedTextTextual(signed, signed.length); + texts[2] = PdfAS.extractNormalizedTextTextual(signed2, signed2.length); + + writeTextToFile(texts[0], new File(BASE_DIR, "original.utf8.txt")); + writeTextToFile(texts[1], new File(BASE_DIR, "signed.utf8.txt")); + writeTextToFile(texts[2], new File(BASE_DIR, "signed_signed.utf8.txt")); + + // String text = texts[2]; + + List holders = AbsoluteTextSignature.extractSignatureHoldersFromText(text); + logger.debug("extracted " + holders.size() + " holders:"); + for (int i = 0; i < holders.size(); i++) + { + SignatureHolder holder = (SignatureHolder) holders.get(i); + + logger.debug(" #" + i + ": " + holder.getSignatureObject().getSignationDate() + ", " + holder.getSignatureObject().getSignatureTypeDefinition().getType()); + } + + SignatureHolder sh_latest = (SignatureHolder) holders.get(1); + + SignatureHolder sh_earlier = (SignatureHolder) holders.get(0); + + writeTextToFile(sh_latest.getSignedText(), new File(BASE_DIR, "reconstructed_latest.utf8.txt")); + writeTextToFile(sh_earlier.getSignedText(), new File(BASE_DIR, "reconstructed.utf8.txt")); + + verifyReconstruction(sh_latest.getSignedText(), texts[1]); + verifyReconstruction(sh_earlier.getSignedText(), texts[0]); + + SignatureResponse sr = PdfAS.verify(sh_latest, "moa"); + System.out.println(sr); + sr = PdfAS.verify(sh_earlier, "moa"); + System.out.println(sr); + + } + + public static byte[] readInFile(File file) throws IOException + { + FileInputStream fis = new FileInputStream(file); + byte[] ba = new byte[(int) file.length()]; + fis.read(ba); + fis.close(); + return ba; + } + + public static void writeTextToFile(String text, File file) throws IOException + { + FileOutputStream fos = new FileOutputStream(file); + OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); + osw.write(text); + osw.close(); + } + + public static void verifyReconstruction(String reconstructed_text, + String expected_text) + { + if (reconstructed_text.equals(expected_text)) + { + System.out.println("TEXT MATCHED OK!"); + } + else + { + System.err.println("TEXT DIDN'T MATCH!!!!!!!"); + } + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/test/BinSig.java b/src/main/java/at/knowcenter/wag/egov/egiz/test/BinSig.java new file mode 100644 index 0000000..612ada1 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/test/BinSig.java @@ -0,0 +1,345 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: BinSig.java,v 1.1 2006/10/31 08:19:52 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.test; + +import java.awt.Color; +import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.pdf.Placeholder; +import at.knowcenter.wag.egov.egiz.pdf.SplitStrings; +import at.knowcenter.wag.egov.egiz.pdf.StringInfo; + +import com.lowagie.text.BadElementException; +import com.lowagie.text.Chunk; +import com.lowagie.text.Document; +import com.lowagie.text.DocumentException; +import com.lowagie.text.Font; +import com.lowagie.text.FontFactory; +import com.lowagie.text.Paragraph; +import com.lowagie.text.Phrase; +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.BaseFont; +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfIndirectReference; +import com.lowagie.text.pdf.PdfPCell; +import com.lowagie.text.pdf.PdfPTable; +import com.lowagie.text.pdf.PdfTemplate; +import com.lowagie.text.pdf.PdfWriter; + +/** + * @author wprinz + */ +public class BinSig +{ + + public static final String KEY_DATE = "Datum ÖÄÜ:"; + + public static final String KEY_SN = "Seriennummer öäü:"; + + public static final String KEY_SIGVAL = "Signaturwert ß:"; + + public static final String KEY_ISSUER = "Aussteller .,!?:"; + + /** + * @param args + * @throws DocumentException + * @throws IOException + * @throws PDFDocumentException + */ + public static void main(String[] args) throws DocumentException, IOException, PDFDocumentException + { + BinSig bs = new BinSig(); + bs.action(); + } + + public void action() throws IOException, DocumentException, PDFDocumentException + { + Document.compress = false; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + Document document = new Document(); + PdfWriter writer = PdfWriter.getInstance(document, baos); + + document.open(); + + Paragraph p1 = new Paragraph(new Chunk("This is my first paragraph. ", FontFactory.getFont(FontFactory.HELVETICA, 10))); + p1.add("The leading of this paragraph is calculated automagically. "); + p1.add("The default leading is 1.5 times the fontsize. "); + p1.add(new Chunk("You can add chunks ")); + p1.add(new Phrase("or you can add phrases. ")); + p1.add(new Phrase("Unless you change the leading with the method setLeading, the leading doesn't change if you add text with another leading. This can lead to some problems.", FontFactory.getFont(FontFactory.HELVETICA, 18))); + document.add(p1); + Paragraph p2 = new Paragraph(new Phrase("This is my second paragraph. ", FontFactory.getFont(FontFactory.HELVETICA, 12))); + p2.add("As you can see, it started on a new line."); + document.add(p2); + Paragraph p3 = new Paragraph("This is my third paragraph.", FontFactory.getFont(FontFactory.HELVETICA, 12)); + document.add(p3); + + PdfContentByte cb = writer.getDirectContent(); + + // Font tableFont = FontFactory.getFont(FontFactory.COURIER, + // Font.DEFAULTSIZE, Font.NORMAL); + // Font tableFont = FontFactory.getFont(FontFactory.HELVETICA, + // Font.DEFAULTSIZE, Font.NORMAL); + + BaseFont bf = BaseFont.createFont(BaseFont.COURIER, BaseFont.WINANSI, false); + Font tableFont = new Font(bf, 12); + + float padding = 0f; + Rectangle border = new Rectangle(0f, 0f); + border.setBorder(Rectangle.BOX); + border.setBorderWidth(1); + border.setBorderColor(Color.BLACK); + border.setBackgroundColor(new Color(.75f, .75f, 1f)); + PdfPTable table = makeTestPage(tableFont, border, padding, true, true); + + float width = 400; + table.setTotalWidth(width); + float height = table.getTotalHeight(); + + PdfTemplate template = cb.createTemplate(width, height); + + // we add some graphics + // template.moveTo(0, 200); + // template.lineTo(500, 0); + // template.rectangle(0, 0, width, height); + // template.setLineWidth(3); + // template.stroke(); + + table.writeSelectedRows(0, -1, 0, table.getTotalHeight(), template); + + // we add some text + // template.beginText(); + // template.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, + // BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 12); + // template.setTextMatrix(0, 0); + // template.showText("Text at the position 0,0 (relative to the + // template!)"); + // template.endText(); + + // we add the template on different positions + cb.addTemplate(template, 100, 500); + + PdfIndirectReference template_ref = template.getIndirectReference(); + System.out.println("template = " + template_ref.getNumber() + " " + template_ref.getGeneration()); + + document.close(); + + baos.close(); + byte[] pdf = baos.toByteArray(); + + // not the best solution to parse the stream, but work's for now. + String pdf_string = new String(pdf, "ISO-8859-1"); + int obj_start = pdf_string.lastIndexOf(template_ref.getNumber() + " " + template_ref.getGeneration() + " obj"); + int stream_start = pdf_string.indexOf("stream\n", obj_start) + 7; + int stream_end = pdf_string.indexOf("endstream\nendobj", stream_start); + int stream_len = stream_end - stream_start; + byte[] stream = new byte[stream_len]; + System.arraycopy(pdf, stream_start, stream, 0, stream_len); + + String stream_string = new String(stream, "ISO-8859-1"); + System.out.println(stream_string); + + List strings = Placeholder.parseStrings(pdf, stream_start, stream_end); + + List date = new ArrayList(); + List sn = new ArrayList(); + List sigval = new ArrayList(); + List issuer = new ArrayList(); + + List[] partitions = new List[] { date, sn, sigval, issuer }; + + Iterator it = strings.iterator(); + int cur_list = -1; + while (it.hasNext()) + { + StringInfo si = (StringInfo) it.next(); + + String str = si.getString("ISO-8859-1"); + + if (str.equals(KEY_DATE)) + { + cur_list = 0; + continue; + } + if (str.equals(KEY_SN)) + { + cur_list = 1; + continue; + } + if (str.equals(KEY_SIGVAL)) + { + cur_list = 2; + continue; + } + if (str.equals(KEY_ISSUER)) + { + cur_list = 3; + continue; + } + + partitions[cur_list].add(si); + } + + String date_orig = "The Date doesn't make problems."; + String sn_orig = "0123456789abcdefghijklmnopqrstuvwxyz0123456789"; + String sigval_orig = "ashdjklsbfkabsflkbadslkfblasdkfhajösdhfkjlasdhfkljasdbfljkasdhfljkasdhfljkasdhfasdfhj."; + String issuer_orig = "CN=Republik Österreich, \\\\O=Bund irgendwas, C=ÖÄÜsterreich, N=ein paar \\worte ohne (sinnn und) verstand #+ßÜ,ÄÖÜ;äöü"; + BinSig.replacePlaceholder(new SplitStrings(pdf, date), date_orig.getBytes("ISO-8859-1")); + BinSig.replacePlaceholder(new SplitStrings(pdf, sn), sn_orig.getBytes("ISO-8859-1")); + BinSig.replacePlaceholder(new SplitStrings(pdf, sigval), sigval_orig.getBytes("ISO-8859-1")); + Placeholder.replacePlaceholderWithTolerance(pdf, issuer, issuer_orig.getBytes("ISO-8859-1"), 10); + // replacePlaceholders(pdf, "CN=Seppl Maximilian Hötürälß, ÖÜÄß", (byte) + // 'Y'); + + byte [] enc = { 'w', 'i', 'n' }; + String date_rec = Placeholder.reconstructStringFromPartition(pdf, date, enc); + String sn_rec = Placeholder.reconstructStringFromPartition(pdf, sn, enc); + String sigval_rec = Placeholder.reconstructStringFromPartition(pdf, sigval, enc); + String issuer_rec = Placeholder.reconstructStringFromPartition(pdf, issuer, enc); + + System.out.println("date ok = " + date_orig.equals(date_rec)); + System.out.println("sn ok = " + sn_orig.equals(sn_rec)); + System.out.println("sigval ok = " + sigval_orig.equals(sigval_rec)); + System.out.println("issuer ok = " + issuer_orig.equals(issuer_rec)); + + FileOutputStream fos = new FileOutputStream("C:\\test.pdf"); + fos.write(pdf); + fos.close(); + + System.out.println("finished"); + + } + + private static PdfPTable makeTestPage(Font tableFont, Rectangle borders, + float padding, boolean ascender, boolean descender) throws BadElementException, DocumentException, IOException + { + // document.newPage(); + PdfPTable table = null; + table = new PdfPTable(2); + table.setWidthPercentage(100f); + + table.setWidths(new float[] { 30, 70 }); + + table.addCell(makeNormalCell(KEY_DATE)); + table.addCell(makeValueCell("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD")); + + table.addCell(makeNormalCell(KEY_SN)); + table.addCell(makeValueCell("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS")); + + table.addCell(makeNormalCell(KEY_SIGVAL)); + table.addCell(makeValueCell("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW")); + + table.addCell(makeNormalCell(KEY_ISSUER)); + table.addCell(makeValueCell("IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII")); + + return table; + } + + protected static PdfPCell makeCell(String text, int vAlignment, + int hAlignment, Font font, float leading, float padding, + Rectangle borders, boolean ascender, boolean descender) + { + Paragraph p = new Paragraph(text, font); + p.setLeading(leading); + + PdfPCell cell = new PdfPCell(p); + cell.setLeading(leading, 0); + cell.setVerticalAlignment(vAlignment); + cell.setHorizontalAlignment(hAlignment); + cell.cloneNonPositionParameters(borders); + cell.setUseAscender(ascender); + cell.setUseDescender(descender); + cell.setUseBorderPadding(true); + cell.setPadding(padding); + return cell; + } + + private static PdfPCell makeNormalCell(String text) + { + + Paragraph p = new Paragraph(text); + + PdfPCell cell = new PdfPCell(p); + cell.setBorder(PdfPCell.BOX); + cell.setBorderColor(Color.BLUE); + cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); + + return cell; + } + + private static PdfPCell makeValueCell(String placeholder) throws DocumentException, IOException + { + BaseFont bf = BaseFont.createFont(BaseFont.COURIER, BaseFont.WINANSI, false); + Font ff = new Font(bf, 12); + + Paragraph p = new Paragraph(placeholder, ff); + + PdfPCell cell = new PdfPCell(p); + cell.setBorder(PdfPCell.BOX); + cell.setBorderColor(Color.RED); + + return cell; + } + + protected boolean isPlaceholder(byte[] pdf, StringInfo si, byte placeholder) + { + for (int i = si.string_start; i < si.string_start + si.string_length; i++) + { + if (pdf[i] != placeholder) + { + return false; + } + } + return true; + } + + /** + * Replaces the given placeholders with the given bytes. + * @param ss The SplitStrings placeholders. + * @param replace_bytes The bytes to be filled in. + */ + public static void replacePlaceholder(SplitStrings ss, byte[] replace_bytes) + { + + for (int i = 0; i < replace_bytes.length; i++) + { + byte[] data = Placeholder.escapeByte(replace_bytes[i]); + if (!ss.fits(data)) + { + ss.newline(); + } + ss.write(data); + } + ss.fillRest(); + + // if (replace_read < replace_bytes.length) + // { + // System.err.println("The replace string was longer than the reserved placeholder."); + // throw new PlaceholderException(null, replace_bytes.length - replace_read); + // } + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/test/ExtractTextTextual.java b/src/main/java/at/knowcenter/wag/egov/egiz/test/ExtractTextTextual.java new file mode 100644 index 0000000..e2433b0 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/test/ExtractTextTextual.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ExtractTextTextual.java,v 1.1 2006/10/31 08:19:52 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.test; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; + +/** + * Test. + * + * @author wprinz + */ +public class ExtractTextTextual +{ + + /** + * @param args + * @throws IOException + * @throws PresentableException + */ + public static void main(String[] args) throws IOException, PresentableException + { + SettingsReader.initializeForCommandLine(); + + File in = new File(args[0]); + FileInputStream fis = new FileInputStream(in); + byte[] pdf = new byte[(int) in.length()]; + fis.read(pdf); + fis.close(); + + String text = PdfAS.extractNormalizedTextTextual(pdf, pdf.length); + + File out = new File(args[0] + ".txt"); + FileOutputStream fos = new FileOutputStream(out); + fos.write(text.getBytes("UTF-8")); + fos.close(); + + System.out.println("finished. written to " + out.getAbsolutePath()); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/test/X509.java b/src/main/java/at/knowcenter/wag/egov/egiz/test/X509.java new file mode 100644 index 0000000..059663a --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/test/X509.java @@ -0,0 +1,40 @@ +/** + * + */ +package at.knowcenter.wag.egov.egiz.test; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +/** + * @author wprinz + */ +public class X509 +{ + + /** + * @param args + * @throws CertificateException + * @throws IOException + */ + public static void main(String[] args) throws CertificateException, IOException + { + File file = new File ("C:\\tr-test.der"); + + InputStream is = new FileInputStream(file); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate)cf.generateCertificate(is); + is.close(); + + System.out.println("SerialNumber = " + cert.getSerialNumber()); + System.out.println("Issuer = " + cert.getIssuerDN().getName()); + + System.out.println("finished."); + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/test/X509Ext.java b/src/main/java/at/knowcenter/wag/egov/egiz/test/X509Ext.java new file mode 100644 index 0000000..30a489b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/test/X509Ext.java @@ -0,0 +1,48 @@ +/** + * + */ +package at.knowcenter.wag.egov.egiz.test; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Iterator; +import java.util.Set; + +/** + * @author wprinz + */ +public class X509Ext +{ + + /** + * @param args + * @throws CertificateException + * @throws IOException + */ + public static void main(String[] args) throws CertificateException, IOException + { + InputStream is = new FileInputStream("C:\\oid.der"); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate)cf.generateCertificate(is); + is.close(); + + Set oids = cert.getNonCriticalExtensionOIDs(); + Iterator it = oids.iterator(); + while (it.hasNext()) + { + String oid = (String) it.next(); + + System.out.println(oid); + } + + // Perhaps use IAIK JCE to parse this in a future version. + byte [] octet_stream = cert.getExtensionValue("1.2.40.0.10.1.1.1"); + System.out.println("octet_stream = " + octet_stream); + + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java b/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java new file mode 100644 index 0000000..7908486 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: CodingHelper.java,v 1.6 2006/10/11 07:52:36 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.tools; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.apache.commons.codec.binary.Base64; + +/** + * This class provides encoding and decoding methods and other coding methods. + * All methods are static! + * + * @author wlackner + */ +public class CodingHelper +{ + + /** + * Static Base64 object + */ + private static Base64 b64 = new Base64(); + + /** + * This method encodes a given Unicode (Java) String to UTF-8 bytes and then + * encodes these UTF-8 bytes to a Base64 US-ASCII (Java) String. + * + * @param plain_string + * to be encoded + * @return the UTF-8 and Base64 encoded string + */ + public static String encodeUTF8AsBase64(String plain_string) + { + try + { + byte[] utf8_bytes = plain_string.getBytes("UTF-8"); + byte[] base64_bytes = b64.encode(utf8_bytes); + String encoded_string = new String(base64_bytes, "US-ASCII"); + return encoded_string; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + /** + * This method decodes the UTF-8 bytes from a Base64 US-ASCII (Java) String + * and decodes the UTF-8 bytes to a unicode (Java) String. + * + * @param encoded_string + * to be decoded + * @return the Base64 and UTF-8 decoded string + */ + public static String decodeUTF8FromBase64(String encoded_string) + { + try + { + byte[] base64_bytes = encoded_string.getBytes("US-ASCII"); + byte[] utf8_bytes = b64.decode(base64_bytes); + String plain_string = new String(utf8_bytes, "UTF-8"); + return plain_string; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + // /** + // * This method encodes a given string UTF-8 + // * + // * @param theString to be encoded + // * @return the UTF-8 encoded string + // */ + // public static byte[] encodeUTF8(String theString) { + // byte[] utf8 = null; + // try { + // utf8 = theString.getBytes("UTF-8"); + // } catch (UnsupportedEncodingException e) { + // e.printStackTrace(); + // } + // return utf8; + // } + + // /** + // * This method decodes a given UTF-8 string + // * + // * @param theString to be decoded + // * @return the decoded UTF-8 string + // */ + // public static String decodeUTF8(String theString) { + // byte[] ba = theString.getBytes(); + // String the_string = decodeUTF8(ba); + // if (the_string != null) { + // return the_string; + // } + // return theString; + // } + + // /** + // * This method decodes a given UTF-8 byte array + // * + // * @param ba the byte array to be decoded + // * @return the decoded UTF-8 string + // */ + // public static String decodeUTF8(byte[] ba) { + // String the_string = null; + // try { + // the_string = new String(ba, "UTF-8"); + // } catch (UnsupportedEncodingException e) { + // e.printStackTrace(); + // } + // return the_string; + // } + + /** + * This method decodes a given Base64 string. + * + *

+ * Note that the given String must only contain Base64 characters. (The string + * will be converted to a byte array of "US-ASCII" (7 bit) bytes and then this + * byte array will be decoded using the Base64 algorithm. + *

+ * + * @param theString + * to be decoded + * @return a Base64 decoded byte array + */ + public static byte[] decodeBase64(String theString) + { + try + { + byte[] base64_bytes = theString.getBytes("US-ASCII"); + return b64.decode(base64_bytes); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException("Very Strange: US-ASCII encoding not supported???", e); + } + } + + /** + * This method decodes a given Base64 byte array + * + * @param ba + * the byte array to be decoded + * @return a Base64 decoded byte array + */ + public static byte[] decodeBase64(byte[] ba) + { + return b64.decode(ba); + } + + /** + * This method encodes a given byte array Base64 + * + * @param plainString + * the byte array to be encoded + * @return the Base64 encoded string + */ + public static String encodeBase64(byte[] plainString) + { + try + { + byte[] base64_bytes = b64.encode(plainString); + return new String(base64_bytes, "US-ASCII"); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException("Very Strange: US-ASCII encoding not supported???", e); + } + } + + /** + * This method builds an SHA-1 hash value of a given byte array. + * + * @param data + * the byte array to build the hash value for + * @return the calculated hash value as a byte array + * @see MessageDigest + */ + public static byte[] buildDigest(byte[] data) + { + MessageDigest sha_1 = null; + try + { + sha_1 = MessageDigest.getInstance("SHA-1"); + sha_1.update(data); + return sha_1.digest(); + } + catch (NoSuchAlgorithmException e) + { + return null; + } + } + + /** + * This method escapes a given string with HTML entities. + * + * @param rawString + * the string to escaped + * @return the HTML escaped string + */ + public static String htmlEscape(String rawString) + { + rawString = rawString.replaceAll("\\&", "&"); + rawString = rawString.replaceAll("\\<", "<"); + rawString = rawString.replaceAll("\\>", ">"); + rawString = rawString.replaceAll("\">", """); + return rawString; + } + + /** + * This method checks, if a byte array contains chars that are not base64 + * conform. + * + * @param byteArray + * the array to test + * @return boolean, if a byte array is base64 conform, false otherwise + */ + public static boolean isB64(byte[] byteArray) + { + try + { + return Base64.isArrayByteBase64(byteArray); + } + catch (ArrayIndexOutOfBoundsException e) + { + return false; + } + } + + /** + * This method checks, if a string contains chars that are not base64 conform. + * + * @param string + * the chars to test + * @return boolean, if the given string is base64 conform, false otherwise + */ + public static boolean isB64(String string) + { + try + { + return Base64.isArrayByteBase64(string.getBytes()); + } + catch (ArrayIndexOutOfBoundsException e) + { + return false; + } + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java b/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java new file mode 100644 index 0000000..0c1a420 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java @@ -0,0 +1,88 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: FileHelper.java,v 1.2 2006/05/15 12:05:21 wlackner Exp $ + */ +package at.knowcenter.wag.egov.egiz.tools; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.FileReader; +import java.io.FileWriter; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; + +/** + * This class provides file reader and writer methods. All methods are static! + * + * @author wlackner + */ +public class FileHelper { + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(FileHelper.class); + + /** + * This method reads a file by reading line by line. + * + * @param fileName the file to be read + * @return the content string of the file + */ + public static String readFromFile(String fileName) { + String file_string = null; + try { + BufferedReader reader = new BufferedReader(new FileReader(fileName)); + String line = null; + file_string = ""; + while ((line = reader.readLine()) != null) { + file_string += line; + } + reader.close(); + } catch (FileNotFoundException e) { + logger_.info("File not found:" + fileName); + } catch (IOException e) { + logger_.info("File can not read:" + fileName); + } + return file_string; + } + + /** + * This method writes a file line by line. + * + * @param fileName the file to be written + * @param fileString the content to be written + * @return true if the file could be written sucessfully, false otherwise + */ + public static boolean writeToFile(String fileName, String fileString) { + BufferedWriter writer; + try { + FileWriter fwriter = new FileWriter(fileName); + writer = new BufferedWriter(fwriter); + writer.write(fileString); + writer.close(); + } catch (IOException e) { + logger_.info("File:" + fileName + " can not be written. Cause:" + e.getMessage()); + return false; + } + return true; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalize.java b/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalize.java new file mode 100644 index 0000000..a2df327 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalize.java @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: Normalize.java,v 1.2 2006/05/15 12:05:21 wlackner Exp $ + */ +package at.knowcenter.wag.egov.egiz.tools; + + +/** + * Defines an interface to get access to different normalizer implementations. + * + * @author wlackner + */ +public interface Normalize { + + /** + * Normalize a given text. + * @param rawText the raw text to normalize + * @return the normalized string + */ + public String normalize(String rawText); + /** + * Return the current normalizer version string. + * @return the version string + */ + public String getVersion(); + + /** + * Returns the normalizer line separator string. + * @return the line separator string + */ + public String getNormCR(); + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/tools/NormalizeV01.java b/src/main/java/at/knowcenter/wag/egov/egiz/tools/NormalizeV01.java new file mode 100644 index 0000000..d3af9b5 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/tools/NormalizeV01.java @@ -0,0 +1,166 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: NormalizeV01.java,v 1.5 2006/10/31 08:20:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.tools; + +import java.io.Serializable; + +/** + * This ist the first version implementing a normalizer method. The normalize statements are + * performed by using regular expressions. + * + * @author wlackner + */ +public class NormalizeV01 implements Normalize, Serializable { + + /** + * SVUID. + */ + private static final long serialVersionUID = 2302956630639871601L; + + /** + * The space string + */ + private final static String NORM_SP = " "; //\u0020 + /** + * The line break string --> use only \n because XML-Parser ignores \r\n + */ + private final static String NORM_CR = "\n"; // + /** + * The apostrophe string + */ + private final static String NORM_AP = "'"; //\u0027 + /** + * The quotation mark string + */ + private final static String NORM_QU = "\""; //\u0022 + /** + * The hypens string + */ + private final static String NORM_HY = "-"; //\u002D + /** + * The current version string + */ + protected static final String VERSION = "V01"; + + /** + * The empty constructor. + */ + public NormalizeV01() { + } + + /** + * The normalizer implementation.
+ * Normalizer algorithums: + *
    + *
  1. code all multiple line breaks as \n\n
  2. + *
  3. replace all Tabs and form feeds with spaces
  4. + *
  5. code line breaks as \n
  6. + *
  7. reduce all multiple line breaks into one line break, code line break as \r
  8. + *
  9. replace all single line breaks with space
  10. + *
  11. normalize spaces
  12. + *
  13. remove spaces before and after a line break
  14. + *
  15. remove leading and trailing space or line break in the string
  16. + *
  17. normalize line breaks
  18. + *
  19. normalize apostrophes
  20. + *
  21. normalize quotations
  22. + *
  23. normalize hypens
  24. + *
+ * + * @see at.knowcenter.wag.egov.egiz.tools.Normalize#normalize(java.lang.String) + */ + public String normalize(String rawText) { + if (rawText == null || rawText.equals("null") || rawText.length() == 0) { + return ""; + } + String normText = rawText; + + // replace all null values + normText = normText.replaceAll("\u0000+", ""); + + // replace all Tabs and form feeds with spaces + normText = normText.replaceAll("[\t\f]", NORM_SP); + + // replace all non breaking spaces with normal spaces + normText = normText.replaceAll("\u00a0+", NORM_SP); + + // code all windows line breaks as \n + normText = normText.replaceAll("\r\n", "\n"); + + // code all mac line breaks as \n + normText = normText.replace('\r', '\n'); + + // reduce all multiple line breaks into two line breaks, code muliple line break as \r\r + normText = normText.replaceAll("\n[\\s\n]*\n", "\r\r"); + + // replace all single line breaks with one line break + normText = normText.replace('\n', '\r'); + + // normalize spaces + normText = normText.replaceAll(" +", NORM_SP); + + // remove spaces before and after a single line break + normText = normText.replaceAll(" ?\r ?", "\r"); + + // remove spaces before and after a multiple line breaks + normText = normText.replaceAll(" ?\r\r ?", "\r"); + + // remove leading and trailing space or line break in the string + int start_idx = (normText.charAt(0) == ' ' || normText.charAt(0) == '\r' ? 1 : 0); + int end_idx = (normText.charAt(normText.length() - 1) == ' ' || normText.charAt(normText.length() - 1) == '\r' ? normText.length() - 1 : normText.length()); + if (end_idx < start_idx) { + end_idx = start_idx; + } + + // System.err.println("Start idx:" + start_idx + " End idx:" + end_idx + " Text length:" + + // normText_.length()); + normText = normText.substring(start_idx, end_idx); + + // normalize line breaks + normText = normText.replaceAll("\r", NORM_CR); + + // normalize apostrophes + normText = normText.replaceAll("[\u0060\u00B4\u2018\u2019\u201A\u201B]", NORM_AP); + + // normalize quotations + normText = normText.replaceAll("[\u201C\u201D\u201E\u201F]", NORM_QU); + + // normalize hypens + normText = normText.replaceAll("[\u00AD\u2013\u2014]", NORM_HY); + + return normText; + } + + /** + * Return the version string. + * + * @see at.knowcenter.wag.egov.egiz.tools.Normalize#getVersion() + */ + public String getVersion() { + return VERSION; + } + + /** + * Returns the normalizer line separator string. + * @return the line separator string + */ + public String getNormCR() { + return NORM_CR; + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalizer.java b/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalizer.java new file mode 100644 index 0000000..ab17e4a --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalizer.java @@ -0,0 +1,270 @@ +/* + * + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * + * 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: Normalizer.java,v 1.5 2006/10/31 08:20:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.tools; + +import java.io.Serializable; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * This class provides wrapper methods to get an access to different normalizer implementations. + *
+ * This class is to load the corresponding implementation of a normalizer class. Therefor it seams + * to be a factory. The factory settings are read from the configuration file calling the + * SettingsReader. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.tools.Normalizer + * @see at.knowcenter.wag.egov.egiz.tools.NormalizeV01 + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + */ +public class Normalizer implements Serializable { + + /** + * SVUID. + */ + private static final long serialVersionUID = 4201772508393848555L; + + /** + * The current raw string to normalize + */ + private String rawString_ = null; + /** + * The current normalisation version string + */ + private String normVersion_ = null; + /** + * The normalized string cache + */ + private String normString_ = null; + /** + * The reference to the normalizer implementation + */ + private Normalize normalize_ = null; +// /** +// * A given Encoding, not used now +// */ +// private String encoding_ = null; + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + /** + * The factory class prefix + */ + private final static String CLASS_PREFIX = ".Normalize"; + /** + * The default version string + */ + protected final static String DEFAULT_VERSION = "V01"; + /** + * The settings key defined in the settings file + * + * @see SettingsReader + */ + protected final static String SETTINGS_VERSION_KEY = "normalizer.version"; + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(Normalizer.class); + + /** + * New Normalizer init by the raw string and a normalizer version. + * + * @param rawString the raw string to normalize + * @param normVersion the nomalizer version that should be used + * @throws NormalizeException ErrorCode:400 + */ + public Normalizer(String rawString, String normVersion) throws NormalizeException { + rawString_ = rawString; + normVersion_ = normVersion; + init(); + } + + /** + * New Normalizer init by the raw string. + * + * @param rawString the raw string to normalize + * @throws NormalizeException ErrorCode:400 + */ + public Normalizer(String rawString) throws NormalizeException { + rawString_ = rawString; + init(); + } + + /** + * The empty constructor. + * + * @throws NormalizeException ErrorCode:400 + */ + public Normalizer() throws NormalizeException { + init(); + } + + /** + * Load the factory implementation. This method trys to load the configured normalizer library. + * + * @throws NormalizeException + */ + public void init() throws NormalizeException { + loadSettings(); + String class_name = this.getClass().getPackage().getName() + getClassName(); + Class normalize_class = null; + try { + normalize_class = Class.forName(class_name); + } catch (ClassNotFoundException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Class not found:" + class_name); + } + NormalizeException ne = new NormalizeException(400, "Can not load normalizer library"); + ne.setErrorCode(400); + throw ne; + } + try { + normalize_ = (Normalize) normalize_class.newInstance(); + } catch (InstantiationException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Can not instantiate:" + class_name); + } + NormalizeException ne = new NormalizeException(400, "Can not load normalizer library"); + ne.setErrorCode(400); + throw ne; + } catch (IllegalAccessException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Can not access:" + class_name); + } + NormalizeException ne = new NormalizeException(400, "Can not load normalizer library"); + ne.setErrorCode(400); + throw ne; + } + } + + /** + * Read the class postfix from the configuration file + * + * @return the full qualified class name + */ + private String getClassName() { + if (normVersion_ == null) { + normVersion_ = settings_.getSetting(SETTINGS_VERSION_KEY, DEFAULT_VERSION); + } + return CLASS_PREFIX + normVersion_; + } + + /* + * public void setEncoding(String encoding) { encoding_ = encoding; } + */ + + /** + * Set the raw string to normalize + */ + public void setRawString(String rawString) { + rawString_ = rawString; + } + + /** + * Return the normalized string. If the chached value does not exist the normalize method from the + * current normalizer implementation is called. + * + * @return the normalized string + */ + public String getNormalizedString() { + if (normString_ == null) { + normalize(); + } + return normString_; + } + + /** + * Set a normalizer version. This activity load the new requested normalizer implementation. + * + * @param normVersion the normalizer version to be use + * @throws NormalizeException ErrorCode:400 + */ + public void setVersion(String normVersion) throws NormalizeException { + normVersion_ = normVersion; + init(); + } + + /** + * Return the current version string. + * + * @return the normaliser version string + */ + public String getVersion() { + return normVersion_; + } + + /** + * Wrapper method. Call the normalizer implementation method. + * + * @param rawString the raw string to normalize + * @return the normalized string + * @see NormalizeV01 + */ + public String normalize(String rawString) { + return normalize_.normalize(rawString); + } + + /** + * Wrapper method. Call the normalizer implementation method. Normalize the current raw string. + * + * @return the normalized string + * @see NormalizeV01 + */ + public String normalize() { + if (normString_ == null) { + normString_ = normalize(rawString_); + } + return normString_; + } + + /** + * Returns the normalizer line separator string. + * @return the line separator string + */ + public String getNormCR() { + return normalize_.getNormCR(); + } + + /** + * load the class settings + * + * @throws NormalizeException + * @see SettingsReader + */ + private void loadSettings() throws NormalizeException { + if (settings_ == null) { + try { + settings_ = SettingsReader.getInstance(); + } catch (SettingsException e) { + String log_message = "Can not load normalizer settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new NormalizeException(400, log_message, e); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousDataResponder.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousDataResponder.java new file mode 100644 index 0000000..847bbcf --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousDataResponder.java @@ -0,0 +1,155 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: AsynchronousDataResponder.java,v 1.3 2006/08/30 14:02:35 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +import java.io.IOException; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; + +/** + * Servlet that responds to the data post requests of the local service (e.g. + * BKU). + * + * @author wprinz + */ +public class AsynchronousDataResponder extends HttpServlet +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -4992297156381763174L; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(AsynchronousDataResponder.class); + + protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException + { + logger_.debug("AsyncDataResp GET REQUEST."); + super.doGet(arg0, arg1); + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + logger_.debug("AsyncDataResp !!!!!!!!!!!!!!!!!!!!!!"); + + HttpSession session = request.getSession(false); + if (session == null) + { + throw new ServletException("There is no session associated with this request."); + } + + // String session_id_string = request.getParameter("session"); + // if (session_id_string == null) + // { + // throw new ServletException("The session parameter is missing."); + // } + + SessionInformation si = (SessionInformation) session.getAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION); + // long session_id = Long.parseLong(session_id_string); + // SessionInformation si = SessionTable.get(session_id); + if (si == null) + { + throw new ServletException("The session is not found or no longer valid."); + } + + // InputStream is = request.getInputStream(); + // byte [] data = new byte[request.getContentLength()]; + // is.read(data); + // is.close(); + // String enc = request.getCharacterEncoding(); + // String ct = request.getContentType(); + // Enumeration enum = request.getHeaderNames(); + // + // String dat = new String(data, "US-ASCII"); + // // dat looks like: XMLResponse=blablabla ... + // // so the actual XMLResponse begins after the = + // String resp = URLDecoder.decode(dat, "UTF-8"); + + logger_.debug("Answer from local service: content-type = '" + request.getContentType() + "', character encoding = '" + request.getCharacterEncoding() + "'"); + + // .getParameter will use the character encoding specified by the + // content-type header. + // Unfortunately BKU forgets to specify a chatacter encoding. + // Therefor, .getParameter will assume US-ASCII or something. + // ==> we explicitely set UTF-8 + if (request.getCharacterEncoding() == null) + { + request.setCharacterEncoding("UTF-8"); + logger_.debug(" no character encoding specified - set to UTF-8"); + } + + logger_.debug("AsyncDataResponder: si.current_operation = " + si.current_operation); + + String resp_string = request.getParameter("XMLResponse"); + if (resp_string == null) + { + logger_.debug("response String is null => trying multipart form"); + + DiskFileItemFactory fif = new DiskFileItemFactory(); + fif.setRepository(SettingsReader.getTemporaryDirectory()); + ServletFileUpload sfu = new ServletFileUpload(fif); + + try + { + List items = sfu.parseRequest(request); + + for (int i = 0; i < items.size(); i++) + { + FileItem item = (FileItem) items.get(i); + logger_.debug("item = " + item.getFieldName()); + + if (item.getFieldName().equals("XMLResponse")) + { + resp_string = item.getString("UTF-8"); + } + } + } + catch (FileUploadException e) + { + throw new ServletException("File Upload exception. cannot parse POST data"); + } + + } + + si.response_string[si.current_operation] = resp_string; //request.getParameter("XMLResponse"); + //logger_.debug("AsyncDataResponder: si.response_string[si.current_operation] = " + si.response_string[si.current_operation]); + + si.current_operation++; + + si.finished = true; + + LocalRequestHelper.formatBKUOkResponse(response); + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousRedirectResponder.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousRedirectResponder.java new file mode 100644 index 0000000..fb5d2e3 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/AsynchronousRedirectResponder.java @@ -0,0 +1,196 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: AsynchronousRedirectResponder.java,v 1.4 2006/10/11 07:39:13 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +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.exceptions.ErrorCodeException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.Signator; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.BKUConnector; + +/** + * Servlet that responds to the redirect requests of the local service (e.g. + * BKU). + * + * @author wprinz + */ +public class AsynchronousRedirectResponder extends HttpServlet +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -682360466333727236L; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(AsynchronousRedirectResponder.class); + + protected void dispatch(HttpServletRequest request, + HttpServletResponse response, String resource) throws ServletException, IOException + { + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + + RequestDispatcher disp = getServletContext().getRequestDispatcher(resource); + disp.forward(request, response); + } + + protected void dispatchToResults(List results, HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException + { + request.setAttribute("results", results); + dispatch(request, response, "/jsp/results.jsp"); + } + + protected void dispatchToRedirectRefreshPage (HttpServletRequest request, + HttpServletResponse response, String refresh_url) throws ServletException, IOException + { + request.setAttribute("refresh_url", refresh_url); + dispatch(request, response, LocalRequestHelper.REDIRECT_REFRESH_PAGE_JSP); + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + logger_.debug("AsyncRedirResp"); + + SessionInformation si = null; + + HttpSession session = null; + try + { + session = request.getSession(false); + //String session_id_string = request.getParameter("session"); + if (session == null) + { + throw new ErrorCodeException(600, "The session is missing."); + } + + si = (SessionInformation) session.getAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION); +// long session_id = Long.parseLong(session_id_string); +// si = SessionTable.get(session_id); + if (si == null) + { + throw new ErrorCodeException(600, "The session is not found or is no longer valid."); + } + + } + catch (PresentableException e) + { + e.printStackTrace(); + Sign.prepareDispatchToErrorPage(e, request); + dispatch(request, response, "/jsp/error.jsp"); + + return; + } + + try + { + if (si.finished == false) + { + String url = request.getRequestURL().toString(); + logger_.debug("RequestURL = " + url); + String refresh_url = response.encodeURL(url); + logger_.debug("RefreshURL = " + refresh_url); + dispatchToRedirectRefreshPage(request, response, refresh_url); + return; + } + + si.finished = false; + + if (si.current_operation < si.requests.length) + { + LocalRequestHelper.prepareDispatchToLocalConnectionPage(si.requests[si.current_operation], request, response); + dispatch(request, response, LocalRequestHelper.LOCAL_CONNECTION_PAGE_JSP); + return; + } + + // all requests have been carried out. + //session.removeAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION); + //SessionTable.remove(si.session_id); + + BKUConnector local_conn = (BKUConnector) ConnectorFactory.createConnector(si.connector); + + if (si.application.equals("verify")) + { + List results = new ArrayList(); + + for (int i = 0; i < si.response_string.length; i++) + { + SignatureResponse sig_resp = local_conn.analyzeVerifyResponse(si.response_string[i]); + results.add(sig_resp); + } + + dispatchToResults(results, request, response); + } + else + { + //logger_.debug("AsyncRedirResponder: si.response_string[0] = " + si.response_string[0]); + logger_.debug("AsyncRedirResponder: si.current_op = " + si.current_operation); + + if (si.response_string[0] == null) + { + String url = request.getRequestURL().toString(); + logger_.debug("RequestURL = " + url); + String refresh_url = response.encodeURL(url); + logger_.debug("RefreshURL = " + refresh_url); + dispatchToRedirectRefreshPage(request, response, refresh_url); + return ; + } + + si.iui.signed_signature_object = local_conn.analyzeSignResponse(si.response_string[0], si.type); + + PdfASID algorithm = FormFields.translateSignatureModeToPdfASID(si.mode); + Signator signator = SignatorFactory.createSignator(algorithm); + + si.sign_result = signator.finishSign(si.iui); + + Sign.returnSignResponse(si, response); + } + + } + catch (PresentableException e) + { + session.removeAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION); + //SessionTable.remove(si.session_id); + + e.printStackTrace(); + Sign.prepareDispatchToErrorPage(e, request); + dispatch(request, response, "/jsp/error.jsp"); + } + + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/FormFields.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/FormFields.java new file mode 100644 index 0000000..6331a54 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/FormFields.java @@ -0,0 +1,210 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: FormFields.java,v 1.4 2006/10/11 07:39:13 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.servlet.ServletException; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * Helper class that provides methods and constants for creating and dealing + * with the various form fields. + * + * @author wprinz + */ +public abstract class FormFields +{ + public static final String PARAMETER_FREE_TEXT_ENTRY = "freetext"; + + public static final String FIELD_UPLOAD = "upload"; + + public static final String FIELD_CONNECTOR = "connector"; + + public static final String FIELD_MODE = "mode"; + + public static final String FIELD_PREVIEW = "preview"; + + public static final String FIELD_RAW_DOCUMENT_TEXT = "raw_document_text"; + + public static final String FIELD_SIGNATURE_TYPE = "sig_type"; + + public static final String FIELD_VERIFY_WHICH = "verify_which"; + + public static final String FIELD_DOWNLOAD = "download"; + + public static final String VALUE_TRUE = "true"; + + public static final String VALUE_FALSE = "false"; + + public static final String VALUE_MODE_BINARY = "binary"; + + public static final String VALUE_MODE_TEXTUAL = "textual"; + + public static final String VALUE_MODE_DETACHED = "detached"; + + public static final String VALUE_VERIFY_WHICH_ALL = "all"; + + public static final String VALUE_DOWNLOAD_INLINE = "inline"; + + public static final String VALUE_DOWNLOAD_ATTACHMENT = "attachment"; + + protected static final String STYLE_CLASS_FIELD = "field"; + + /** + * Translates the form field to a PDF-AS-ID. + * + * @param signature_mode + * The signator mode form field. + * @return Returns the corresponding PDFASID. + */ + protected static PdfASID translateSignatureModeToPdfASID(String signature_mode) + { + if (signature_mode.equals(VALUE_MODE_BINARY)) + { + return SignatorFactory.MOST_RECENT_BINARY_SIGNATOR_ID; + } + if (signature_mode.equals(VALUE_MODE_TEXTUAL)) + { + return SignatorFactory.MOST_RECENT_TEXTUAL_SIGNATOR_ID; + } + if (signature_mode.equals(VALUE_MODE_DETACHED)) + { + return SignatorFactory.MOST_RECENT_DETACHED_SIGNATOR_ID; + } + return null; + } + + /** + * Generates the HTML snippet of a FIELD_CONNECTOR select box that allows to + * choose a connector. + * + * @return Returns the HTML snippet. + * @throws SettingsException + * Forwarded exception. + * @throws ConnectorFactoryException + * Forwarded exception. + */ + public static String generateConnectorSelectBox() throws SettingsException, ConnectorFactoryException + { + StringWriter sw = new StringWriter(); + PrintWriter writer = new PrintWriter(sw); + + writer.println(""); + + return sw.toString(); + } + + /** + * Generates a HTML snippet of a FIELD_SIGNATURE_TYPE select box that allows + * to choose the signature type. + * + * @return Returns the HTML snippet. + * @throws ServletException + * Forwarded exception. + */ + public static String generateTypeSelectBox() throws ServletException + { + try + { + StringWriter sw = new StringWriter(); + PrintWriter writer = new PrintWriter(sw); + + SettingsReader settings = SettingsReader.getInstance(); + SignatureTypes sig_types = SignatureTypes.getInstance(); + + // SettingsReader settings = null; + // SignatureTypes sig_types = null; + // try + // { + // settings = SettingsReader.getInstance(); + // sig_types = SignatureTypes.getInstance(); + // } + // catch (IOException e) + // { + // String log_message = "Can not load signature settings. Cause:\n" + + // e.getMessage(); + // logger_.error(log_message); + // req.setAttribute("error", "Das System konnte nicht gestartet werden."); + // req.setAttribute("cause", "Die Konfiguration ist fehlerhaft oder konnte + // nicht geladen werden."); + // dispatch(req, res, "/jsp/error.jsp"); + // } + + ArrayList types_array = sig_types.getSignatureTypes(); + Iterator type_it = types_array.iterator(); + + String default_type = settings.getValueFromKey(SignatureTypes.DEFAULT_TYPE); + + writer.println(""); + + return sw.toString(); + } + catch (Exception e) + { + throw new ServletException(e); + } + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequest.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequest.java new file mode 100644 index 0000000..d3c24a7 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequest.java @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: LocalRequest.java,v 1.2 2006/08/25 17:06:11 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +import java.io.Serializable; + +/** + * Encapsulates a local request, basicall an URL where the local request is sent + * to and a request string. + * + * @author wprinz + */ +public class LocalRequest implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -3734904043231861998L; + + /** + * The URL the local request sould be directed at. + */ + protected String url_; + + /** + * The request string to be sent to that URL. + */ + protected String request_string_; + + /** + * Constructor that initializes the URL and request string. + * + * @param url + * The URL the local request sould be directed at. + * @param request_string + * The request string to be sent to that URL. + */ + public LocalRequest(String url, String request_string) + { + this.url_ = url; + this.request_string_ = request_string; + } + + /** + * Returns the URL. + * + * @return Returns the URL. + */ + public String getUrl() + { + return url_; + } + + /** + * Returns the request string. + * + * @return Returns the request string. + */ + public String getRequestString() + { + return request_string_; + } + +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequestHelper.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequestHelper.java new file mode 100644 index 0000000..50bea41 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/LocalRequestHelper.java @@ -0,0 +1,226 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: LocalRequestHelper.java,v 1.6 2006/10/31 08:22:04 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory; +import at.knowcenter.wag.egov.egiz.sig.LocalConnector; + +/** + * Contains commonly used helper functions for the local request procedure. + * + * @author wprinz + */ +public abstract class LocalRequestHelper +{ + /** + * The resource of the local connection page jsp. + */ + public static final String LOCAL_CONNECTION_PAGE_JSP = "/jsp/local_connection_page.jsp"; + + /** + * The resource of the redirect refresh page jsp. + */ + public static final String REDIRECT_REFRESH_PAGE_JSP = "/jsp/redirect_refresh_page.jsp"; + + /** + * Sets up the local sign procedure. + * + * @param response + * The HttpServletResponse the local request page is written to. + * @throws IOException + * Forwarded exception. + * @throws PresentableException + * Forwarded exception. + */ + public static void processLocalSign(SessionInformation si, + HttpServletRequest request, HttpServletResponse response) throws IOException, PresentableException + { + LocalConnector local_conn = (LocalConnector) ConnectorFactory.createConnector(si.connector); + + String document_text = si.iui.document_text; + String request_string = local_conn.prepareSignRequest(si.user_name, document_text, si.type); + String request_url = local_conn.getSignURL(si.type); + + LocalRequest local_request = new LocalRequest(request_url, request_string); + List local_requests = new ArrayList(); + local_requests.add(local_request); + + // ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // ObjectOutputStream oos = new ObjectOutputStream(baos); + // oos.writeObject(local_requests); + // oos.close(); + // baos.close(); + + si.requests = new LocalRequest[1]; + si.requests[0] = new LocalRequest(local_conn.getSignURL(si.type), request_string); + si.current_operation = 0; + si.response_string = new String[1]; + si.response_string[0] = null; + + // SessionTable.put(si); + request.getSession().setAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION, si); + + // byte [] requests_bytes = baos.toByteArray(); + // String base64 = CodingHelper.encodeBase64(requests_bytes); + + LocalRequestHelper.prepareDispatchToLocalConnectionPage(si.requests[0], request, response); + } + + /** + * Sets up the local verify procedure. + * + * @param response + * The HttpServletResponse the local request page is written to. + * @throws SignatureException + * Forwarded exception. + * @throws NormalizeException + * Forwarded exception. + * @throws IOException + * Forwarded exception. + * @throws ConnectorFactoryException + * Forwarded exception. + */ + public static void processLocalVerify(SessionInformation si, + List holders_to_verify, HttpServletRequest request, + HttpServletResponse response) throws SignatureException, NormalizeException, IOException, ConnectorFactoryException + { + si.requests = new LocalRequest[holders_to_verify.size()]; + si.response_string = new String[si.requests.length]; + si.current_operation = 0; + si.finished = false; + + request.getSession().setAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION, si); + // SessionTable.put(si); + + LocalConnector local_conn = (LocalConnector) ConnectorFactory.createConnector(si.connector); + + for (int i = 0; i < si.requests.length; i++) + { + SignatureHolder holder = (SignatureHolder) holders_to_verify.get(i); + + String text_to_be_verified = holder.getSignedText(); + // Normalizer normalizer = new Normalizer(); + // String normalized = normalizer.normalize(holder.signed_text); + + String request_string = local_conn.prepareVerifyRequest(text_to_be_verified, holder.getSignatureObject()); + + LocalRequest local_request = new LocalRequest(local_conn.getVerifyURL(holder.getSignatureObject().getSignationType()), request_string); + si.requests[i] = local_request; + si.response_string[i] = null; + } + + // ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // ObjectOutputStream oos = new ObjectOutputStream(baos); + // oos.writeObject(local_requests); + // oos.close(); + // baos.close(); + + // byte [] requests_bytes = baos.toByteArray(); + // String base64 = CodingHelper.encodeBase64(requests_bytes); + + prepareDispatchToLocalConnectionPage(si.requests[0], request, response); + } + + /** + * Formats the OK response from the web application back to the local BKU. + * + *

+ * As stated in the BKU tutorial, this response must be plain text "". + * Otherwise BKU will assume a failure. + *

+ * + * @param response + * The HttpServletResponse to answer to. + * @throws IOException + * Forwarded exception. + */ + protected static void formatBKUOkResponse(HttpServletResponse response) throws IOException + { + response.setContentType("text/plain"); + response.setCharacterEncoding("ISO-8859-1"); + + response.getWriter().println(""); + } + + /** + * Prepares the dispatch to the local data connection page. + * + *

+ * The calling servlet just has to dispatch to the jsp after calling this + * method. + *

+ * + * @param local_request + * The local request. Basically this contains the local service's + * target URL and the XML request string. + * @param response + * The HttpServletResponse to write this page to. + * @throws IOException + * Forwarded exception. + * @throws SignatureException + * Forwarded exception. + * @throws NormalizeException + * Forwarded exception. + */ + public static void prepareDispatchToLocalConnectionPage( + LocalRequest local_request, HttpServletRequest request, + HttpServletResponse response) throws IOException, SignatureException, NormalizeException + { + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + + String local_request_url = local_request.getUrl(); + + String quoted_request = makeStringHTMLReady(local_request.getRequestString()); + + String host = request.getServerName(); // "129.27.153.77" + URL data_URL = new URL(request.getScheme(), host, request.getServerPort(), request.getContextPath() + "/AsynchronousDataResponder"); + String data_url = response.encodeURL(data_URL.toString()); + URL redirect_URL = new URL(request.getScheme(), host, request.getServerPort(), request.getContextPath() + "/AsynchronousRedirectResponder"); + String redirect_url = response.encodeURL(redirect_URL.toString()); + + request.setAttribute("local_request_url", local_request_url); + request.setAttribute("quoted_request", quoted_request); + request.setAttribute("data_url", data_url); + request.setAttribute("redirect_url", redirect_url); + } + + public static String makeStringHTMLReady(String input) + { + String output = input; + + output = output.replaceAll("&", "&"); + output = output.replaceAll("\"", """); + output = output.replaceAll("<", "<"); + output = output.replaceAll(">", ">"); + return output; + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/PdfASServletContextListener.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/PdfASServletContextListener.java new file mode 100644 index 0000000..fab3e04 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/PdfASServletContextListener.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PdfASServletContextListener.java,v 1.3 2006/10/31 08:22:04 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +import java.io.File; +import java.io.IOException; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; + +/** + * The ServletContextListener is notified when the webapplication starts up and shuts down. + * + *

+ * Maintainance work is performed. + *

+ * + * @author wprinz + */ +public class PdfASServletContextListener implements ServletContextListener +{ + /** + * The logger. + */ + private static final Logger logger = ConfigLogger.getLogger(PdfASServletContextListener.class); + + /** + * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) + */ + public void contextInitialized(ServletContextEvent arg0) + { + logger.info("PDF-AS Context init"); + String base_dir = arg0.getServletContext().getRealPath("/"); + try + { + logger.info("PDF-AS base directory = " + new File(base_dir).getCanonicalPath()); + } + catch (IOException e) + { + e.printStackTrace(); + } + + SettingsReader.initializeForWeb(base_dir); + + SettingsReader.clearTemporaryDirectory(); + } + + /** + * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent) + */ + public void contextDestroyed(ServletContextEvent arg0) + { + SettingsReader.clearTemporaryDirectory(); + logger.info("PDF-AS Context exit"); + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionAttributes.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionAttributes.java new file mode 100644 index 0000000..02b6855 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionAttributes.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SessionAttributes.java,v 1.2 2006/08/25 17:06:11 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +/** + * Helper class that provides constants for the session attributes. + * + * @author wprinz + */ +public abstract class SessionAttributes +{ + + /** + * The user name. + */ + public static final String ATTRIBUTE_USER_NAME = "uname"; + + /** + * The user password. + */ + public static final String ATTRIBUTE_USER_PASSWORD = "upass"; + + /** + * The attribute name under which the SessionInformation object is stored. + * + *

+ * The SessionInformation class contains type safe references to the objects. + *

+ */ + public static final String ATTRIBUTE_SESSION_INFORMATION = "session_information"; +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionInformation.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionInformation.java new file mode 100644 index 0000000..f3c34d3 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionInformation.java @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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.knowcenter.wag.egov.egiz.web; + +import java.io.Serializable; +import java.util.List; + +import at.knowcenter.wag.egov.egiz.framework.SignResult; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; + +/** + * This class is a collection of various session parameters that are passed + * between the servlets and jsps. + * + *

+ * The SessionInformation class contains type safe references to the objects. + *

+ * + * @author wprinz + */ +public class SessionInformation implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7413884936584659150L; + + // public long session_id = -1; + + /** + * 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 byte[] pdf = 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; + + /** + * An array of local requests to be processed. + */ + public LocalRequest[] requests = null; + + /** + * The index of the local request to be processed next. + */ + public int current_operation = 0; + + /** + * An array of response strings of the local requests. + */ + public String[] response_string = null; + + /** + * Tells, if the current local request has been finished. + */ + public boolean finished = false; + + /** + * The incremental update information that has been extracted from the given + * PDF document. + */ + public IncrementalUpdateInformation iui; + + /** + * The signature holders. + */ + public List 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; +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionTable.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionTable.java new file mode 100644 index 0000000..4d0ba21 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/SessionTable.java @@ -0,0 +1,94 @@ +/** + * + */ +package at.knowcenter.wag.egov.egiz.web; + + +/** + * This class contains the session table that is used for local requests. + * + * @author wprinz + */ +public abstract class SessionTable +{ + // Session table no longer needed - because J2EE Servlet sessions are used. + +// /** +// * The HashMap for mapping the session id to the SessionInformation object on +// * the server. +// */ +// protected static Map session_table = new HashMap(); +// +// /** +// * The random number generator used to generate session_ids. +// */ +// protected static Random random = new Random(); +// +// /** +// * Generates a new SessionInformation object with a unique session_id. +// * +// *

+// * The object has to be added to the session table by using put(). +// *

+// * +// * @return Returns the generated SessionInformation object. +// * +// * @see #put(SessionInformation) +// */ +// public static SessionInformation generateSessionInformationObject() +// { +// SessionInformation si = new SessionInformation(); +// si.session_id = random.nextLong(); +// +// return si; +// } +// +// /** +// * Puts the SessionInformation object into the session table. +// * +// * @param si +// * The SessionInformation object. The session_id field must be filled +// * out properly. +// */ +// public static void put(SessionInformation si) +// { +// session_table.put(new Long(si.session_id), si); +// } +// +// /** +// * Gets the SessionInformation object associated with the given session_id. +// * +// * @param session_id +// * The session_id. +// * @return Returns the corresponding SessionInformation object or null, if no +// * object is associated with that id. +// */ +// public static SessionInformation get(final long session_id) +// { +// return (SessionInformation) session_table.get(new Long(session_id)); +// } +// +// /** +// * Removes the SessionInformation object with the provided session_id from the +// * session table. +// * +// * @param session_id +// * The session_id to be removed. +// */ +// public static void remove(long session_id) +// { +// session_table.remove(new Long(session_id)); +// } +// +// /** +// * Simply clear the session table. +// * +// *

+// * This should be used once in a while to tie up some loose ends. +// *

+// */ +// public static void clear() +// { +// session_table.clear(); +// } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/Sign.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/Sign.java new file mode 100644 index 0000000..a3ded84 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/Sign.java @@ -0,0 +1,525 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: Sign.java,v 1.7 2006/10/11 07:39:13 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.Iterator; +import java.util.List; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfAS; +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.ErrorCodeException; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PlaceholderException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.SignResult; +import at.knowcenter.wag.egov.egiz.framework.Signator; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +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.tools.CodingHelper; + +/** + * This method is the sign servlet for the pdf-as web application. It takes get + * and post requests fill out jsp templates and give the user feedback about the + * results of the sign process + * + * @author wlackner + * @author wprinz + */ +public class Sign extends HttpServlet +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -4156938216903740438L; + + /** + * Authorisation marker for the http header string. + */ + protected static final String AUTH = "authorization"; + + /** + * Authorisation marker for the http header string. + */ + protected static final String AUTH_BASIC = "Basic"; + + /** + * The logger. + */ + private static final Logger logger_ = ConfigLogger.getLogger(Sign.class); + + protected void dispatch(HttpServletRequest request, + HttpServletResponse response, String resource) throws ServletException, IOException + { + dispatch(request, response, resource, getServletContext()); + } + + 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); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + String authenticate = request.getHeader(AUTH); + if (authenticate != null) + { + logger_.info("authenticate:" + authenticate); + if (authenticate.indexOf(AUTH_BASIC) == 0) + { + authenticate = authenticate.substring(AUTH_BASIC.length() + 1); + logger_.info("authenticate:" + authenticate); + authenticate = new String(CodingHelper.decodeBase64(authenticate), "UTF-8"); + logger_.info("authenticate:" + authenticate); + + String[] auth_value = authenticate.split(":"); + String user_name = auth_value[0]; + String user_password = auth_value[1]; + logger_.info("username:" + user_name); + logger_.info("password:" + user_password); + + HttpSession session = request.getSession(); + session.setAttribute(SessionAttributes.ATTRIBUTE_USER_NAME, user_name); + session.setAttribute(SessionAttributes.ATTRIBUTE_USER_PASSWORD, user_password); + + dispatch(request, response, "/jsp/signupload.jsp"); + return; + } + } + + request.setAttribute("error", "Falsche Authentifikation"); + request.setAttribute("cause", "Passwort oder Benutzername ist falsch"); + dispatch(request, response, "/jsp/error.jsp"); + } + + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + DiskFileItemFactory fif = new DiskFileItemFactory(); + fif.setRepository(SettingsReader.getTemporaryDirectory()); + ServletFileUpload sfu = new ServletFileUpload(fif); + + try + { + List items = sfu.parseRequest(request); + + FileItem preview_fi = null; + FileItem sig_type_fi = null; + FileItem sig_app_fi = null; + FileItem mode_fi = null; + FileItem file_upload_fi = null; + FileItem download_fi = null; + + Iterator it = items.iterator(); + while (it.hasNext()) + { + FileItem item = (FileItem) it.next(); + logger_.debug("item = " + item.getFieldName()); + + if (item.isFormField()) + { + byte[] item_data = item.get(); + String item_string = new String(item_data, "UTF-8"); + logger_.debug(" form field string = " + item_string); + } + else + { + logger_.debug(" filename = " + item.getName()); + logger_.debug(" filesize = " + item.getSize()); + } + + if (item.getFieldName().equals(FormFields.FIELD_PREVIEW)) + { + preview_fi = item; + continue; + } + + if (item.getFieldName().equals(FormFields.FIELD_SIGNATURE_TYPE)) + { + sig_type_fi = item; + continue; + } + + if (item.getFieldName().equals(FormFields.FIELD_CONNECTOR)) + { + sig_app_fi = item; + continue; + } + + if (item.getFieldName().equals(FormFields.FIELD_MODE)) + { + mode_fi = item; + continue; + } + + if (item.getFieldName().equals(FormFields.FIELD_UPLOAD)) + { + file_upload_fi = item; + continue; + } + + if (item.getFieldName().equals(FormFields.FIELD_DOWNLOAD)) + { + download_fi = item; + continue; + } + + throw new ServletException("unrecognized POST data."); + + } + + if (preview_fi == null || sig_type_fi == null || sig_app_fi == null || file_upload_fi == null || download_fi == null) + { + throw new ServletException("Unsufficient data provided in request"); + } + + String mode = mode_fi.getString("UTF-8"); + if (!mode.equals(FormFields.VALUE_MODE_BINARY) && !mode.equals(FormFields.VALUE_MODE_TEXTUAL) && !mode.equals(FormFields.VALUE_MODE_DETACHED)) + { + throw new ServletException("The mode '" + mode + "' is unrecognized."); + } + + String preview_str = preview_fi.getString("UTF-8"); + boolean preview = false; + if (preview_str.equals("true")) + { + preview = true; + } + + boolean download_inline = true; + if (download_fi.getString("UTF-8").equals(FormFields.VALUE_DOWNLOAD_ATTACHMENT)) + { + download_inline = false; + } + + String sig_type = sig_type_fi.getString("UTF-8"); + String connector = sig_app_fi.getString("UTF-8"); + + String doc_file_name = file_upload_fi.getName(); + logger_.debug(" file content type =" + file_upload_fi.getContentType()); + + String extension = Verify.extractExtension(doc_file_name); + if (extension != null && !extension.equals("pdf")) + { + throw new PDFDocumentException(201, "The provided file '" + doc_file_name + "' doesn't have the PDF extension (.pdf)."); + } + + byte[] pdf = file_upload_fi.get(); + if (file_upload_fi.getSize() <= 0) + { + throw new PDFDocumentException(250, "The document is empty."); + } + PdfAS.applyStrictMode(pdf); + + String user_name = (String) request.getSession().getAttribute(SessionAttributes.ATTRIBUTE_USER_NAME); + String user_password = (String) request.getSession().getAttribute(SessionAttributes.ATTRIBUTE_USER_PASSWORD); + + SessionInformation si = new SessionInformation(); // SessionTable.generateSessionInformationObject(); + si.connector = connector; + si.application = "sign"; + si.mode = mode; + si.pdf = pdf; + si.type = sig_type; + si.user_name = user_name; + si.user_password = user_password; + si.filename = formatFileName(file_upload_fi.getName()); + si.download_inline = download_inline; + + prepareSign(si); + + if (preview) + { + request.getSession().setAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION, si); + + String submit_url = response.encodeURL(request.getContextPath() + "/SignPreview"); + + request.setAttribute("submit_url", submit_url); + + dispatch(request, response, "/jsp/signpreview.jsp"); + + return; + } + + finishSign(si, request, response, getServletContext()); + } + catch (FileUploadException e) + { + request.setAttribute("error", "Fehler beim Upload der Daten"); + request.setAttribute("cause", "Beim Upload der Daten ist ein Fehler aufgetreten."); + dispatch(request, response, "/jsp/error.jsp"); + } + catch (PresentableException e) + { + e.printStackTrace(); + prepareDispatchToErrorPage(e, request); + dispatch(request, response, "/jsp/error.jsp"); + } + } + + public static void prepareSign(SessionInformation si) throws PresentableException + { + PdfASID algorithm = FormFields.translateSignatureModeToPdfASID(si.mode); + Signator signator = SignatorFactory.createSignator(algorithm); + si.iui = signator.prepareSign(si.pdf, si.type, null, ConnectorFactory.needsSIG_ID(si.connector)); + } + + public static void finishSign(SessionInformation si, + HttpServletRequest request, HttpServletResponse response, ServletContext context) throws PresentableException, IOException, ServletException + { + if (ConnectorFactory.isConnectorLocal(si.connector)) + { + LocalRequestHelper.processLocalSign(si, request, response); + dispatch(request, response, LocalRequestHelper.LOCAL_CONNECTION_PAGE_JSP, context); + return; + } + + PdfASID algorithm = FormFields.translateSignatureModeToPdfASID(si.mode); + Signator signator = SignatorFactory.createSignator(algorithm); + + si.iui.signed_signature_object = PdfAS.sign(si.iui.document_text, si.type, si.connector, si.user_name, si.user_password); + + si.sign_result = signator.finishSign(si.iui); + + returnSignResponse(si, response); + } + + public static void prepareDispatchToErrorPage(PresentableException pe, + HttpServletRequest request) + { + if (pe instanceof ErrorCodeException) + { + ErrorCodeException ece = (ErrorCodeException) pe; + request.setAttribute("error", "Fehler " + ece.getErrorCode()); + + String cause = ece.getErrorCodeMessage(); + if (ece.hasExternalErrorMessage()) + { + cause = ece.getExternalErrorCode() + ": " + ece.getExternalErrorMessage(); + } + request.setAttribute("cause", cause); + + if (pe instanceof PlaceholderException) + { + PlaceholderException phe = (PlaceholderException) ece; + + request.setAttribute("cause", "Der Platzhalter des Feldes " + phe.getField() + " ist um " + phe.getMissing() + " Bytes zu kurz. " + ece.getErrorCodeMessage()); + } + } + else + { + request.setAttribute("error", "PresentableException"); + request.setAttribute("cause", pe.toString()); + } + } + + public void dispatchToPreview(String document_text, String connector, + String mode, String signature_type, String submit_url, + HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + request.setAttribute("document_text", document_text); + request.setAttribute("connector", connector); + request.setAttribute("mode", mode); + request.setAttribute("signature_type", signature_type); + request.setAttribute("submit_url", submit_url); + + dispatch(request, response, "/jsp/signpreview.jsp"); + } + + // public static void formatPreview(String document_text, String connector, + // String mode, String signature_type, String submit_url, + // HttpServletResponse response) throws ServletException, IOException + // { + // response.setContentType("text/html"); + // response.setCharacterEncoding("UTF-8"); + // + // PrintWriter writer = response.getWriter(); + // + // writer.println(""); + // writer.println(""); + // writer.println(""); + // writer.println(""); + // writer.println(""); + // writer.println("PDF-AS Amtssignaturen Vorschau"); + // writer.println(""); + // writer.println(""); + // + // writer.println(""); + // writer.println("
"); + // + // writer.println("

PDF-AS Amtssignaturen

"); + // + // writer.println("
"); + // writer.println("
Vorschau: Dokument Prüfen
"); + // writer.println("
"); + // writer.println("
"); + // + // writer.println(""); + // writer.println(""); + // writer.println(""); + // writer.println(""); + // writer.println(""); + // + // writer.println(""); + // writer.println("
"); + // + // writer.println(""); + // + // writer.println("
"); + // writer.println("
"); + // writer.println("
"); + // + // writer.println("zurück"); + // + // writer.println("
"); + // writer.println(""); + // + // writer.println(""); + // } + + /** + * This class is just used to put the pdf byte array into the session. + * + * @author wprinz + */ + protected class SignPreviewInfo implements Serializable + { + /** + * SVUID. + */ + private static final long serialVersionUID = 3102824040163616332L; + + public byte[] pdf = null; + + public String mode = null; + } + + /** + * Formats the file name so that it is suitable for content disposition. + * + * @param file_name + * The file name. + * @return Returns the formatted file name. + */ + public static String formatFileName(String file_name) + { + File file = new File(file_name); + String file_name_only = file.getName(); + // the file_name contains \\ ==> remove them so Internet Explorer works + // correctly. + return file_name_only; + } + + /** + * 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, + SignResult sign_result) + { + String output = file_name + "_signed"; + if (sign_result.getMimeType().equals(DetachedSignator_1_0_0.MIME_TYPE)) + { + output += ".xml"; + } + else + { + output += ".pdf"; + } + + return output; + } + + /** + * 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(SessionInformation si, + HttpServletResponse response) throws IOException + { + SignResult sign_result = si.sign_result; + + String file_name = formatFileNameForSignResult(si.filename, sign_result); + + // 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(sign_result.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 + "\""); + } + response.getOutputStream().write(sign_result.getData()); + + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/SignPreview.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/SignPreview.java new file mode 100644 index 0000000..1b32bdf --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/SignPreview.java @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: SignPreview.java,v 1.2 2006/10/11 07:39:13 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +import java.io.IOException; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import at.knowcenter.wag.egov.egiz.exceptions.ErrorCodeException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; + +/** + * @author wprinz + */ +public class SignPreview extends HttpServlet +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -8818532511322299998L; + + protected void dispatch(HttpServletRequest request, + HttpServletResponse response, String resource) throws ServletException, IOException + { + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + + RequestDispatcher disp = getServletContext().getRequestDispatcher(resource); + disp.forward(request, response); + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + SessionInformation si = null; + HttpSession session = null; + try + { + session = request.getSession(false); + // String session_id_string = request.getParameter("session"); + if (session == null) + { + throw new ErrorCodeException(600, "The session is missing."); + } + + si = (SessionInformation) session.getAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION); + // long session_id = Long.parseLong(session_id_string); + // si = SessionTable.get(session_id); + if (si == null) + { + throw new ErrorCodeException(600, "The session is not found or is no longer valid."); + } + + } + catch (PresentableException e) + { + e.printStackTrace(); + Sign.prepareDispatchToErrorPage(e, request); + dispatch(request, response, "/jsp/error.jsp"); + + return; + } + + try + { + String preview = request.getParameter(FormFields.FIELD_PREVIEW); + if (preview != null && preview.equals(FormFields.VALUE_TRUE)) + { + response.setContentType("application/pdf"); + response.getOutputStream().write(si.iui.signed_pdf); + return; + } + else + { + Sign.finishSign(si, request, response, getServletContext()); + } + } + catch (PresentableException e) + { + e.printStackTrace(); + Sign.prepareDispatchToErrorPage(e, request); + dispatch(request, response, "/jsp/error.jsp"); + } + } +} diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/Verify.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/Verify.java new file mode 100644 index 0000000..a8a5a5b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/Verify.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: Verify.java,v 1.7 2006/10/11 07:39:13 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfAS; +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.VerificationFilter; +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory; + +/** + * This method is the verify servlet for the pdf-as web application. It takes + * get and post requests fill out jsp templates and give the user feedback about + * the results of the verify process. + * + * @author wlackner + * @author wprinz + */ +public class Verify extends HttpServlet +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 309198792358636766L; + + /** + * The logger. + */ + private static final Logger logger_ = ConfigLogger.getLogger(Verify.class); + + protected void dispatch(HttpServletRequest request, + HttpServletResponse response, String resource) throws ServletException, IOException + { + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + + RequestDispatcher disp = getServletContext().getRequestDispatcher(resource); + disp.forward(request, response); + } + + protected void dispatchToResults(List results, HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException + { + request.setAttribute("results", results); + dispatch(request, response, "/jsp/results.jsp"); + } + + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + dispatch(request, response, "/jsp/verifyupload.jsp"); + } + + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + + DiskFileItemFactory fif = new DiskFileItemFactory(); + fif.setRepository(SettingsReader.getTemporaryDirectory()); + ServletFileUpload sfu = new ServletFileUpload(fif); + + try + { + + List items = sfu.parseRequest(request); + + FileItem upload_fi = null; + FileItem connector_fi = null; +// FileItem mode_fi = null; + FileItem preview_fi = null; + + { + Iterator it = items.iterator(); + while (it.hasNext()) + { + FileItem item = (FileItem) it.next(); + logger_.debug("item = " + item.getFieldName()); + + if (item.isFormField()) + { + byte[] item_data = item.get(); + String item_string = new String(item_data, "UTF-8"); + logger_.debug(" form field string = " + item_string); + } + else + { + logger_.debug(" filename = " + item.getName()); + logger_.debug(" filesize = " + item.getSize()); + } + + if (item.getFieldName().equals(FormFields.FIELD_UPLOAD)) + { + upload_fi = item; + continue; + } + + if (item.getFieldName().equals(FormFields.FIELD_CONNECTOR)) + { + connector_fi = item; + continue; + } + +// if (item.getFieldName().equals(FormFields.FIELD_MODE)) +// { +// mode_fi = item; +// continue; +// } + + if (item.getFieldName().equals(FormFields.FIELD_PREVIEW)) + { + preview_fi = item; + continue; + } + + throw new ServletException("unrecognized POST data."); + } + } + + if (upload_fi == null || connector_fi == null || /*mode_fi == null ||*/ preview_fi == null) + { + throw new ServletException("Unsufficient data provided in request."); + } + + String connector = connector_fi.getString("UTF-8"); + +// String mode = mode_fi.getString("UTF-8"); +// if (!mode.equals(FormFields.VALUE_MODE_BINARY) && !mode.equals(FormFields.VALUE_MODE_TEXTUAL)) +// { +// throw new ServletException("The mode '" + mode + "' is unrecognized."); +// } + + String preview_str = preview_fi.getString("UTF-8"); + if (!preview_str.equals(FormFields.VALUE_TRUE) && !preview_str.equals(FormFields.VALUE_FALSE)) + { + throw new ServletException("The preview '" + preview_str + "' is unrecognized."); + } + boolean preview = false; + if (preview_str.equals(FormFields.VALUE_TRUE)) + { + preview = true; + } + + // process the request + logger_.debug("file content type =" + upload_fi.getContentType()); + logger_.debug("file size = " + upload_fi.getSize()); + if (upload_fi.getSize() <= 0) + { + throw new PDFDocumentException(250, "The document is empty."); + } + byte[] document_bytes = upload_fi.get(); + + VerificationFilter vf = new VerificationFilter(); + List signature_holders = null; + + String doc_file_name = upload_fi.getName(); + String extension = extractExtension(doc_file_name); + + String raw_text = null; + if (doc_file_name == null || (extension != null && extension.equals("txt"))) + { + raw_text = new String(document_bytes, "UTF-8"); + signature_holders = vf.extractSignaturesFromPlainText(raw_text); + } + else + { + signature_holders = vf.extractSignaturesFromPdf(document_bytes); + } + + if (signature_holders.size() == 0) + { + throw new PDFDocumentException(206, "PDF document not signed."); + } + + if (preview) + { + SessionInformation si = new SessionInformation(); + si.application = "verify"; + si.connector = connector; + si.signature_holders = signature_holders; + request.getSession().setAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION, si); + + dispatch(request, response, "/jsp/verifylist.jsp"); + //VerifyPreview.formatPreview(signature_holders, connector, request, response); + } + else + { + if (ConnectorFactory.isConnectorLocal(connector)) + { + SessionInformation si = new SessionInformation(); //SessionTable.generateSessionInformationObject(); + si.connector = connector; + si.application = "verify"; + si.mode = null; + si.pdf = null; + si.type = null; + si.user_name = null; + si.user_password = null; + + si.signature_holders = signature_holders; + + LocalRequestHelper.processLocalVerify(si, si.signature_holders, request, response); + dispatch(request, response, LocalRequestHelper.LOCAL_CONNECTION_PAGE_JSP); + return; + } + + List results = PdfAS.verifySignatureHolders(signature_holders, connector); + dispatchToResults(results, request, response); + } + + } + catch (FileUploadException e) + { + request.setAttribute("error", "Fehler beim Upload der Daten"); + request.setAttribute("cause", "Beim Upload der Daten ist ein Fehler aufgetreten."); + dispatch(request, response, "/jsp/error.jsp"); + } + catch (PresentableException e) + { + e.printStackTrace(); + Sign.prepareDispatchToErrorPage(e, request); + dispatch(request, response, "/jsp/error.jsp"); + } + + } + + /** + * Extracts the extension from a file name string. + * + *

+ * The extension of a file name is whatever text follows the last '.'. + *

+ * + * @param file_name + * The file name. + * @return Returns the extension. If the file name ends with the '.', then an + * empty string is returned. If the file name doesn't contain any '.' + * or file_name is null, null is returned. + */ + public static String extractExtension(String file_name) + { + if (file_name == null) + { + return null; + } + + int dot_index = file_name.lastIndexOf('.'); + if (dot_index < 0) + { + return null; + } + return file_name.substring(dot_index + 1); + } +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/web/VerifyPreview.java b/src/main/java/at/knowcenter/wag/egov/egiz/web/VerifyPreview.java new file mode 100644 index 0000000..c39fd91 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/web/VerifyPreview.java @@ -0,0 +1,704 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: VerifyPreview.java,v 1.4 2006/10/11 07:39:13 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.web; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfAS; +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.ErrorCodeException; +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder; +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory; +import at.knowcenter.wag.egov.egiz.sig.SignatureEntry; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * @author wprinz + */ +public class VerifyPreview extends HttpServlet +{ + /** + * SVUID. + */ + private static final long serialVersionUID = 6954343542890239109L; + + /** + * The logger. + */ + private static final Logger logger_ = ConfigLogger.getLogger(VerifyPreview.class); + + protected void dispatch(HttpServletRequest request, + HttpServletResponse response, String resource) throws ServletException, IOException + { + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + + RequestDispatcher disp = getServletContext().getRequestDispatcher(resource); + disp.forward(request, response); + } + + protected static String generateNamePrefix(int num) + { + return SIG_INPUT_PREFIX + num + "_"; + } + + // public static void formatPreview(List signature_holders, String connector, + // HttpServletRequest request, HttpServletResponse response) throws + // ServletException, IOException + // { + // response.setContentType("text/html"); + // response.setCharacterEncoding("UTF-8"); + // + // PrintWriter writer = response.getWriter(); + // + // writer.println(""); + // writer.println(""); + // writer.println(""); + // writer.println(""); + // writer.println("PDF-AS Amtssignaturen Vorschau"); + // writer.println(""); + // + // writer.println(""); + // + // writer.println(""); + // + // writer.println(""); + // writer.println("
"); + // + // writer.println("

PDF-AS Amtssignaturen

"); + // + // writer.println("
"); + // writer.println("
Vorschau: Dokument Prüfen
"); + // writer.println("
"); + // writer.println("
"); + // + // // writer.println(""); + // writer.println(""); + // + // // if (mode.equals(FormFields.VALUE_MODE_TEXTUAL)) + // // { + // // String raw_document_text = ((SignatureHolder) + // // signature_holders.get(0)).signed_text; + // // writer.println(""); + // // writer.println("
"); + // // } + // + // if (signature_holders.size() == 1) + // { + // writer.println("
Rekonstruktion der Signaturmarke:
"); + // } + // else + // { + // writer.println("
Rekonstruktion der Signaturmarken:
"); + // } + // + // // this special
is only needed because internet explorer doesn't + // // format the width of the + // // tables right when the div is not given. + // // probably this is because the table then tries to calculate the relative + // // width from the surrounding form object. + // writer.println("
"); + // int num = 0; + // Iterator it = signature_holders.iterator(); + // while (it.hasNext()) + // { + // SignatureHolder signature_holder = (SignatureHolder) it.next(); + // + // String name_prefix = generateNamePrefix(num); + // + // String input_key = name_prefix + FormFields.FIELD_RAW_DOCUMENT_TEXT; + // if (signature_holder.signature_object.isBinary()) + // { + // writer.println(""); + // } + // else + // { + // writer.println("
"); + // writer.println(""); + // writer.println("
"); + // } + // + // String html = renderRequiredKeys(signature_holder.signature_object, + // name_prefix, false); + // writer.println(html); + // + // writer.println(""); + // + // num++; + // } + // writer.println("
"); + // + // writer.println("");// + + // // FormFields.VALUE_VERIFY_WHICH_ALL + // // + + // // "\" + // // />"); + // writer.println(""); + // + // writer.println("
"); + // writer.println(""); + // writer.println("
"); + // + // writer.println("zurück"); + // + // writer.println("
"); + // writer.println(""); + // + // writer.println(""); + // + // } + + public static String renderRequiredKeysJavaScript( + SignatureObject signature_object, String name_prefix) + { + StringWriter sw = new StringWriter(); + PrintWriter writer = new PrintWriter(sw); + + String[] rkeys = SignatureTypes.REQUIRED_SIG_KEYS; + + for (int key_idx = 0; key_idx < rkeys.length; key_idx++) + { + String key = rkeys[key_idx]; + SignatureEntry entry = signature_object.getSigEntry(key); + String value = entry.getValue(); + if (SignatureTypes.SIG_ID.equals(key) && value == null) + { + continue; + } + + value = value.replaceAll("\\s", " "); + value = value.replaceAll("\\\"", "\\\""); + + String input_key = name_prefix + key; + + writer.println(" document.submitform." + input_key + ".value = \"" + value + "\";"); + } + + return sw.toString(); + } + + public static String renderRequiredKeys(SignatureObject signature_object, + String name_prefix, boolean write_value) + { + StringWriter sw = new StringWriter(); + PrintWriter writer = new PrintWriter(sw); + + writer.println(""); + + String[] rkeys = SignatureTypes.REQUIRED_SIG_KEYS; + + for (int key_idx = 0; key_idx < rkeys.length; key_idx++) + { + String key = rkeys[key_idx]; + SignatureEntry entry = signature_object.getSigEntry(key); + String caption = entry.getCaption(); + String value = entry.getValue(); + if (SignatureTypes.SIG_ID.equals(key) && value == null) + { + continue; + } + + writer.println(" "); + writer.println(" "); + writer.println(" "); + writer.println(" "); + } + writer.println("
" + caption + ":"); + + value = value.replaceAll("\\s", " "); + value = value.replaceAll("\\\"", "\\\""); + + String input_key = name_prefix + key; + writer.println(" "); + + writer.println("
"); + + return sw.toString(); + } + + public static String renderRequiredKeysText(SignatureObject signature_object) + { + StringWriter sw = new StringWriter(); + PrintWriter writer = new PrintWriter(sw); + + String title = "alte PDF-AS Signatur"; + try + { + PdfASID kz = signature_object.getKZ(); + if (kz != null) + { + title = kz.toString(); + } + } + catch (InvalidIDException e) + { + e.printStackTrace(); + } + writer.println("
Signatur: " + title + "
"); + writer.println(""); + + // just render useful information + String[] rkeys = { SignatureTypes.SIG_DATE, SignatureTypes.SIG_ISSUER, + SignatureTypes.SIG_NUMBER }; // SignatureTypes.REQUIRED_SIG_KEYS; + + for (int key_idx = 0; key_idx < rkeys.length; key_idx++) + { + String key = rkeys[key_idx]; + SignatureEntry entry = signature_object.getSigEntry(key); + String caption = entry.getCaption(); + String value = entry.getValue(); + if (SignatureTypes.SIG_ID.equals(key) && value == null) + { + continue; + } + + writer.println(" "); + writer.println(" "); + writer.println(" "); + writer.println(" "); + } + writer.println("
" + caption + ":"); + + value = value.replaceAll("\\s", " "); + value = value.replaceAll("\\\"", "\\\""); + + writer.println(" " + value); + + writer.println("
"); + + return sw.toString(); + } + + protected void dispatchToResults(List results, HttpServletRequest request, + HttpServletResponse response, boolean backbutton) throws ServletException, IOException + { + request.setAttribute("results", results); + request.setAttribute("backbutton", backbutton ? "true" : "false"); + dispatch(request, response, "/jsp/results.jsp"); + } + + // public static void formatVerifyResults(List results, + // HttpServletResponse response) throws IOException, SettingNotFoundException + // { + // response.setContentType("text/html"); + // response.setCharacterEncoding("UTF-8"); + // + // PrintWriter writer = response.getWriter(); + // + // writer.println(""); + // writer.println(""); + // writer.println(""); + // writer.println(""); + // writer.println("PDF-AS Amtssignaturen Resultat"); + // writer.println(""); + // writer.println(""); + // + // writer.println(""); + // writer.println("
"); + // + // writer.println("

PDF-AS Amtssignaturen

"); + // + // writer.println("
"); + // writer.println("
Resultat
"); + // writer.println("
"); + // + // Iterator it = results.iterator(); + // while (it.hasNext()) + // { + // SignatureResponse result = (SignatureResponse) it.next(); + // formatSignatureResponse(result, writer); + // + // if (it.hasNext()) + // { + // writer.println("
"); + // } + // } + // + // writer.println("
"); + // writer.println("
"); + // + // writer.println("zurück"); + // + // writer.println("
"); + // writer.println(""); + // + // writer.println(""); + // + // } + // + // public static void formatSignatureResponse(SignatureResponse result, + // PrintWriter writer) throws SettingNotFoundException + // { + // writer.println("
Zertifikat"); + // writer.println(""); + // writer.println(" "); + // writer.println(" "); + // writer.println(" "); + // List public_properties = result.getPublicProperties(); + // Iterator it = public_properties.iterator(); + // while (it.hasNext()) + // { + // String public_property = (String) it.next(); + // writer.println(" "); + // } + // + // writer.println(" "); + // + // writer.println("
Signator:" + + // result.getX509SubjectName() + "
Aussteller:" + + // result.getX509IssuerName() + "
Seriennummer:" + + // result.getX509SerialNumber() + "
Eigenschaft:" + + // public_property + "
Zertifikat:" + result.getCertificateCheckInfo() + // + "
"); + // writer.println("
"); + // writer.println("
Signatur-Check"); + // writer.println("
" + result.getSignatureCheckInfo() + "
"); + // writer.println("
"); + // writer.println("
Manifest-Check"); + // writer.println("
" + + // result.getSignatureManifestCheckInfo() + "
"); + // writer.println("
"); + // } + + /** + * Form field name prefix for signature table names + */ + public static final String SIG_INPUT_PREFIX = "sig_inp_"; + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + SessionInformation si = null; + HttpSession session = null; + try + { + session = request.getSession(false); + // String session_id_string = request.getParameter("session"); + if (session == null) + { + throw new ErrorCodeException(600, "The session is missing."); + } + + si = (SessionInformation) session.getAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION); + // long session_id = Long.parseLong(session_id_string); + // si = SessionTable.get(session_id); + if (si == null) + { + throw new ErrorCodeException(600, "The session is not found or is no longer valid."); + } + + } + catch (PresentableException e) + { + e.printStackTrace(); + Sign.prepareDispatchToErrorPage(e, request); + dispatch(request, response, "/jsp/error.jsp"); + + return; + } + + try + { + + int verify_which = -1; + boolean preview = false; + + { + String str_verify_which = request.getParameter(FormFields.FIELD_VERIFY_WHICH); + logger_.debug("verify_which = " + str_verify_which); + if (str_verify_which.equals(FormFields.VALUE_VERIFY_WHICH_ALL)) + { + verify_which = -1; + } + else + { + verify_which = Integer.parseInt(str_verify_which); + } + logger_.debug("verify_which = " + verify_which); + } + + { + String preview_string = request.getParameter(FormFields.FIELD_PREVIEW); + if (preview_string.equals("true")) + { + preview = true; + } + } + + List holders_to_verify = si.signature_holders; + + if (verify_which >= 0) + { + if (verify_which >= si.signature_holders.size()) + { + throw new SignatureException(312, "The selected signature to be verified doesn't exist."); + } + + SignatureHolder holder = (SignatureHolder) si.signature_holders.get(verify_which); + holders_to_verify = new ArrayList(); + holders_to_verify.add(holder); + + if (preview == true) + { + if (holder instanceof BinarySignatureHolder) + { + BinarySignatureHolder binary_holder = (BinarySignatureHolder) holder; + response.setContentType("application/pdf"); + response.getOutputStream().write(binary_holder.getSignedPdf(), 0, binary_holder.getSignedPdfLength()); + } + else + // if (holder.getSignatureObject().isTextual()) + { + // formatPreview(holders_to_verify, si.connector, request, + // response); + request.setAttribute(FormFields.FIELD_VERIFY_WHICH, new Integer(verify_which)); + dispatch(request, response, "/jsp/verifypreview.jsp"); + } + + return; + } + + } + + if (ConnectorFactory.isConnectorLocal(si.connector)) + { + LocalRequestHelper.processLocalVerify(si, holders_to_verify, request, response); + dispatch(request, response, LocalRequestHelper.LOCAL_CONNECTION_PAGE_JSP); + return; + } + + List results = PdfAS.verifySignatureHolders(holders_to_verify, si.connector); + boolean backbutton = true; + if (verify_which >= 0) + { + backbutton = false; + } + dispatchToResults(results, request, response, backbutton); + + } + catch (PresentableException e) + { + e.printStackTrace(); + Sign.prepareDispatchToErrorPage(e, request); + dispatch(request, response, "/jsp/error.jsp"); + } + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + SessionInformation si = null; + HttpSession session = null; + try + { + session = request.getSession(false); + // String session_id_string = request.getParameter("session"); + if (session == null) + { + throw new ErrorCodeException(600, "The session is missing."); + } + + si = (SessionInformation) session.getAttribute(SessionAttributes.ATTRIBUTE_SESSION_INFORMATION); + // long session_id = Long.parseLong(session_id_string); + // si = SessionTable.get(session_id); + if (si == null) + { + throw new ErrorCodeException(600, "The session is not found or is no longer valid."); + } + + } + catch (PresentableException e) + { + e.printStackTrace(); + Sign.prepareDispatchToErrorPage(e, request); + dispatch(request, response, "/jsp/error.jsp"); + + return; + } + + DiskFileItemFactory fif = new DiskFileItemFactory(); + fif.setRepository(SettingsReader.getTemporaryDirectory()); + ServletFileUpload sfu = new ServletFileUpload(fif); + + try + { + String text_to_be_verified = null; + SignatureObject signature_object = new SignatureObject(); + + String default_type = SettingsReader.getInstance().getValueFromKey(SignatureTypes.DEFAULT_TYPE); + signature_object.setSigType(default_type); + signature_object.initByType(); + + int verify_which = -1; + boolean verify = false; + + List items = sfu.parseRequest(request); + + Iterator it = items.iterator(); + while (it.hasNext()) + { + FileItem item = (FileItem) it.next(); + logger_.debug("item = " + item.getFieldName()); + + if (item.getFieldName().equals(FormFields.FIELD_RAW_DOCUMENT_TEXT)) + { + String raw_document_text = item.getString("UTF-8"); + text_to_be_verified = PdfAS.normalizeText(raw_document_text); + continue; + } + + if (item.getFieldName().equals(FormFields.FIELD_VERIFY_WHICH)) + { + String which_str = item.getString("UTF-8"); + verify_which = Integer.parseInt(which_str); + continue; + } + + if (item.getFieldName().equals("verify")) + { + if (item.getString("UTF-8").equals("true")) + { + verify = true; + } + continue; + } + + String key = item.getFieldName(); + String value = item.getString("UTF-8"); + + signature_object.setSigValue(key, value); + logger_.debug("sig_obj_number" + key + " = " + value); + } + + SignatureHolder new_holder = new TextualSignatureHolder(text_to_be_verified, signature_object); + si.signature_holders.set(verify_which, new_holder); + + if (verify == false) + { + dispatch(request, response, "/dataok.html"); + return; + } + + List holders_to_verify = si.signature_holders; + + if (verify_which >= 0) + { + if (verify_which >= si.signature_holders.size()) + { + throw new SignatureException(312, "The selected signature to be verified doesn't exist."); + } + + SignatureHolder holder = (SignatureHolder) si.signature_holders.get(verify_which); + holders_to_verify = new ArrayList(); + holders_to_verify.add(holder); + } + + if (ConnectorFactory.isConnectorLocal(si.connector)) + { + LocalRequestHelper.processLocalVerify(si, holders_to_verify, request, response); + dispatch(request, response, LocalRequestHelper.LOCAL_CONNECTION_PAGE_JSP); + return; + } + + List results = PdfAS.verifySignatureHolders(holders_to_verify, si.connector); + dispatchToResults(results, request, response, true); + } + catch (FileUploadException e) + { + request.setAttribute("error", "Fehler beim Upload der Daten"); + request.setAttribute("cause", "Beim Upload der Daten ist ein Fehler aufgetreten."); + dispatch(request, response, "/jsp/error.jsp"); + } + catch (PresentableException e) + { + e.printStackTrace(); + Sign.prepareDispatchToErrorPage(e, request); + dispatch(request, response, "/jsp/error.jsp"); + } + + } +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/ByteArrayUtils.java b/src/main/java/at/knowcenter/wag/exactparser/ByteArrayUtils.java new file mode 100644 index 0000000..e6b32ec --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/ByteArrayUtils.java @@ -0,0 +1,140 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ByteArrayUtils.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser; + +import java.io.UnsupportedEncodingException; + +/** + * Abstract class that contains utility methods for handling byte arrays. + * + * @author wprinz + */ +public abstract class ByteArrayUtils { + + public static final String BYTE_ARRAY_ENCODING = "ISO-8859-1"; + + /** + * Converts the byte array to a String. + * + * @param data + * The byte array. + * @return Returns the String. + * @throws UnsupportedEncodingException + * Forwarded exception + */ + public static String convertByteArrayToString(final byte[] data) throws UnsupportedEncodingException { + return new String(data, BYTE_ARRAY_ENCODING); + } + + /** + * Finds the first occurance of search in data starting to search from the + * given index. + * + * @param data + * The big array. + * @param index + * The index to start searching from. + * @param search + * The sought array. + * @return Returns the index of the found occurence or -1 if nothing was + * found. + */ + public static int indexOf(final byte[] data, final int index, final byte[] search) { + for (int i = index; i <= data.length - search.length; i++) { + if (compareByteArrays(data, i, search)) { + return i; + } + } + return -1; + } + + /** + * Finds the last occurance of the array. + * + * @param data + * The source array to be searched. + * @param search + * The sought array. + * @return Returns the index of the last occurance - or -1 if nothing was + * found. + */ + public static int lastIndexOf(final byte[] data, byte[] search) { + for (int index = data.length - search.length; index >= 0; index--) { + if (compareByteArrays(data, index, search)) { + return index; + } + } + return -1; + } + + /** + * Compares the two byte arrays for equality. + * + * @param data + * The source array. + * @param index + * In index into the source array marking where the comparison should + * start. + * @param search + * The sought array. + * @return Returns true if the first search.length bytes of data+index and + * search match exactly. Returns false otherwise. + */ + public static boolean compareByteArrays(final byte[] data, final int index, byte[] search) { + if (index < 0 || index >= data.length) { + throw new IndexOutOfBoundsException("The index " + index + " is out of bounds"); + } + + if (search.length > data.length) { + return false; + } + + if (search.length > data.length - index) { + return false; + } + + for (int i = 0; i < search.length; i++) { + if (data[index + i] != search[i]) { + return false; + } + } + + return true; + } + + /** + * Checks, if the sought data byte is contained within the byte array. + * + * @param byte_array + * The byte array. + * @param data + * A data byte sought within the byte array. + * @return Returns true, if the data byte was found (at least once) in the + * byte array, false otherwise. + */ + public static boolean contains(final byte[] byte_array, final byte data) { + for (int i = 0; i < byte_array.length; i++) { + byte b = byte_array[i]; + if (b == data) { + return true; + } + } + return false; + } + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/ParseDocument.java b/src/main/java/at/knowcenter/wag/exactparser/ParseDocument.java new file mode 100644 index 0000000..a1ad10d --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/ParseDocument.java @@ -0,0 +1,265 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ParseDocument.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import at.knowcenter.wag.exactparser.parsing.PDFUtils; +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.NameParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NumberParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ObjectParseResult; +import at.knowcenter.wag.exactparser.parsing.results.StartXRefParseResult; +import at.knowcenter.wag.exactparser.parsing.results.TrailerParseResult; +import at.knowcenter.wag.exactparser.parsing.results.XRefSectionParseResult; + + +/** + * Test class. + * @author wprinz + */ +public class ParseDocument +{ + + public static final String DOCUMENT = "C:/wprinz/temp.pdf"; + + public static final byte[] EGIZ_DICT_NAME = { 'E', 'G', 'I', 'Z', 'S', 'i', + 'g', 'D', 'i', 'c', 't' }; + + public static final byte[] EGIZ_ODS_NAME = { 'O', 'D', 'S' }; + + public static final byte[] EGIZ_XOBJ_NAME = { 'S', 'i', 'g', 'X', 'O', 'b', + 'j', 'e', 'c', 't' }; + + /** + * @param args + */ + public static void main(String[] args) + { + + try + { + File in = new File(DOCUMENT); + FileInputStream fis = new FileInputStream(in); + byte[] pdf = new byte[(int) in.length()]; + fis.read(pdf); + fis.close(); + fis = null; + + List blocks = parseDocument(pdf); + + Iterator it = blocks.iterator(); + while (it.hasNext()) + { + FooterParseResult bpr = (FooterParseResult) it.next(); + + System.out.print("block from " + bpr.start_index + " to " + bpr.next_index); + + if (bpr.tpr.root != null) + { + int root_index = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(bpr.xpr, bpr.tpr.root.ior); + ObjectParseResult root_opr = PDFUtils.parseObject(pdf, root_index); + DictionaryParseResult root_dpr = (DictionaryParseResult) root_opr.object; + + int egiz_index = PDFUtils.indexOfName(pdf, root_dpr.names, EGIZ_DICT_NAME); + if (egiz_index >= 0) + { + System.out.print(" == EGIZDict"); + } + } + + System.out.println(); + } + + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + public static List parseDocument(final byte[] pdf) throws IOException + { + //HeaderParseResult hpr = PDFUtils.parseHeader(pdf, 0); + //System.out.println("PDF-version = " + hpr.major + "." + hpr.minor); + + + List blocks = new ArrayList(); + + int last_start_xref = PDFUtils.findLastStartXRef(pdf); + StartXRefParseResult last_sxpr = PDFUtils.parseStartXRef(pdf, last_start_xref); + int xref_index = last_sxpr.xref_index; + + for (;;) + { + FooterParseResult fpr = PDFUtils.parseFooter(pdf, xref_index); + blocks.add(0, fpr); + + //System.out.println("tpr.has_predecessor = " + fpr.tpr.has_predecessor); + if (!fpr.tpr.has_predecessor) + { + // eventually parse the PDF header here. + break; + } + + //System.out.println("tpr.prev = " + fpr.tpr.getPrev()); + + xref_index = fpr.tpr.getPrev(); + } + + return blocks; + } + + // public static void parseEGIZ() + // { + // + // int root_index = + // PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(bpr.xpr, + // bpr.tpr.root.ior); + // ObjectParseResult root_opr = PDFUtils.parseObject(pdf, root_index); + // DictionaryParseResult root_dpr = (DictionaryParseResult) root_opr.object; + // + // int egiz_index = PDFUtils.indexOfName(pdf, root_dpr.names, EGIZ_DICT_NAME); + // if (egiz_index >= 0) + // { + // IndirectObjectReferenceParseResult egiz_iorpr = + // (IndirectObjectReferenceParseResult) root_dpr.values.get(egiz_index); + // System.out.println("EGIZ signature info at = " + egiz_iorpr); + // + // int egiz_dict_index = + // PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(bpr.xpr, + // egiz_iorpr.ior); + // ObjectParseResult opr = PDFUtils.parseObject(pdf, egiz_dict_index); + // DictionaryParseResult egiz_dict = (DictionaryParseResult) opr.object; + // + // for (int i = 0; i < egiz_dict.names.size(); i++) + // { + // NameParseResult npr = egiz_dict.names.get(i); + // int len = npr.next_index - npr.name_start_index; + // byte[] name = new byte[len]; + // System.arraycopy(pdf, npr.name_start_index, name, 0, len); + // System.out.print(" " + new String(name, "US-ASCII") + " = "); + // + // System.out.println(egiz_dict.values.get(i)); + // } + // + // // int key = PDFUtils.indexOfName(pdf, egiz_dict.names, new byte [] { 'K', + // // 'e', 'y'}); + // // IndirectObjectReferenceParseResult key_iorpr = + // // (IndirectObjectReferenceParseResult) egiz_dict.values.get(key); + // // int key_offset = + // // PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(xpr, + // // key_iorpr.ior); + // // ObjectParseResult key_opr = PDFUtils.parseObject(pdf, key_offset); + // // StreamParseResult spr = (StreamParseResult) key_opr.object; + // // System.out.println(" key stream from " + spr.content_start_index + " to + // // " + spr.content_end_index); + // // + // // int data_len = spr.content_end_index - spr.content_start_index; + // // byte [] data = new byte[data_len]; + // // System.arraycopy(pdf, spr.content_start_index, data, 0, data_len); + // // System.out.println(new String(data, "US-ASCII")); + // + // } + // else + // { + // System.out.println("No EGIZ block found."); + // } + // + // } + + public static byte[] getOriginalDocument(final File file_name) throws IOException + { + FileInputStream fis = new FileInputStream(file_name); + byte[] pdf = new byte[(int) file_name.length()]; + fis.read(pdf); + fis.close(); + fis = null; + + int last_start_xref = PDFUtils.findLastStartXRef(pdf); + + StartXRefParseResult sxpr = PDFUtils.parseStartXRef(pdf, last_start_xref); + + XRefSectionParseResult xpr = PDFUtils.parseXRefSection(pdf, sxpr.xref_index); + + TrailerParseResult tpr = PDFUtils.parseTrailer(pdf, xpr.next_index); + + System.out.println("tpr.info = " + tpr.info); + System.out.println("tpr.root = " + tpr.root); + System.out.println("tpr.size = " + tpr.size); + + System.out.println("tpr.has_predecessor = " + tpr.has_predecessor); + if (tpr.has_predecessor) + { + System.out.println("tpr.prev = " + tpr.getPrev()); + } + + int root_index = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(xpr, tpr.root.ior); + ObjectParseResult root_opr = PDFUtils.parseObject(pdf, root_index); + DictionaryParseResult root_dpr = (DictionaryParseResult) root_opr.object; + + byte[] EGIZ_TYPE = new String("EGIZSigDict").getBytes("US-ASCII"); + int egiz_index = PDFUtils.indexOfName(pdf, root_dpr.names, EGIZ_TYPE); + if (egiz_index >= 0) + { + System.out.println("The document is EGIZ-signed. ==> extract original document"); + + IndirectObjectReferenceParseResult egiz_iorpr = (IndirectObjectReferenceParseResult) root_dpr.values.get(egiz_index); + System.out.println("EGIZ signature info at = " + egiz_iorpr); + + int egiz_dict_index = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(xpr, egiz_iorpr.ior); + ObjectParseResult opr = PDFUtils.parseObject(pdf, egiz_dict_index); + DictionaryParseResult egiz_dict = (DictionaryParseResult) opr.object; + + for (int i = 0; i < egiz_dict.names.size(); i++) + { + NameParseResult npr = (NameParseResult) egiz_dict.names.get(i); + int len = npr.next_index - npr.name_start_index; + byte[] name = new byte[len]; + System.arraycopy(pdf, npr.name_start_index, name, 0, len); + System.out.print(" " + new String(name, "US-ASCII") + " = "); + + System.out.println(egiz_dict.values.get(i)); + } + + // Original document size + int key = PDFUtils.indexOfName(pdf, egiz_dict.names, new byte[] { 'O', + 'D', 'S' }); + NumberParseResult ods = (NumberParseResult) egiz_dict.values.get(key); + + int original_document_size = ods.number; + System.out.println("Original Document Size = " + original_document_size); + + byte[] original = new byte[original_document_size]; + System.arraycopy(pdf, 0, original, 0, original_document_size); + + return original; + } + + System.out.println("No EGIZ block found. ==> the whold document is the original document"); + return pdf; + } + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/IndirectObjectReference.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/IndirectObjectReference.java new file mode 100644 index 0000000..fa68bf6 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/IndirectObjectReference.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: IndirectObjectReference.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing; + +/** + * The IndirectObjectReference class completely holds a so called object + * identifier of an indirect object. + * + *

+ * An indirect object is an object not contained within another object. In + * accordance, a direct object is structurally part of another object. For + * example, a direct String object that is the value of some key in a dictionary + * object. + *

+ *

+ * An object identifier uniquely identifies a specific indirect object by the + * object number and the generation number. In PDF such an object identifier may + * be used to reference to the object. + *

+ * + * @author wprinz + */ +public class IndirectObjectReference { + + public int object_number; + + public int generation_number; + + //@Override + public String toString() { + return object_number + " " + generation_number; + } + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFNames.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFNames.java new file mode 100644 index 0000000..66e1931 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFNames.java @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PDFNames.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing; + +/** + * Abstract class that contains several frequently used PDF constants. + * + *

+ * The PDF specification partitions the character set (ASCII) into three groups: + *

+ *
    + *
  • Whitespace characters (space, tab, etc., but also newline and carriage + * return) used to separate tokens. Unless otherwise specified a group of + * consecutive whitespace characters behaves like a single whitespace character.
  • + *
  • Delimiter characters ('(', '<', etc., but also '/', which precedes the + * PDF Key Names in dictionaries) that are used to encircle semantic groups. + *
  • Regular characters are per definition the rest characters that are + * neither whitespaces nor delimiters.
  • + *
+ *

+ * Newlines consist per default of CR and LF, but also LF and even CR alone are + * allowed. It seems that all variations of newlines may exist within a single + * document. + *

+ * + * @author wprinz + */ +public abstract class PDFNames +{ + + /** + * The standard encoding of PDF tokens and names. + * + *

+ * PDF is usually an 8 bit format. Binary data etc. can be saves just as it + * is. Nevertheless all PDF tokens ('xref', 'obj', etc.) and PDF Names + * ('/Size', '/Pages', '/Type', etc.) must be in 7 bit ASCII US encoding. + *

+ *

+ * Therefor, whenever using Java Strings to convert e.g. numbers to such PDF + * tokens use this encoding constant. + *

+ *

+ * The same applies for PDF token/name byte arrays that are retransfromed to + * Java Strings. + *

+ */ + public static final String PDF_STANDARD_ENCODING = "US-ASCII"; + + // Whitespace characters + + // TABLE 3.1 White-space characters + // DECIMAL HEXADECIMAL OCTAL NAME + // 0 00 000 Null (NUL) + // 9 09 011 Tab (HT) + // 10 0A 012 Line feed (LF) + // 12 0C 014 Form feed (FF) + // 13 0D 015 Carriage return + // 32 20 040 Space (SP) + + public static final byte WHITESPACE_NUL = 0x00; + + public static final byte WHITESPACE_HT = 0x09; + + public static final byte WHITESPACE_LF = 0x0A; + + public static final byte WHITESPACE_FF = 0x0C; + + public static final byte WHITESPACE_CR = 0x0D; + + public static final byte WHITESPACE_SP = 0x20; + + public static final byte[] WHITESPACE_CHARACTERS = { WHITESPACE_NUL, + WHITESPACE_HT, WHITESPACE_LF, WHITESPACE_FF, WHITESPACE_CR, WHITESPACE_SP }; + + // comment character + + public static final byte COMMENT = '%'; + + // PDF-version + + public static final byte[] PDF_VERSION_STR = { 'P', 'D', 'F', '-' }; + + public static final byte PDF_VERSION_SEPARATOR = '.'; + + // delimiter characters + + public static final byte DELIMITER_STRING_OPEN = '('; + + public static final byte DELIMITER_STRING_CLOSE = ')'; + + public static final byte DELIMITER_HEXSTRING_OPEN = '<'; + + public static final byte DELIMITER_HEXSTRING_CLOSE = '>'; + + public static final byte DELIMITER_ARRAY_OPEN = '['; + + public static final byte DELIMITER_ARRAY_CLOSE = ']'; + + public static final byte DELIMITER_CURLY_OPEN = '{'; + + public static final byte DELIMITER_CURLY_CLOSE = '}'; + + public static final byte DELIMITER_NAME = '/'; + + public static final byte[] DELIMITER_CHARACTERS = { DELIMITER_STRING_OPEN, + DELIMITER_STRING_CLOSE, DELIMITER_HEXSTRING_OPEN, + DELIMITER_HEXSTRING_CLOSE, DELIMITER_ARRAY_OPEN, DELIMITER_ARRAY_CLOSE, + DELIMITER_CURLY_OPEN, DELIMITER_CURLY_CLOSE, DELIMITER_NAME }; + + // Footer + + public static final byte[] XREF_STR = { 'x', 'r', 'e', 'f' }; + + public static final byte[] TRAILER_STR = { 't', 'r', 'a', 'i', 'l', 'e', 'r' }; + + public static final byte[] STARTXREF_STR = { 's', 't', 'a', 'r', 't', 'x', + 'r', 'e', 'f' }; + + public static final byte[] EOF_STR = { '%', '%', 'E', 'O', 'F' }; + + // objects + + public static final byte[] OBJ_STR = { 'o', 'b', 'j' }; + + public static final byte[] ENDOBJ_STR = { 'e', 'n', 'd', 'o', 'b', 'j' }; + + public static final byte[] DICT_START_STR = { DELIMITER_HEXSTRING_OPEN, + DELIMITER_HEXSTRING_OPEN }; + + public static final byte[] DICT_END_STR = { DELIMITER_HEXSTRING_CLOSE, + DELIMITER_HEXSTRING_CLOSE }; + + public static final byte[] STREAM_STR = { 's', 't', 'r', 'e', 'a', 'm' }; + + public static final byte[] ENDSTREAM_STR = { 'e', 'n', 'd', 's', 't', 'r', + 'e', 'a', 'm' }; + + public static final byte[] NULL_STR = { 'n', 'u', 'l', 'l' }; + + public static final byte[] TRUE_STR = { 't', 'r', 'u', 'e' }; + + public static final byte[] FALSE_STR = { 'f', 'a', 'l', 's', 'e' }; + + // indirect object references + + public static final byte[] REFERENCE_STR = { 'R' }; + + // Dictionary keys + + public static final byte[] SIZE_STR = { 'S', 'i', 'z', 'e' }; + + public static final byte[] PREV_STR = { 'P', 'r', 'e', 'v' }; + + public static final byte[] ROOT_STR = { 'R', 'o', 'o', 't' }; + + public static final byte[] INFO_STR = { 'I', 'n', 'f', 'o' }; + + public static final byte[] LENGTH_STR = { 'L', 'e', 'n', 'g', 't', 'h' }; + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFUtils.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFUtils.java new file mode 100644 index 0000000..9a2f738 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFUtils.java @@ -0,0 +1,1393 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: PDFUtils.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import at.knowcenter.wag.exactparser.ByteArrayUtils; +import at.knowcenter.wag.exactparser.parsing.results.ArrayParseResult; +import at.knowcenter.wag.exactparser.parsing.results.BooleanParseResult; +import at.knowcenter.wag.exactparser.parsing.results.DictionaryParseResult; +import at.knowcenter.wag.exactparser.parsing.results.EOFParseResult; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; +import at.knowcenter.wag.exactparser.parsing.results.HeaderParseResult; +import at.knowcenter.wag.exactparser.parsing.results.HexStringParseResult; +import at.knowcenter.wag.exactparser.parsing.results.IndirectObjectReferenceParseResult; +import at.knowcenter.wag.exactparser.parsing.results.IntegerParseResult; +import at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NameParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NullParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NumberParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ObjectHeaderParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ObjectParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ParseResult; +import at.knowcenter.wag.exactparser.parsing.results.StartXRefParseResult; +import at.knowcenter.wag.exactparser.parsing.results.StreamParseResult; +import at.knowcenter.wag.exactparser.parsing.results.TrailerParseResult; +import at.knowcenter.wag.exactparser.parsing.results.XRefLineParseResult; +import at.knowcenter.wag.exactparser.parsing.results.XRefSectionParseResult; +import at.knowcenter.wag.exactparser.parsing.results.XRefSubSectionParseResult; + + + +/** + * Abstract class that contains several static utility methods for parsing and + * analyzing PDF documents on the lowest level. + * + *

+ * Most operations require random access to the PDF data (mostly to verify the + * synthax). So the whole PDF document has to be provided as a byte array. The + * term "pdf+index" states a specific position index within this byte array. + *

+ * + * @author wprinz + * + */ +public abstract class PDFUtils +{ + + public static boolean isWhitespace(final byte data) + { + return ByteArrayUtils.contains(PDFNames.WHITESPACE_CHARACTERS, data); + } + + public static boolean isDelimiter(final byte data) + { + return ByteArrayUtils.contains(PDFNames.DELIMITER_CHARACTERS, data); + } + + protected static boolean isRegular(final byte data) + { + return !(isWhitespace(data) || isDelimiter(data)); + } + + /** + * Skips whitespace. + * + *

+ * Skips all whitespace, which may be none, one or multiple whitespace + * characters. + *

+ *

+ * Note that this also skips newline characters (which belong to whitespace as + * well). + *

+ * + * @param data + * The PDF data. + * @param index + * The index. + * @return Returns the index of the first non whitespace character. This may + * be equal to index if no whitespaces were skipped at all. + */ + public static int skipWhitespace(final byte[] data, final int index) + { + int non_whitespace_index = index; + while (isWhitespace(data[non_whitespace_index])) + { + non_whitespace_index++; + } + return non_whitespace_index; + } + + /** + * Skips bytes until whitespace is reached. + * + *

+ * Skips all non whitespace characters, which may be none at all. + *

+ * + * @param data + * The PDF data. + * @param index + * The index. + * @return Returns the index of the first whitespace character. This may be + * equal to index if no non whitespaces were skipped at all. + */ + public static int skipToWhitespace(final byte[] data, final int index) + { + int whitespace_index = index; + while (!isWhitespace(data[whitespace_index])) + { + whitespace_index++; + } + return whitespace_index; + } + + protected static final byte[] LINE_TERMINATOR_CRLF = { + PDFNames.WHITESPACE_CR, PDFNames.WHITESPACE_LF }; + + protected static final byte[] LINE_TERMINATOR_CRALONE = { PDFNames.WHITESPACE_CR }; + + protected static final byte[] LINE_TERMINATOR_LF = { PDFNames.WHITESPACE_LF }; + + public static boolean isNewline(final byte[] data, final int index) + { + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_LF)) + { + return true; + } + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRLF)) + { + return true; + } + // although not specified by PDF, some applications use the CR alone as line + // terminator + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRALONE)) + { + return true; + } + return false; + } + + public static int skipNewline(final byte[] data, final int index) + { + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_LF)) + { + return index + LINE_TERMINATOR_LF.length; + } + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRLF)) + { + return index + LINE_TERMINATOR_CRLF.length; + } + // although not specified by PDF, some applications use the CR alone as line + // terminator + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRALONE)) + { + return index + LINE_TERMINATOR_CRALONE.length; + } + + assert false : "don't call this if you don't expect a newline - call skipWhitespace instead"; + return index; + } + + public static int skipToNewline(final byte[] data, final int index) + { + int current_index = index; + for (;;) + { + if (ByteArrayUtils.compareByteArrays(data, current_index, LINE_TERMINATOR_LF)) + { + return current_index + LINE_TERMINATOR_LF.length; + } + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRLF)) + { + return index + LINE_TERMINATOR_CRLF.length; + } + // although not specified by PDF, some applications use the CR alone as + // line terminator + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRALONE)) + { + return index + LINE_TERMINATOR_CRALONE.length; + } + current_index++; + } + } + + /** + * Parses a boolean value. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static BooleanParseResult parseBoolean(final byte[] pdf, + final int index) + { + BooleanParseResult bpr = new BooleanParseResult(); + bpr.start_index = index; + + if (ByteArrayUtils.compareByteArrays(pdf, bpr.start_index, PDFNames.TRUE_STR)) + { + bpr.value = true; + bpr.next_index = bpr.start_index + PDFNames.TRUE_STR.length; + + return bpr; + } + if (ByteArrayUtils.compareByteArrays(pdf, bpr.start_index, PDFNames.FALSE_STR)) + { + bpr.value = false; + bpr.next_index = bpr.start_index + PDFNames.FALSE_STR.length; + + return bpr; + } + + throw new RuntimeException("Boolean couldn't be parsed at index " + index); + } + + public static boolean isSign(final byte data) + { + return data == '+' || data == '-'; + } + + public static boolean isNumeric(final byte data) + { + return '0' <= data && data <= '9'; + } + + /** + * Reads the (positive integer) number from the data. The number must be + * terminated by the end of line. + * + * @param data + * The data. + * @param index + * The index. + * @return Returns the read number. + */ + public static int readNumberFromByteArray(final byte[] data, final int index) + { + NumberParseResult npr = parseNumberFromByteArray(data, index); + + assert npr.number >= 0; + return npr.number; + } + + /** + * Parses an unsigned integer. + * + *

+ * The integer must be a block of successive number characters. It must not be + * preceded by a sign (not even '+'). + *

+ * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static IntegerParseResult parseUnsignedInteger(final byte[] pdf, + final int index) + { + assert isNumeric(pdf[index]); + + String number = ""; + + int cur_index = index; + while (isNumeric(pdf[cur_index])) + { + + number += (char) pdf[cur_index]; + + cur_index++; + } + + // TODO: make better + int int_value = Integer.parseInt(number); + + assert int_value >= 0; + + IntegerParseResult ipr = new IntegerParseResult(); + ipr.start_index = index; + ipr.next_index = cur_index; + ipr.number = int_value; + return ipr; + } + + /** + * Parses a (potentially) signed integer. + * + *

+ * The integer must be a block of successive number characters. It may be + * preceded by a sign character ('+' or '-'). + *

+ * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static IntegerParseResult parseInteger(final byte[] pdf, + final int index) + { + assert isSign(pdf[index]) || isNumeric(pdf[index]); + + int sign = +1; + int number_start = index; + if (pdf[index] == '+') + { + sign = +1; + number_start++; + } + else + { + if (pdf[index] == '-') + { + sign = -1; + number_start++; + } + else + { + assert isNumeric(pdf[index]); + } + } + + IntegerParseResult ipr = parseUnsignedInteger(pdf, number_start); + ipr.start_index = index; + ipr.number *= sign; + return ipr; + } + + /** + * Parses an arbitrary number; + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static NumberParseResult parseNumberFromByteArray(final byte[] pdf, + int index) + { + String number = ""; + + assert isSign(pdf[index]) || isNumeric(pdf[index]); + + int sign = +1; + if (pdf[index] == '+') + { + sign = +1; + index++; + } + else + { + if (pdf[index] == '-') + { + sign = -1; + index++; + } + else + { + assert isNumeric(pdf[index]); + } + } + + while (isNumeric(pdf[index]) || pdf[index] == '.') + { + + number += (char) pdf[index]; + + index++; + } + + NumberParseResult npr = new NumberParseResult(); + npr.next_index = index; + // TODO: make better + try + { + npr.number = Integer.parseInt(number) * sign; + } + catch (NumberFormatException e) + { + npr.floating = Float.parseFloat(number) * sign; + } + + return npr; + } + + /** + * Searches the last occurrence of the "startxref" entry ... in other words + * starts the search from the end of the document and works reversely. + * + * @param pdf + * The complete PDF file data. + * @return Returns the offset (byte index) of the "startxref" entry. + */ + public static int findLastStartXRef(final byte[] pdf) + { + return ByteArrayUtils.lastIndexOf(pdf, PDFNames.STARTXREF_STR); + } + + /** + * Parses the xref section at pdf+index. + * + *

+ * An xref section starts with 'xref' and contains one or more xref + * sub-sections. + *

+ * + * @param pdf + * The PDF data. + * @param index + * The start index of the xref table. + * @return Returns the result of the parsing operation. + */ + public static XRefSectionParseResult parseXRefSection(final byte[] pdf, + final int index) + { + at.knowcenter.wag.exactparser.parsing.results.XRefSectionParseResult xpr = new XRefSectionParseResult(); + xpr.start_index = index; + + assert ByteArrayUtils.compareByteArrays(pdf, xpr.start_index, PDFNames.XREF_STR); + assert isNewline(pdf, xpr.start_index + PDFNames.XREF_STR.length); + + int cur_index = skipWhitespace(pdf, xpr.start_index + PDFNames.XREF_STR.length); + // skipNewline(pdf, xpr.start_index + PDFNames.XREF_STR.length); + + for (;;) + { + // trailer ends the xref section. + if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.TRAILER_STR)) + { + break; + } + + // no trailer ==> another xref section + + XRefSubSectionParseResult sspr = parseXRefSubSection(pdf, cur_index); + xpr.appendXRefSubSection(sspr); + + cur_index = sspr.next_index; + } + + xpr.next_index = cur_index; + assert ByteArrayUtils.compareByteArrays(pdf, xpr.next_index, PDFNames.TRAILER_STR); + + return xpr; + } + + /** + * Parses a xref sub-section. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static XRefSubSectionParseResult parseXRefSubSection(final byte[] pdf, + final int index) + { + XRefSubSectionParseResult sspr = new XRefSubSectionParseResult(); + sspr.start_index = index; + + NumberParseResult start_obj_num_npr = parseNumberFromByteArray(pdf, sspr.start_index); + sspr.start_obj_number = start_obj_num_npr.number; + assert sspr.start_obj_number >= 0; + + assert isWhitespace(pdf[start_obj_num_npr.next_index]); + int num_obj_index = skipWhitespace(pdf, start_obj_num_npr.next_index); + + NumberParseResult num_obj_npr = parseNumberFromByteArray(pdf, num_obj_index); + sspr.num_objects = num_obj_npr.number; + + // assert isNewline(pdf, num_obj_npr.next_index); + assert isWhitespace(pdf[num_obj_npr.next_index]); + int start_of_line = skipWhitespace(pdf, num_obj_npr.next_index); + // skipNewline(pdf, num_obj_npr.next_index); + + for (int i = 0; i < sspr.num_objects; i++) + { + final int cur_object_number = sspr.start_obj_number + i; + + XRefLineParseResult lpr = parseXrefLine(pdf, start_of_line); + sspr.appendXRefLine(lpr); + + // System.out.println("xref line of object " + (oc.start_obj_number + i) + + // " at " + lpr.start_index + ": " + lpr.object_offset + " " + + // lpr.generation_number + " " + (char) lpr.object_usage); + + if (lpr.object_usage == 'n') + { + // check the line - this simple check may make problems with object + // streams and xref streams + ObjectHeaderParseResult ohpr = parseObjectHeader(pdf, lpr.object_offset); + assert ohpr.object_number == cur_object_number; + assert ohpr.generation_number == lpr.generation_number; + } + + start_of_line = lpr.next_index; + } + + sspr.next_index = start_of_line; + return sspr; + } + + /** + * Parses a single 20 bytes xref line at pdf+index. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static XRefLineParseResult parseXrefLine(final byte[] pdf, + final int index) + { + XRefLineParseResult lpr = new XRefLineParseResult(); + + lpr.start_index = index; + + IntegerParseResult object_offset_ipr = parseUnsignedInteger(pdf, lpr.start_index); + lpr.object_offset = object_offset_ipr.number; + assert lpr.object_offset >= 0; + assert lpr.object_offset < pdf.length; + assert object_offset_ipr.next_index == lpr.start_index + 10; + + assert pdf[object_offset_ipr.next_index] == PDFNames.WHITESPACE_SP; // Standard + // explicitely + // says 1 + // single + // SPACE + int generation_number_index = object_offset_ipr.next_index + 1; + + IntegerParseResult generation_number_ipr = parseUnsignedInteger(pdf, generation_number_index); + lpr.generation_number = generation_number_ipr.number; + assert generation_number_ipr.next_index == lpr.start_index + 16; + + assert pdf[generation_number_ipr.next_index] == PDFNames.WHITESPACE_SP; + int usage_index = generation_number_ipr.next_index + 1; + + lpr.object_usage = pdf[usage_index]; + assert lpr.object_usage == 'n' || lpr.object_usage == 'f'; + + if (pdf[usage_index + 1] == PDFNames.WHITESPACE_SP) + { + assert pdf[usage_index + 2] == PDFNames.WHITESPACE_CR || pdf[usage_index + 2] == PDFNames.WHITESPACE_LF; + } + else + { + assert pdf[usage_index + 1] == PDFNames.WHITESPACE_CR; + assert pdf[usage_index + 2] == PDFNames.WHITESPACE_LF; + } + + lpr.next_index = usage_index + 3; + + assert lpr.next_index == lpr.start_index + 20; + + return lpr; + } + + public static int indexOfName(final byte[] pdf, List names, + byte[] sought) + { + for (int i = 0; i < names.size(); i++) + { + NameParseResult name = (NameParseResult) names.get(i); + if (ByteArrayUtils.compareByteArrays(pdf, name.name_start_index, sought)) + { + return i; + } + } + return -1; + } + + public static TrailerParseResult parseTrailer(final byte[] pdf, + final int index) + { + TrailerParseResult tpr = new TrailerParseResult(); + tpr.start_index = index; + tpr.has_predecessor = false; + + assert ByteArrayUtils.compareByteArrays(pdf, tpr.start_index, PDFNames.TRAILER_STR); + + // assert isWhitespace(pdf[tpr.start_index + PDFNames.TRAILER_STR.length]); + tpr.contents_index = skipWhitespace(pdf, tpr.start_index + PDFNames.TRAILER_STR.length); + + int trailer_dict_index = skipWhitespace(pdf, tpr.contents_index); + + assert ByteArrayUtils.compareByteArrays(pdf, trailer_dict_index, PDFNames.DICT_START_STR); + + tpr.dpr = parseDictionary(pdf, trailer_dict_index); + + int cur_index = tpr.dpr.next_index; + + int info_index = indexOfName(pdf, tpr.dpr.names, PDFNames.INFO_STR); + if (info_index >= 0) + { + tpr.info = (IndirectObjectReferenceParseResult) tpr.dpr.values.get(info_index); + } + + int root_index = indexOfName(pdf, tpr.dpr.names, PDFNames.ROOT_STR); + if (root_index >= 0) + { + tpr.root = (IndirectObjectReferenceParseResult) tpr.dpr.values.get(root_index); + } + + tpr.size = ((NumberParseResult) tpr.dpr.values.get(indexOfName(pdf, tpr.dpr.names, PDFNames.SIZE_STR))).number; + + int prev_index = indexOfName(pdf, tpr.dpr.names, PDFNames.PREV_STR); + if (prev_index >= 0) + { + tpr.has_predecessor = true; + tpr.setPrev(((NumberParseResult) tpr.dpr.values.get(prev_index)).number); + } + + // + // int cur_index = skipWhitespace(pdf, trailer_dict_index + + // PDFNames.DICT_START_STR.length); + // for (;;) { + // if (ByteArrayUtils.compareByteArrays(pdf, cur_index, + // PDFNames.DICT_END_STR)) { + // cur_index += PDFNames.DICT_END_STR.length; + // break; + // } + // + // assert pdf[cur_index] == PDFNames.DELIMITER_NAME; + // cur_index++; + // + // if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.INFO_STR)) + // { + // assert isWhitespace(pdf[cur_index + PDFNames.INFO_STR.length]); + // int ir_index = skipWhitespace(pdf, cur_index + PDFNames.INFO_STR.length); + // + // IndirectObjectReferenceParseResult iorpr = + // parseIndirectObjectReference(pdf, ir_index); + // tpr.info = iorpr; + // + // cur_index = skipWhitespace(pdf, iorpr.next_index); + // continue; + // } + // + // if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.ROOT_STR)) + // { + // assert isWhitespace(pdf[cur_index + PDFNames.ROOT_STR.length]); + // int ir_index = skipWhitespace(pdf, cur_index + PDFNames.ROOT_STR.length); + // + // IndirectObjectReferenceParseResult iorpr = + // parseIndirectObjectReference(pdf, ir_index); + // tpr.root = iorpr; + // + // cur_index = skipWhitespace(pdf, iorpr.next_index); + // continue; + // } + // + // if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.SIZE_STR)) + // { + // assert isWhitespace(pdf[cur_index + PDFNames.SIZE_STR.length]); + // int size_index = skipWhitespace(pdf, cur_index + + // PDFNames.SIZE_STR.length); + // + // NumberParseResult npr = parseNumberFromByteArray(pdf, size_index); + // tpr.size = npr.number; + // assert tpr.size > 0; + // + // cur_index = skipWhitespace(pdf, npr.next_index); + // continue; + // } + // + // if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.PREV_STR)) + // { + // assert isWhitespace(pdf[cur_index + PDFNames.PREV_STR.length]); + // int prev_index = skipWhitespace(pdf, cur_index + + // PDFNames.PREV_STR.length); + // + // NumberParseResult npr = parseNumberFromByteArray(pdf, prev_index); + // tpr.has_predecessor = true; + // tpr.setPrev(npr.number); + // assert tpr.getPrev() >= 0; + // assert tpr.getPrev() < pdf.length; + // + // assert ByteArrayUtils.compareByteArrays(pdf, tpr.getPrev(), + // PDFNames.XREF_STR); + // + // cur_index = skipWhitespace(pdf, npr.next_index); + // continue; + // } + // + // // unrecognized type + // // skip to next delimiter + // // TODO: this will not work with nested dicts. + // while (pdf[cur_index] != PDFNames.DELIMITER_NAME) { + // cur_index++; + // } + // } + + tpr.contents_end_index = cur_index; + tpr.next_index = skipWhitespace(pdf, tpr.contents_end_index); + + assert ByteArrayUtils.compareByteArrays(pdf, tpr.next_index, PDFNames.STARTXREF_STR); + return tpr; + } + + /** + * Parses the startxref section at pdf+index. + * + * @param pdf + * The complete PDF file data. + * @param index + * The index of the startxref section. + * @return Returns the retsult of the parsing operation. + */ + public static StartXRefParseResult parseStartXRef(final byte[] pdf, + final int index) + { + StartXRefParseResult spr = new StartXRefParseResult(); + spr.next_index = index; + + assert ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.STARTXREF_STR); + assert isNewline(pdf, index + PDFNames.STARTXREF_STR.length); + + int index_of_number = skipWhitespace(pdf, index + PDFNames.STARTXREF_STR.length); + // skipNewline(pdf, index + PDFNames.STARTXREF_STR.length); + NumberParseResult npr = parseNumberFromByteArray(pdf, index_of_number); + spr.xref_index = npr.number; + + assert isNewline(pdf, npr.next_index); + spr.next_index = skipWhitespace(pdf, npr.next_index); + // skipNewline(pdf, npr.next_index); + + assert ByteArrayUtils.compareByteArrays(pdf, spr.next_index, PDFNames.EOF_STR); + + assert spr.xref_index >= 0; + assert spr.xref_index < pdf.length; + + // A linearized document sets the startxref value of the first page's footer + // to 0. + if (spr.xref_index != 0) + { + assert ByteArrayUtils.compareByteArrays(pdf, spr.xref_index, PDFNames.XREF_STR); + } + + return spr; + } + + /** + * Parses the End Of File (EOF) marker at pdf+index. + * + * @param pdf + * The PDF data. + * @param index + * The index where to start the parsing. + * @return Returns the result of the parsing operation. + */ + public static EOFParseResult parseEOF(final byte[] pdf, final int index) + { + EOFParseResult eofpr = new EOFParseResult(); + eofpr.start_index = index; + + assert ByteArrayUtils.compareByteArrays(pdf, eofpr.start_index, PDFNames.EOF_STR); + + eofpr.eof_end_index = eofpr.start_index + PDFNames.EOF_STR.length; + + // Note: The EOF marker is not necessarily terminated with a + // newline. + + // perhaps explicitely determine a newline. + + eofpr.next_index = eofpr.eof_end_index; + + return eofpr; + } + + public static boolean isIndirectObjectReference(final byte[] pdf, + final int index) + { + IndirectObjectReferenceParseResult iorpr = new IndirectObjectReferenceParseResult(); + iorpr.ior = new IndirectObjectReference(); + iorpr.start_index = index; + + if (!PDFUtils.isNumeric(pdf[iorpr.start_index])) + { + return false; + } + NumberParseResult object_number_npr = parseNumberFromByteArray(pdf, iorpr.start_index); + iorpr.ior.object_number = object_number_npr.number; + if (iorpr.ior.object_number <= 0) + { + return false; + } + + if (!isWhitespace(pdf[object_number_npr.next_index])) + { + return false; + } + int generation_number_index = skipWhitespace(pdf, object_number_npr.next_index); + + if (!PDFUtils.isNumeric(pdf[generation_number_index])) + { + return false; + } + NumberParseResult generation_number_npr = parseNumberFromByteArray(pdf, generation_number_index); + iorpr.ior.generation_number = generation_number_npr.number; + if (iorpr.ior.generation_number < 0) + { + return false; + } + + if (!isWhitespace(pdf[generation_number_npr.next_index])) + { + return false; + } + int R_index = skipWhitespace(pdf, generation_number_npr.next_index); + + if (!ByteArrayUtils.compareByteArrays(pdf, R_index, PDFNames.REFERENCE_STR)) + { + return false; + } + + iorpr.next_index = R_index + PDFNames.REFERENCE_STR.length; + + return true; + } + + /** + * Parses an indirect object reference. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static IndirectObjectReferenceParseResult parseIndirectObjectReference( + final byte[] pdf, final int index) + { + + assert isIndirectObjectReference(pdf, index); + + IndirectObjectReferenceParseResult iorpr = new IndirectObjectReferenceParseResult(); + iorpr.ior = new IndirectObjectReference(); + iorpr.start_index = index; + + NumberParseResult object_number_npr = parseNumberFromByteArray(pdf, iorpr.start_index); + iorpr.ior.object_number = object_number_npr.number; + assert iorpr.ior.object_number > 0; + + assert isWhitespace(pdf[object_number_npr.next_index]); + int generation_number_index = skipWhitespace(pdf, object_number_npr.next_index); + + NumberParseResult generation_number_npr = parseNumberFromByteArray(pdf, generation_number_index); + iorpr.ior.generation_number = generation_number_npr.number; + assert iorpr.ior.generation_number >= 0; + + assert isWhitespace(pdf[generation_number_npr.next_index]); + int R_index = skipWhitespace(pdf, generation_number_npr.next_index); + + assert ByteArrayUtils.compareByteArrays(pdf, R_index, PDFNames.REFERENCE_STR); + + iorpr.next_index = R_index + PDFNames.REFERENCE_STR.length; + + return iorpr; + } + + /** + * Parses the object header at pdf+index. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static ObjectHeaderParseResult parseObjectHeader(final byte[] pdf, + final int index) + { + ObjectHeaderParseResult ohpr = new ObjectHeaderParseResult(); + + ohpr.start_index = index; + + NumberParseResult object_number_npr = parseNumberFromByteArray(pdf, ohpr.start_index); + ohpr.object_number = object_number_npr.number; + assert ohpr.object_number > 0; + + assert isWhitespace(pdf[object_number_npr.next_index]); + int generation_number_index = skipWhitespace(pdf, object_number_npr.next_index); + + NumberParseResult generation_number_npr = parseNumberFromByteArray(pdf, generation_number_index); + ohpr.generation_number = generation_number_npr.number; + assert ohpr.generation_number >= 0; + + assert isWhitespace(pdf[generation_number_npr.next_index]); + int obj_index = skipWhitespace(pdf, generation_number_npr.next_index); + + assert ByteArrayUtils.compareByteArrays(pdf, obj_index, PDFNames.OBJ_STR); + + // not all pdfwriters make a newline after obj... + // assert isNewline(pdf, obj_index + PDFNames.OBJ_STR.length); + // ohpr.next_index = skipNewline(pdf, obj_index + PDFNames.OBJ_STR.length); + ohpr.next_index = skipWhitespace(pdf, obj_index + PDFNames.OBJ_STR.length); + + return ohpr; + } + + public static ObjectParseResult parseObject(final byte[] pdf, final int index) + { + ObjectParseResult opr = new ObjectParseResult(); + opr.start_index = index; + + opr.header = parseObjectHeader(pdf, opr.start_index); + opr.content_index = opr.header.next_index; + + int cur_index = skipWhitespace(pdf, opr.content_index); + + opr.object = parseUnknownObject(pdf, cur_index); + + cur_index = skipWhitespace(pdf, opr.object.next_index); + + opr.end_of_content_index = cur_index; + assert ByteArrayUtils.compareByteArrays(pdf, opr.end_of_content_index, PDFNames.ENDOBJ_STR); + + cur_index = opr.end_of_content_index + PDFNames.ENDOBJ_STR.length; + + opr.next_index = cur_index; + //assert isNewline(pdf, cur_index); + //opr.next_index = skipNewline(pdf, cur_index); + + return opr; + } + + public static ParseResult parseUnknownObject(final byte[] pdf, final int index) + { + if (ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.DICT_START_STR)) + { + DictionaryParseResult dpr = parseDictionary(pdf, index); + + int possible_stream_index = skipWhitespace(pdf, dpr.next_index); + if (ByteArrayUtils.compareByteArrays(pdf, possible_stream_index, PDFNames.STREAM_STR)) + { + return parseStream(pdf, possible_stream_index, dpr); + } + + return dpr; + } + + if (ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.NULL_STR)) + { + return parseNull(pdf, index); + } + + if (ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.TRUE_STR) || ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.FALSE_STR)) + { + return parseBoolean(pdf, index); + } + + final byte first_byte = pdf[index]; + + if (isNumeric(first_byte) || isSign(first_byte)) + { + + // try to parse a Indirect reference first - if this fails, parse a number + if (isIndirectObjectReference(pdf, index)) + { + return parseIndirectObjectReference(pdf, index); + } + + return parseNumberFromByteArray(pdf, index); + } + + ParseResult pr = null; + + switch (first_byte) + { + case PDFNames.DELIMITER_STRING_OPEN: + pr = parseLiteralString(pdf, index); + break; + case PDFNames.DELIMITER_HEXSTRING_OPEN: + pr = parseHexString(pdf, index); + break; + case PDFNames.DELIMITER_ARRAY_OPEN: + pr = parseArray(pdf, index); + break; + case PDFNames.DELIMITER_NAME: + pr = parseName(pdf, index); + break; + default: + throw new RuntimeException("Unknown first_byte when parsing an unknown object at index=" + index + "."); + // assert false : "nyi or invalid char"; + } + assert pr != null; + + return pr; + } + + /** + * Parses a literal string. + * + *

+ * A literal string is a string of ASCII characters enclosed by '(' and ')'. + * Balanced pairs of '(' and ')' are allowed within the string. Unbalanced '(' + * or ')' must be escaped as '\(' or '\)'. + *

+ * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static LiteralStringParseResult parseLiteralString(final byte[] pdf, + final int index) + { + LiteralStringParseResult lspr = new LiteralStringParseResult(); + lspr.start_index = index; + + assert pdf[lspr.start_index] == PDFNames.DELIMITER_STRING_OPEN; + + lspr.content_start_index = lspr.start_index + 1; + + int cur_index = lspr.content_start_index; + int parenthesis_stack = 0; + for (;;) + { + if (pdf[cur_index] == '\\' && (pdf[cur_index + 1] == PDFNames.DELIMITER_STRING_CLOSE || pdf[cur_index + 1] == PDFNames.DELIMITER_STRING_OPEN)) + { + cur_index += 2; + continue; + } + if (pdf[cur_index] == PDFNames.DELIMITER_STRING_OPEN) + { + parenthesis_stack++; + } + if (pdf[cur_index] == PDFNames.DELIMITER_STRING_CLOSE) + { + assert parenthesis_stack >= 0; + + if (parenthesis_stack == 0) + { + break; + } + + assert parenthesis_stack > 0; + parenthesis_stack--; + + } + + cur_index++; + } + + lspr.content_end_index = cur_index; + assert pdf[lspr.content_end_index] == PDFNames.DELIMITER_STRING_CLOSE; + + lspr.next_index = lspr.content_end_index + 1; + + return lspr; + } + + protected static boolean isHex(final byte data) + { + return isNumeric(data) || ('a' <= data && data <= 'f') || ('A' <= data && data <= 'f'); + } + + /** + * Parses a hexadecimal string. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static HexStringParseResult parseHexString(final byte[] pdf, + final int index) + { + HexStringParseResult hspr = new HexStringParseResult(); + hspr.start_index = index; + + assert pdf[hspr.start_index] == PDFNames.DELIMITER_HEXSTRING_OPEN; + + hspr.content_start_index = hspr.start_index + 1; + + int cur_index = hspr.content_start_index; + while (isHex(pdf[cur_index]) || isWhitespace(pdf[cur_index])) + { + cur_index++; + } + + hspr.content_end_index = cur_index; + assert pdf[hspr.content_end_index] == PDFNames.DELIMITER_HEXSTRING_CLOSE; + + hspr.next_index = hspr.content_end_index + 1; + + return hspr; + } + + public static ArrayParseResult parseArray(final byte[] pdf, final int index) + { + ArrayParseResult apr = new ArrayParseResult(); + apr.start_index = index; + assert pdf[apr.start_index] == PDFNames.DELIMITER_ARRAY_OPEN; + + apr.content_start_index = apr.start_index + 1; + + apr.elements = new ArrayList(); + + int cur_index = skipWhitespace(pdf, apr.content_start_index); + for (;;) + { + if (pdf[cur_index] == PDFNames.DELIMITER_ARRAY_CLOSE) + { + break; + } + + ParseResult pr = parseUnknownObject(pdf, cur_index); + apr.elements.add(pr); + + cur_index = skipWhitespace(pdf, pr.next_index); + } + assert pdf[cur_index] == PDFNames.DELIMITER_ARRAY_CLOSE; + + apr.content_end_index = cur_index; + assert pdf[apr.content_end_index] == PDFNames.DELIMITER_ARRAY_CLOSE; + + apr.next_index = apr.content_end_index + 1; + return apr; + } + + /** + * Parses a PDF Name. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of this parsing operation. + */ + public static NameParseResult parseName(final byte[] pdf, final int index) + { + NameParseResult npr = new NameParseResult(); + npr.start_index = index; + + assert pdf[npr.start_index] == PDFNames.DELIMITER_NAME; + + npr.name_start_index = npr.start_index + 1; + + assert isRegular(pdf[npr.name_start_index]); + + int cur_index = npr.name_start_index; + while (isRegular(pdf[cur_index])) + { + cur_index++; + } + assert !isRegular(pdf[cur_index]); + + npr.next_index = cur_index; + + return npr; + } + + public static DictionaryParseResult parseDictionary(final byte[] pdf, + final int index) + { + DictionaryParseResult dpr = new DictionaryParseResult(); + dpr.start_index = index; + + assert ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.DICT_START_STR); + + dpr.content_start_index = dpr.start_index + PDFNames.DICT_START_STR.length; + + dpr.names = new ArrayList(); + dpr.values = new ArrayList(); + + int cur_index = skipWhitespace(pdf, dpr.content_start_index); + for (;;) + { + if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.DICT_END_STR)) + { + break; + } + + NameParseResult npr = parseName(pdf, cur_index); + dpr.names.add(npr); + + cur_index = npr.next_index; + cur_index = skipWhitespace(pdf, cur_index); + + ParseResult pr = parseUnknownObject(pdf, cur_index); + dpr.values.add(pr); + + cur_index = pr.next_index; + cur_index = skipWhitespace(pdf, cur_index); + } + + dpr.content_end_index = cur_index; + assert ByteArrayUtils.compareByteArrays(pdf, dpr.content_end_index, PDFNames.DICT_END_STR); + dpr.next_index = dpr.content_end_index + PDFNames.DICT_END_STR.length; + + return dpr; + } + + /** + * Parses a stream. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @param dpr + * The DictionaryParseResult of the stream's dictionary. This + * dictionary must precede the stream keyword. Usually this is + * provided in the stream object's dictionary via the /Length field. + * @return Returns the result of this parsing operation. + */ + public static StreamParseResult parseStream(final byte[] pdf, + final int index, final DictionaryParseResult dpr) + { + StreamParseResult spr = new StreamParseResult(); + spr.stream_dictionary = dpr; + spr.start_index = spr.stream_dictionary.start_index; + spr.stream_start_index = index; + assert ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.STREAM_STR); + + // assert that the provided dictionary really belongs to this stream + assert spr.stream_start_index == skipWhitespace(pdf, spr.stream_dictionary.next_index); + + // see PDF Spec 1.4 chapter 3.2.7 + assert pdf[spr.stream_start_index + PDFNames.STREAM_STR.length] == PDFNames.WHITESPACE_LF || (pdf[spr.stream_start_index + PDFNames.STREAM_STR.length] == PDFNames.WHITESPACE_CR && pdf[spr.stream_start_index + PDFNames.STREAM_STR.length + 1] == PDFNames.WHITESPACE_LF); + spr.content_start_index = skipNewline(pdf, spr.stream_start_index + PDFNames.STREAM_STR.length); + + int length = -1; + for (int i = 0; i < spr.stream_dictionary.names.size(); i++) + { + NameParseResult name = (NameParseResult) spr.stream_dictionary.names.get(i); + if (ByteArrayUtils.compareByteArrays(pdf, name.name_start_index, PDFNames.LENGTH_STR)) + { + ParseResult pr = (ParseResult) spr.stream_dictionary.values.get(i); + NumberParseResult npr = null; + if (pr instanceof IndirectObjectReferenceParseResult) + { + System.out.println("An object stream with indirect length - cannot parse this instantly - parse later again."); + spr.content_end_index = -1; + spr.next_index = -1; + return spr; + + } + else + { + npr = (NumberParseResult) pr; + } + assert npr != null; + + length = npr.number; + break; + } + + } + assert length >= 0; + + spr.content_end_index = spr.content_start_index + length; + + int endstr_index = spr.content_end_index; + if (isNewline(pdf, endstr_index)) + { + endstr_index = skipWhitespace(pdf, endstr_index); + } + assert ByteArrayUtils.compareByteArrays(pdf, endstr_index, PDFNames.ENDSTREAM_STR); + + spr.next_index = endstr_index + PDFNames.ENDSTREAM_STR.length; + + return spr; + } + + public static NullParseResult parseNull(final byte[] pdf, final int index) + { + NullParseResult npr = new NullParseResult(); + npr.start_index = index; + + assert ByteArrayUtils.compareByteArrays(pdf, npr.start_index, PDFNames.NULL_STR); + + npr.next_index = npr.start_index + PDFNames.NULL_STR.length; + + return npr; + } + + public static int getObjectOffsetFromXRefByIndirectObjectReference( + XRefSectionParseResult xpr, IndirectObjectReference ior) + { + Iterator it = xpr.xref_subsections.iterator(); + while (it.hasNext()) + { + XRefSubSectionParseResult section = (XRefSubSectionParseResult) it.next(); + + for (int i = 0; i < section.xref_lines.size(); i++) + { + if (section.start_obj_number + i == ior.object_number) + { + XRefLineParseResult lpr = (XRefLineParseResult) section.xref_lines.get(i); + return lpr.object_offset; + } + } + } + + return -1; + } + + public static HeaderParseResult parseHeader(final byte[] pdf, final int index) + { + HeaderParseResult hpr = new HeaderParseResult(); + hpr.start_index = index; + + assert pdf[hpr.start_index] == PDFNames.COMMENT; + + assert ByteArrayUtils.compareByteArrays(pdf, hpr.start_index + 1, PDFNames.PDF_VERSION_STR); + + hpr.major_index = hpr.start_index + 1 + PDFNames.PDF_VERSION_STR.length; + + IntegerParseResult major_ipr = parseUnsignedInteger(pdf, hpr.major_index); + hpr.major = major_ipr.number; + assert hpr.major >= 1; + + assert pdf[major_ipr.next_index] == PDFNames.PDF_VERSION_SEPARATOR; + + hpr.minor_index = major_ipr.next_index + 1; + + IntegerParseResult minor_ipr = parseUnsignedInteger(pdf, hpr.minor_index); + hpr.minor = minor_ipr.number; + assert hpr.minor >= 0; + + assert isWhitespace(pdf[minor_ipr.next_index]); + hpr.binary_characters_index = skipWhitespace(pdf, minor_ipr.next_index); + + assert pdf[hpr.binary_characters_index] == PDFNames.COMMENT; + + hpr.next_index = skipToNewline(pdf, hpr.binary_characters_index); + return hpr; + } + + /** + * Parses a PDF footer. + * + *

+ * A PDF footer starts with the xref, followed by the trailer, the startxref + * and the EOF marker. + *

+ * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + * + * @see FooterParseResult + */ + public static FooterParseResult parseFooter(final byte[] pdf, final int index) + { + FooterParseResult fpr = new FooterParseResult(); + fpr.start_index = index; + + fpr.xpr = PDFUtils.parseXRefSection(pdf, fpr.start_index); + + fpr.tpr = PDFUtils.parseTrailer(pdf, fpr.xpr.next_index); + + fpr.sxpr = PDFUtils.parseStartXRef(pdf, fpr.tpr.next_index); + + fpr.eofpr = PDFUtils.parseEOF(pdf, fpr.sxpr.next_index); + + fpr.next_index = fpr.eofpr.next_index; + return fpr; + } + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ArrayParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ArrayParseResult.java new file mode 100644 index 0000000..53d2838 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ArrayParseResult.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ArrayParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +import java.util.List; + +/** + * The result of parsing a hex string. + * + * @see at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult + * + * @author wprinz + */ +public class ArrayParseResult extends ContainerParseResult { + + public List elements = null; + + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/BooleanParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/BooleanParseResult.java new file mode 100644 index 0000000..5b6c31d --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/BooleanParseResult.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: BooleanParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * Parse result of parsing a boolean value. + * + * @author wprinz + */ +public class BooleanParseResult extends ParseResult +{ + + public boolean value = false; + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ContainerParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ContainerParseResult.java new file mode 100644 index 0000000..3ca8dc2 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ContainerParseResult.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ContainerParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * Base class of container parse results. + * + *

+ * Containers are types that include some content. + * E.g. literal strings include string data as content, + * arrays include elements as content etc. + *

+ * + * @author wprinz + */ +public class ContainerParseResult extends ParseResult { + + public int content_start_index = -1; + public int content_end_index = -1; + + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/DictionaryParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/DictionaryParseResult.java new file mode 100644 index 0000000..b976bd2 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/DictionaryParseResult.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: DictionaryParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +import java.util.List; + +/** + * The result of parsing a dictionary. + * + * @author wprinz + */ +public class DictionaryParseResult extends ContainerParseResult +{ + + public List names = null; + + public List values = null; +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/EOFParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/EOFParseResult.java new file mode 100644 index 0000000..19d864d --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/EOFParseResult.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: EOFParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The result of parsing the End Of File marker. + * + * @author wprinz + */ +public class EOFParseResult extends ParseResult +{ + + /** + * The index of the byte after the EOF marker. + * + *

+ * A newline is not necessary after the EOF marker, but if it is present it will be considered + * as part of it. + * So eof_end_index marks this newline. + * If eof_end_index == next_index, then no new line is present. + *

+ */ + public int eof_end_index = -1; +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/FooterParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/FooterParseResult.java new file mode 100644 index 0000000..d8eb2e1 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/FooterParseResult.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: FooterParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + + +/** + * The result of parsing a PDF footer block. + * + *

+ * A PDF footer block starts with the xref table followed by the trailer, the + * startxref and finally the EOF marker. Usually the footer should be at the end + * of the file. All object offsets in the footer's xref table should be before + * the footer itself. Nevertheless, there are PDF Writers (e.g. Microsoft Word) + * that put the footer at the beginning of the document so that all indirect + * objects are after the EOF marker. + *

+ * + * @author wprinz + */ +public class FooterParseResult extends ParseResult +{ + + public StartXRefParseResult sxpr = null; + + public EOFParseResult eofpr = null; + + public XRefSectionParseResult xpr = null; + + public TrailerParseResult tpr = null; +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HeaderParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HeaderParseResult.java new file mode 100644 index 0000000..893fa07 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HeaderParseResult.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: HeaderParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The result of parsing the PDF header. + * + *

+ * The header contains the PDF version and is usually followed by some binary + * characers. + *

+ * + * @author wprinz + */ +public class HeaderParseResult extends ParseResult +{ + public int major_index = -1; + public int minor_index = -1; + + public int major = -1; + public int minor = -1; + + public int binary_characters_index = -1; + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HexStringParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HexStringParseResult.java new file mode 100644 index 0000000..fdaaf66 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HexStringParseResult.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: HexStringParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The result of parsing a hex string. + * + * @see at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult + * + * @author wprinz + */ +public class HexStringParseResult extends ContainerParseResult { +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IndirectObjectReferenceParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IndirectObjectReferenceParseResult.java new file mode 100644 index 0000000..d839004 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IndirectObjectReferenceParseResult.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: IndirectObjectReferenceParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +import at.knowcenter.wag.exactparser.parsing.IndirectObjectReference; + +/** + * The ParseResult of parsing an indirect object reference. + * + * @author wprinz + */ +public class IndirectObjectReferenceParseResult extends ParseResult { + + public IndirectObjectReference ior; + + //@Override + public String toString() + { + return ior.toString() + " R"; + } +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IntegerParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IntegerParseResult.java new file mode 100644 index 0000000..5eec5e5 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IntegerParseResult.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: IntegerParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * @author wprinz + */ +public class IntegerParseResult extends ParseResult +{ + + public int number; + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/LiteralStringParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/LiteralStringParseResult.java new file mode 100644 index 0000000..0c7872d --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/LiteralStringParseResult.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: LiteralStringParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The result of parsing a simple string (ASCII string). + * + * @see at.knowcenter.wag.exactparser.parsing.results.HexStringParseResult + * + * @author wprinz + */ +public class LiteralStringParseResult extends ContainerParseResult { + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NameParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NameParseResult.java new file mode 100644 index 0000000..9a8aa39 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NameParseResult.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: NameParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * @author wprinz + */ +public class NameParseResult extends ParseResult { + + public int name_start_index = -1; + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NullParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NullParseResult.java new file mode 100644 index 0000000..fd6e57d --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NullParseResult.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: NullParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The result of parsing a "null". + * + * @author wprinz + */ +public class NullParseResult extends ParseResult { +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NumberParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NumberParseResult.java new file mode 100644 index 0000000..a6882c1 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NumberParseResult.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: NumberParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The ParseResult of parsing an integer number. + * + * @author wprinz + */ +public class NumberParseResult extends ParseResult { + /** + * The (signed) integer number. + */ + public int number; + + // TODO: make better + public float floating; +} \ No newline at end of file diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectHeaderParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectHeaderParseResult.java new file mode 100644 index 0000000..5a2265a --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectHeaderParseResult.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ObjectHeaderParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The ParseResult of a parsing an object header. + * + *

+ * Note that this information regards only the object header and not the + * contents of the object itself. (meaning: next points to the contents and not + * to the end of the whole object) + *

+ * + * @author Administrator + */ +public class ObjectHeaderParseResult extends ParseResult { + + /** + * The object's object number. + */ + public int object_number = -1; + + /** + * The object's generation number. + */ + public int generation_number = -1; + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectParseResult.java new file mode 100644 index 0000000..4d9c224 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectParseResult.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ObjectParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + + +/** + * The ParseResult of parsing an indirect object. + * @author wprinz + */ +public class ObjectParseResult extends ParseResult { + + public int content_index = -1; + public int end_of_content_index = -1; + + public ObjectHeaderParseResult header = null; + +/* enum ObjectType + { + UNKNOWN_TO_PARSER, + OBJ_DICTIONARY + }; + + public ObjectType object_type = ObjectType.UNKNOWN_TO_PARSER; + */ + public ParseResult object = null; + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ParseResult.java new file mode 100644 index 0000000..d7ad4e9 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ParseResult.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: ParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * Base class of all parse results. + * + * @author wprinz + */ +public class ParseResult { + + /** + * The start index, where the parser started its work and where the parsed + * entity begins. + */ + public int start_index = -1; + + /** + * The index of the next entity following the currently parsed entity. + * + *

+ * This is the index of the first byte not belonging to this entity anymore. + *

+ */ + public int next_index = -1; + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StartXRefParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StartXRefParseResult.java new file mode 100644 index 0000000..801e04b --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StartXRefParseResult.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: StartXRefParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + + +/** + * The ParseResult of parsing a startxref entry. + * @author wprinz + */ +public class StartXRefParseResult extends ParseResult { + + public int xref_index; +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StreamParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StreamParseResult.java new file mode 100644 index 0000000..6682d55 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StreamParseResult.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: StreamParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + + +/** + * The result of parsing a hex string. + * + * @see at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult + * + * @author wprinz + */ +public class StreamParseResult extends ContainerParseResult { + + public DictionaryParseResult stream_dictionary = null; + + public int stream_start_index = -1; +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/TrailerParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/TrailerParseResult.java new file mode 100644 index 0000000..d958cdb --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/TrailerParseResult.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: TrailerParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The ParseResult of parsing the trailer. + * + * @author wprinz + */ +public class TrailerParseResult extends ParseResult { + + public int contents_index = -1; + public int contents_end_index = -1; + + public DictionaryParseResult dpr = null; + + public IndirectObjectReferenceParseResult info; + + public IndirectObjectReferenceParseResult root; + + /** + * The content of the "/Size" entry. + */ + public int size; + + /** + * Tells, if this PDF footer has a predecessor (as specified by + * the /Prev entry). + */ + public boolean has_predecessor = false; + + /** + * The index of the predecessor. + * + *

+ * Only valid if has_predecessor is true. + *

+ *

+ * Use getPrev and setPrev to access this member variable. + *

+ * + * @see #getPrev() + * @see #setPrev(int) + */ + private int prev = -1; + + public int getPrev() { + assert has_predecessor; + return prev; + } + + public void setPrev(int prev) { + assert has_predecessor : "Set has_predecessor to true first."; + this.prev = prev; + } + + + + + +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefLineParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefLineParseResult.java new file mode 100644 index 0000000..e04e88d --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefLineParseResult.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: XRefLineParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The ParseResult of parsing a single xref line. + * + * @author wprinz + */ +public class XRefLineParseResult extends ParseResult { + + public int object_offset; + + public int generation_number; + + public byte object_usage; +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSectionParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSectionParseResult.java new file mode 100644 index 0000000..8b2858c --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSectionParseResult.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: XRefSectionParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +import java.util.ArrayList; +import java.util.List; + +/** + * The ParseResult of an xref parsing operation. + * + *

+ * This contains one whole xref table section. An xref section starts with the + * word xref and contains one or more xref sub-sections. + *

+ *

+ * Due to Incremental Updates, there may be more than one xref section in a + * document. All xref section together are called the xref table. Using this + * aggregated xref table, an application has the full access to all indirect + * objects in the document. + *

+ *

+ * In many PDF libraries and applications one xref section is also informally + * called xref table. + *

+ * + * @author wprinz + */ +public class XRefSectionParseResult extends ParseResult +{ + + public List xref_subsections = new ArrayList(); + + /** + * Appends another cross-reference (xref) sub-section to the xref table. + * + * @param xref_section + * The xref section to be appended. + */ + public void appendXRefSubSection(XRefSubSectionParseResult xref_section) + { + xref_subsections.add(xref_section); + } +} diff --git a/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSubSectionParseResult.java b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSubSectionParseResult.java new file mode 100644 index 0000000..41982c4 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSubSectionParseResult.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * 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: XRefSubSectionParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +import java.util.ArrayList; +import java.util.List; + +/** + * Contains an xref sub-section. + * + *

+ * An xref sub-section is an ordered list of xref lines. The object numbers of the + * corresponding objects are numbered incrementally. + *

+ *

+ * xref sections are important in Incremental Updates because they allow to + * specify explicitely which objects (object numbers) are contained in the xref. + *

+ * + * @author wprinz + */ +public class XRefSubSectionParseResult extends ParseResult { + + public int start_obj_number; + + public int num_objects; + + public List xref_lines = new ArrayList(); + + public void appendXRefLine(XRefLineParseResult xref_line) { + assert xref_lines.size() < num_objects; + + xref_lines.add(xref_line); + } + +} -- cgit v1.2.3