You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by gb...@apache.org on 2013/03/06 17:46:37 UTC
svn commit: r1453416 [12/16] - in /pdfbox/trunk/preflight: ./
src/main/java/org/apache/pdfbox/preflight/
src/main/java/org/apache/pdfbox/preflight/action/
src/main/java/org/apache/pdfbox/preflight/annotation/
src/main/java/org/apache/pdfbox/preflight/a...
Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/CatalogValidationProcess.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/CatalogValidationProcess.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/CatalogValidationProcess.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/CatalogValidationProcess.java Wed Mar 6 16:46:35 2013
@@ -121,307 +121,345 @@ import org.apache.pdfbox.preflight.utils
/**
* This ValidationProcess check if the Catalog entries are confirming with the PDF/A-1b specification.
*/
-public class CatalogValidationProcess extends AbstractProcess {
+public class CatalogValidationProcess extends AbstractProcess
+{
- protected PDDocumentCatalog catalog;
+ protected PDDocumentCatalog catalog;
- protected List<String> listICC = new ArrayList<String>();
+ protected List<String> listICC = new ArrayList<String>();
- public CatalogValidationProcess() {
- listICC.add(ICC_Characterization_Data_Registry_FOGRA43);
- listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_006);
- listICC.add(ICC_Characterization_Data_Registry_CGATS_TR006);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA39);
- listICC.add(ICC_Characterization_Data_Registry_JC200103);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA27);
- listICC.add(ICC_Characterization_Data_Registry_EUROSB104);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA45);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA46);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA41);
- listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_001);
- listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_003);
- listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_005);
- listICC.add(ICC_Characterization_Data_Registry_CGATS_TR001);
- listICC.add(ICC_Characterization_Data_Registry_CGATS_TR003);
- listICC.add(ICC_Characterization_Data_Registry_CGATS_TR005);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA28);
- listICC.add(ICC_Characterization_Data_Registry_JCW2003);
- listICC.add(ICC_Characterization_Data_Registry_EUROSB204);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA47);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA44);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA29);
- listICC.add(ICC_Characterization_Data_Registry_JC200104);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA40);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA30);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA42);
- listICC.add(ICC_Characterization_Data_Registry_IFRA26);
- listICC.add(ICC_Characterization_Data_Registry_JCN2002);
- listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_002);
- listICC.add(ICC_Characterization_Data_Registry_CGATS_TR002);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA33);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA37);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA31);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA35);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA32);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA34);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA36);
- listICC.add(ICC_Characterization_Data_Registry_FOGRA38);
- listICC.add(ICC_Characterization_Data_Registry_sRGB);
- listICC.add(ICC_Characterization_Data_Registry_sRGB_IEC);
- listICC.add(ICC_Characterization_Data_Registry_Adobe);
- listICC.add(ICC_Characterization_Data_Registry_bg_sRGB);
- listICC.add(ICC_Characterization_Data_Registry_sYCC);
- listICC.add(ICC_Characterization_Data_Registry_scRGB);
- listICC.add(ICC_Characterization_Data_Registry_scRGB_nl);
- listICC.add(ICC_Characterization_Data_Registry_scYCC_nl);
- listICC.add(ICC_Characterization_Data_Registry_ROMM);
- listICC.add(ICC_Characterization_Data_Registry_RIMM);
- listICC.add(ICC_Characterization_Data_Registry_ERIMM);
- listICC.add(ICC_Characterization_Data_Registry_eciRGB);
- listICC.add(ICC_Characterization_Data_Registry_opRGB);
- }
-
- protected boolean isStandardICCCharacterization(String name) {
- for (String iccStandard : listICC) {
- if (iccStandard.contains(name)) {
- return true;
- }
- }
- return false;
- }
-
- public void validate(PreflightContext ctx) throws ValidationException {
- PDDocument pdfbox = ctx.getDocument();
- this.catalog = pdfbox.getDocumentCatalog();
-
- if (this.catalog == null) {
- new ValidationError(ERROR_SYNTAX_NOCATALOG, "There are no Catalog entry in the Document.");
- throw new ValidationException("There are no Catalog entry in the Document.");
- }
-
- validateActions(ctx);
- validateLang(ctx);
- validateNames(ctx);
- validateOCProperties(ctx);
- validateOutputIntent(ctx);
- }
-
- /**
- * This method validates if OpenAction entry contains forbidden action type.
- * It checks too if an Additional Action is present.
- *
- * @param ctx
- * @throws ValidationException Propagate the ActionManager exception
- */
- protected void validateActions(PreflightContext ctx) throws ValidationException {
- ContextHelper.validateElement(ctx, catalog.getCOSDictionary(), ACTIONS_PROCESS);
- // AA entry if forbidden in PDF/A-1
- COSBase aa = catalog.getCOSDictionary().getItem(DICTIONARY_KEY_ADDITIONAL_ACTION);
- if (aa != null) {
- addValidationError(ctx, new ValidationError(ERROR_ACTION_FORBIDDEN_ADDITIONAL_ACTION, "The AA field is forbidden for the Catalog when the PDF is a PDF/A"));
- }
- }
-
- /**
- * The Lang element is optional but it is recommended. This method check the
- * Syntax of the Lang if this entry is present.
- *
- * @param ctx
- * @throws ValidationException
- */
- protected void validateLang(PreflightContext ctx) throws ValidationException {
- String lang = catalog.getLanguage();
- if (lang != null && !"".equals(lang) && !lang.matches("[A-Za-z]{1,8}(-[A-Za-z]{1,8})*")) {
- addValidationError(ctx, new ValidationError(ERROR_SYNTAX_LANG_NOT_RFC1766));
- }
- }
-
- /**
- * A Catalog shall not contain the EmbeddedFiles entry.
- *
- * @param ctx
- * @throws ValidationException
- */
- protected void validateNames(PreflightContext ctx) throws ValidationException {
- PDDocumentNameDictionary names = catalog.getNames();
- if (names != null) {
- PDEmbeddedFilesNameTreeNode efs = names.getEmbeddedFiles();
- if (efs != null) {
- addValidationError(ctx,
- new ValidationError(ERROR_SYNTAX_TRAILER_CATALOG_EMBEDDEDFILES,
- "EmbeddedFile entry is present in the Names dictionary"));
- }
- }
- }
-
- /**
- * A Catalog shall not contain the OCPProperties (Optional Content Properties) entry.
- *
- * @param ctx
- * @throws ValidationException
- */
- protected void validateOCProperties(PreflightContext ctx) throws ValidationException {
- if (catalog.getOCProperties() != null) {
- addValidationError(ctx,
- new ValidationError(ERROR_SYNTAX_TRAILER_CATALOG_OCPROPERTIES,
- "A Catalog shall not contain the OCPProperties entry."));
- }
- }
-
- /**
- * This method checks the content of each OutputIntent. The S entry must
- * contain GTS_PDFA1. The DestOuputProfile must contain a valid ICC Profile
- * Stream.
- *
- * If there are more than one OutputIntent, they have to use the same ICC
- * Profile.
- *
- * This method returns a list of ValidationError. It is empty if no errors
- * have been found.
- *
- * @param ctx
- * @throws ValidationException
- */
- public void validateOutputIntent(PreflightContext ctx) throws ValidationException {
- COSDocument cosDocument = ctx.getDocument().getDocument();
- COSBase cBase = catalog.getCOSDictionary().getItem(COSName.getPDFName(DOCUMENT_DICTIONARY_KEY_OUTPUT_INTENTS));
- COSArray outputIntents = COSUtils.getAsArray(cBase, cosDocument);
-
- Map<COSObjectKey, Boolean> tmpDestOutputProfile = new HashMap<COSObjectKey, Boolean>();
- for (int i = 0; outputIntents != null && i < outputIntents.size(); ++i) {
- COSDictionary outputIntentDict = COSUtils.getAsDictionary(outputIntents.get(i), cosDocument);
-
- if (outputIntentDict == null) {
- addValidationError(ctx,
- new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY,
- "OutputIntent object is null or isn't a dictionary"));
- } else {
- // S entry is mandatory and must be equals to GTS_PDFA1
- String sValue = outputIntentDict.getNameAsString(OUTPUT_INTENT_DICTIONARY_KEY_S);
- if (!OUTPUT_INTENT_DICTIONARY_VALUE_GTS_PDFA1.equals(sValue)) {
- addValidationError(ctx,
- new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_S_VALUE_INVALID,
- "The S entry of the OutputIntent isn't GTS_PDFA1"));
- continue;
- }
-
- // OutputConditionIdentifier is a mandatory field
- String outputConditionIdentifier = outputIntentDict.getString(OUTPUT_INTENT_DICTIONARY_KEY_OUTPUT_CONDITION_IDENTIFIER);
- if (outputConditionIdentifier == null) {// empty string is authorized (it may be an application specific value)
- addValidationError(ctx,
- new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY,
- "The OutputIntentCondition is missing"));
- continue;
- }
-
-
- /* If OutputConditionIdentifier is "Custom" or a non Standard ICC Characterization :
- * DestOutputProfile and Info are mandatory
- * DestOutputProfile must be a ICC Profile
- *
- * Because of PDF/A conforming file needs to specify the color characteristics, the DestOutputProfile
- * is checked even if the OutputConditionIdentifier isn't "Custom"
- */
- COSBase destOutputProfile = outputIntentDict.getItem(OUTPUT_INTENT_DICTIONARY_KEY_DEST_OUTPUT_PROFILE);
- validateICCProfile(destOutputProfile, tmpDestOutputProfile, ctx);
-
- PreflightConfiguration config = ctx.getConfig();
- if (config.isLazyValidation() && !isStandardICCCharacterization(outputConditionIdentifier)) {
- String info = outputIntentDict.getString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_INFO));
- if (info == null || "".equals(info)) {
- ValidationError error = new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, "The Info entry of a OutputIntent dictionary is missing");
- error.setWarning(true);
- addValidationError(ctx, error);
- continue;
- }
- }
- }
- }
- }
-
-
- /**
- * This method checks the destOutputProfile which must be a valid ICCProfile.
- *
- * If an other ICCProfile exists in the mapDestOutputProfile, a
- * ValdiationError (ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_MULTIPLE) is
- * returned because of only one profile is authorized. If the ICCProfile
- * already exist in the mapDestOutputProfile, the method returns null. If the
- * destOutputProfile contains an invalid ICCProfile, a ValidationError
- * (ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_INVALID) is returned If the
- * destOutputProfile is an empty stream, a
- * ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY) is returned.
- *
- * If the destOutputFile is valid, mapDestOutputProfile is updated, the
- * ICCProfile is added to the document ctx and null is returned.
- *
- * @param destOutputProfile
- * @param tmpDestOutputProfile
- * @param ctx
- * @return
- * @throws ValidationException
- */
- protected void validateICCProfile(COSBase destOutputProfile, Map<COSObjectKey, Boolean> mapDestOutputProfile,
- PreflightContext ctx) throws ValidationException {
- try {
- if (destOutputProfile == null) {
- return ;
- }
-
- // destOutputProfile should be an instance of COSObject because of this is a object reference
- if (destOutputProfile instanceof COSObject) {
- if (mapDestOutputProfile.containsKey(new COSObjectKey((COSObject) destOutputProfile))) {
- // the profile is already checked. continue
- return ;
- } else if (!mapDestOutputProfile.isEmpty()) {
- // A DestOutputProfile exits but it isn't the same, error
- addValidationError(ctx, new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_MULTIPLE, "More than one ICCProfile is defined"));
- return;
- }
- // else the profile will be kept in the tmpDestOutputProfile if it is valid
- }
-
- // keep reference to avoid multiple profile definition
- mapDestOutputProfile.put(new COSObjectKey((COSObject) destOutputProfile), true);
- COSDocument cosDocument = ctx.getDocument().getDocument();
- PDStream stream = PDStream.createFromCOS(COSUtils.getAsStream(destOutputProfile, cosDocument));
- if (stream == null) {
- addValidationError(ctx, new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY, "OutputIntent object uses a NULL Object"));
- return;
- }
-
- ICC_Profile iccp = ICC_Profile.getInstance(stream.getByteArray());
- PreflightConfiguration config = ctx.getConfig();
- // check the ICC Profile version (6.2.2)
- if (iccp.getMajorVersion() == 2) {
- if (iccp.getMinorVersion() > 0x40) {
- // in PDF 1.4, max version is 02h.40h (meaning V 3.5)
- // see the ICCProfile specification (ICC.1:1998-09)page 13 - §6.1.3 :
- // The current profile version number is "2.4.0" (encoded as 02400000h")
- ValidationError error = new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_TOO_RECENT, "Invalid version of the ICCProfile");
- error.setWarning(config.isLazyValidation());
- addValidationError(ctx, error);
- return ;
- } // else OK
- } else if (iccp.getMajorVersion() > 2) {
- // in PDF 1.4, max version is 02h.40h (meaning V 3.5)
- // see the ICCProfile specification (ICC.1:1998-09)page 13 - §6.1.3 :
- // The current profile version number is "2.4.0" (encoded as 02400000h"
- ValidationError error = new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_TOO_RECENT, "Invalid version of the ICCProfile");
- error.setWarning(config.isLazyValidation());
- addValidationError(ctx, error);
- return ;
- } // else seems less than 2, so correct
-
- if (ctx.getIccProfileWrapper() == null) {
- ctx.setIccProfileWrapper(new ICCProfileWrapper(iccp));
- }
-
- } catch (IllegalArgumentException e) {
- // this is not a ICC_Profile
- addValidationError(ctx, new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_INVALID, "DestOutputProfile isn't a ICCProfile"));
- } catch (IOException e) {
- throw new ValidationException("Unable to parse the ICC Profile", e);
- }
- }
+ public CatalogValidationProcess()
+ {
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA43);
+ listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_006);
+ listICC.add(ICC_Characterization_Data_Registry_CGATS_TR006);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA39);
+ listICC.add(ICC_Characterization_Data_Registry_JC200103);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA27);
+ listICC.add(ICC_Characterization_Data_Registry_EUROSB104);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA45);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA46);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA41);
+ listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_001);
+ listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_003);
+ listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_005);
+ listICC.add(ICC_Characterization_Data_Registry_CGATS_TR001);
+ listICC.add(ICC_Characterization_Data_Registry_CGATS_TR003);
+ listICC.add(ICC_Characterization_Data_Registry_CGATS_TR005);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA28);
+ listICC.add(ICC_Characterization_Data_Registry_JCW2003);
+ listICC.add(ICC_Characterization_Data_Registry_EUROSB204);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA47);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA44);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA29);
+ listICC.add(ICC_Characterization_Data_Registry_JC200104);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA40);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA30);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA42);
+ listICC.add(ICC_Characterization_Data_Registry_IFRA26);
+ listICC.add(ICC_Characterization_Data_Registry_JCN2002);
+ listICC.add(ICC_Characterization_Data_Registry_CGATS_TR_002);
+ listICC.add(ICC_Characterization_Data_Registry_CGATS_TR002);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA33);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA37);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA31);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA35);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA32);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA34);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA36);
+ listICC.add(ICC_Characterization_Data_Registry_FOGRA38);
+ listICC.add(ICC_Characterization_Data_Registry_sRGB);
+ listICC.add(ICC_Characterization_Data_Registry_sRGB_IEC);
+ listICC.add(ICC_Characterization_Data_Registry_Adobe);
+ listICC.add(ICC_Characterization_Data_Registry_bg_sRGB);
+ listICC.add(ICC_Characterization_Data_Registry_sYCC);
+ listICC.add(ICC_Characterization_Data_Registry_scRGB);
+ listICC.add(ICC_Characterization_Data_Registry_scRGB_nl);
+ listICC.add(ICC_Characterization_Data_Registry_scYCC_nl);
+ listICC.add(ICC_Characterization_Data_Registry_ROMM);
+ listICC.add(ICC_Characterization_Data_Registry_RIMM);
+ listICC.add(ICC_Characterization_Data_Registry_ERIMM);
+ listICC.add(ICC_Characterization_Data_Registry_eciRGB);
+ listICC.add(ICC_Characterization_Data_Registry_opRGB);
+ }
+
+ protected boolean isStandardICCCharacterization(String name)
+ {
+ for (String iccStandard : listICC)
+ {
+ if (iccStandard.contains(name))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void validate(PreflightContext ctx) throws ValidationException
+ {
+ PDDocument pdfbox = ctx.getDocument();
+ this.catalog = pdfbox.getDocumentCatalog();
+
+ if (this.catalog == null)
+ {
+ new ValidationError(ERROR_SYNTAX_NOCATALOG, "There are no Catalog entry in the Document.");
+ throw new ValidationException("There are no Catalog entry in the Document.");
+ }
+
+ validateActions(ctx);
+ validateLang(ctx);
+ validateNames(ctx);
+ validateOCProperties(ctx);
+ validateOutputIntent(ctx);
+ }
+
+ /**
+ * This method validates if OpenAction entry contains forbidden action type. It checks too if an Additional Action
+ * is present.
+ *
+ * @param ctx
+ * @throws ValidationException
+ * Propagate the ActionManager exception
+ */
+ protected void validateActions(PreflightContext ctx) throws ValidationException
+ {
+ ContextHelper.validateElement(ctx, catalog.getCOSDictionary(), ACTIONS_PROCESS);
+ // AA entry if forbidden in PDF/A-1
+ COSBase aa = catalog.getCOSDictionary().getItem(DICTIONARY_KEY_ADDITIONAL_ACTION);
+ if (aa != null)
+ {
+ addValidationError(ctx, new ValidationError(ERROR_ACTION_FORBIDDEN_ADDITIONAL_ACTION,
+ "The AA field is forbidden for the Catalog when the PDF is a PDF/A"));
+ }
+ }
+
+ /**
+ * The Lang element is optional but it is recommended. This method check the Syntax of the Lang if this entry is
+ * present.
+ *
+ * @param ctx
+ * @throws ValidationException
+ */
+ protected void validateLang(PreflightContext ctx) throws ValidationException
+ {
+ String lang = catalog.getLanguage();
+ if (lang != null && !"".equals(lang) && !lang.matches("[A-Za-z]{1,8}(-[A-Za-z]{1,8})*"))
+ {
+ addValidationError(ctx, new ValidationError(ERROR_SYNTAX_LANG_NOT_RFC1766));
+ }
+ }
+
+ /**
+ * A Catalog shall not contain the EmbeddedFiles entry.
+ *
+ * @param ctx
+ * @throws ValidationException
+ */
+ protected void validateNames(PreflightContext ctx) throws ValidationException
+ {
+ PDDocumentNameDictionary names = catalog.getNames();
+ if (names != null)
+ {
+ PDEmbeddedFilesNameTreeNode efs = names.getEmbeddedFiles();
+ if (efs != null)
+ {
+ addValidationError(ctx, new ValidationError(ERROR_SYNTAX_TRAILER_CATALOG_EMBEDDEDFILES,
+ "EmbeddedFile entry is present in the Names dictionary"));
+ }
+ }
+ }
+
+ /**
+ * A Catalog shall not contain the OCPProperties (Optional Content Properties) entry.
+ *
+ * @param ctx
+ * @throws ValidationException
+ */
+ protected void validateOCProperties(PreflightContext ctx) throws ValidationException
+ {
+ if (catalog.getOCProperties() != null)
+ {
+ addValidationError(ctx, new ValidationError(ERROR_SYNTAX_TRAILER_CATALOG_OCPROPERTIES,
+ "A Catalog shall not contain the OCPProperties entry."));
+ }
+ }
+
+ /**
+ * This method checks the content of each OutputIntent. The S entry must contain GTS_PDFA1. The DestOuputProfile
+ * must contain a valid ICC Profile Stream.
+ *
+ * If there are more than one OutputIntent, they have to use the same ICC Profile.
+ *
+ * This method returns a list of ValidationError. It is empty if no errors have been found.
+ *
+ * @param ctx
+ * @throws ValidationException
+ */
+ public void validateOutputIntent(PreflightContext ctx) throws ValidationException
+ {
+ COSDocument cosDocument = ctx.getDocument().getDocument();
+ COSBase cBase = catalog.getCOSDictionary().getItem(COSName.getPDFName(DOCUMENT_DICTIONARY_KEY_OUTPUT_INTENTS));
+ COSArray outputIntents = COSUtils.getAsArray(cBase, cosDocument);
+
+ Map<COSObjectKey, Boolean> tmpDestOutputProfile = new HashMap<COSObjectKey, Boolean>();
+ for (int i = 0; outputIntents != null && i < outputIntents.size(); ++i)
+ {
+ COSDictionary outputIntentDict = COSUtils.getAsDictionary(outputIntents.get(i), cosDocument);
+
+ if (outputIntentDict == null)
+ {
+ addValidationError(ctx, new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY,
+ "OutputIntent object is null or isn't a dictionary"));
+ }
+ else
+ {
+ // S entry is mandatory and must be equals to GTS_PDFA1
+ String sValue = outputIntentDict.getNameAsString(OUTPUT_INTENT_DICTIONARY_KEY_S);
+ if (!OUTPUT_INTENT_DICTIONARY_VALUE_GTS_PDFA1.equals(sValue))
+ {
+ addValidationError(ctx, new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_S_VALUE_INVALID,
+ "The S entry of the OutputIntent isn't GTS_PDFA1"));
+ continue;
+ }
+
+ // OutputConditionIdentifier is a mandatory field
+ String outputConditionIdentifier = outputIntentDict
+ .getString(OUTPUT_INTENT_DICTIONARY_KEY_OUTPUT_CONDITION_IDENTIFIER);
+ if (outputConditionIdentifier == null)
+ {// empty string is authorized (it may be an application specific value)
+ addValidationError(ctx, new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY,
+ "The OutputIntentCondition is missing"));
+ continue;
+ }
+
+ /*
+ * If OutputConditionIdentifier is "Custom" or a non Standard ICC Characterization : DestOutputProfile
+ * and Info are mandatory DestOutputProfile must be a ICC Profile
+ *
+ * Because of PDF/A conforming file needs to specify the color characteristics, the DestOutputProfile is
+ * checked even if the OutputConditionIdentifier isn't "Custom"
+ */
+ COSBase destOutputProfile = outputIntentDict.getItem(OUTPUT_INTENT_DICTIONARY_KEY_DEST_OUTPUT_PROFILE);
+ validateICCProfile(destOutputProfile, tmpDestOutputProfile, ctx);
+
+ PreflightConfiguration config = ctx.getConfig();
+ if (config.isLazyValidation() && !isStandardICCCharacterization(outputConditionIdentifier))
+ {
+ String info = outputIntentDict.getString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_INFO));
+ if (info == null || "".equals(info))
+ {
+ ValidationError error = new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY,
+ "The Info entry of a OutputIntent dictionary is missing");
+ error.setWarning(true);
+ addValidationError(ctx, error);
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * This method checks the destOutputProfile which must be a valid ICCProfile.
+ *
+ * If an other ICCProfile exists in the mapDestOutputProfile, a ValdiationError
+ * (ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_MULTIPLE) is returned because of only one profile is authorized. If the
+ * ICCProfile already exist in the mapDestOutputProfile, the method returns null. If the destOutputProfile contains
+ * an invalid ICCProfile, a ValidationError (ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_INVALID) is returned If the
+ * destOutputProfile is an empty stream, a ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY) is returned.
+ *
+ * If the destOutputFile is valid, mapDestOutputProfile is updated, the ICCProfile is added to the document ctx and
+ * null is returned.
+ *
+ * @param destOutputProfile
+ * @param tmpDestOutputProfile
+ * @param ctx
+ * @return
+ * @throws ValidationException
+ */
+ protected void validateICCProfile(COSBase destOutputProfile, Map<COSObjectKey, Boolean> mapDestOutputProfile,
+ PreflightContext ctx) throws ValidationException
+ {
+ try
+ {
+ if (destOutputProfile == null)
+ {
+ return;
+ }
+
+ // destOutputProfile should be an instance of COSObject because of this is a object reference
+ if (destOutputProfile instanceof COSObject)
+ {
+ if (mapDestOutputProfile.containsKey(new COSObjectKey((COSObject) destOutputProfile)))
+ {
+ // the profile is already checked. continue
+ return;
+ }
+ else if (!mapDestOutputProfile.isEmpty())
+ {
+ // A DestOutputProfile exits but it isn't the same, error
+ addValidationError(ctx, new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_MULTIPLE,
+ "More than one ICCProfile is defined"));
+ return;
+ }
+ // else the profile will be kept in the tmpDestOutputProfile if it is valid
+ }
+
+ // keep reference to avoid multiple profile definition
+ mapDestOutputProfile.put(new COSObjectKey((COSObject) destOutputProfile), true);
+ COSDocument cosDocument = ctx.getDocument().getDocument();
+ PDStream stream = PDStream.createFromCOS(COSUtils.getAsStream(destOutputProfile, cosDocument));
+ if (stream == null)
+ {
+ addValidationError(ctx, new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY,
+ "OutputIntent object uses a NULL Object"));
+ return;
+ }
+
+ ICC_Profile iccp = ICC_Profile.getInstance(stream.getByteArray());
+ PreflightConfiguration config = ctx.getConfig();
+ // check the ICC Profile version (6.2.2)
+ if (iccp.getMajorVersion() == 2)
+ {
+ if (iccp.getMinorVersion() > 0x40)
+ {
+ // in PDF 1.4, max version is 02h.40h (meaning V 3.5)
+ // see the ICCProfile specification (ICC.1:1998-09)page 13 - §6.1.3 :
+ // The current profile version number is "2.4.0" (encoded as 02400000h")
+ ValidationError error = new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_TOO_RECENT,
+ "Invalid version of the ICCProfile");
+ error.setWarning(config.isLazyValidation());
+ addValidationError(ctx, error);
+ return;
+ } // else OK
+ }
+ else if (iccp.getMajorVersion() > 2)
+ {
+ // in PDF 1.4, max version is 02h.40h (meaning V 3.5)
+ // see the ICCProfile specification (ICC.1:1998-09)page 13 - §6.1.3 :
+ // The current profile version number is "2.4.0" (encoded as 02400000h"
+ ValidationError error = new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_TOO_RECENT,
+ "Invalid version of the ICCProfile");
+ error.setWarning(config.isLazyValidation());
+ addValidationError(ctx, error);
+ return;
+ } // else seems less than 2, so correct
+
+ if (ctx.getIccProfileWrapper() == null)
+ {
+ ctx.setIccProfileWrapper(new ICCProfileWrapper(iccp));
+ }
+
+ }
+ catch (IllegalArgumentException e)
+ {
+ // this is not a ICC_Profile
+ addValidationError(ctx, new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_ICC_PROFILE_INVALID,
+ "DestOutputProfile isn't a ICCProfile"));
+ }
+ catch (IOException e)
+ {
+ throw new ValidationException("Unable to parse the ICC Profile", e);
+ }
+ }
}
Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/EmptyValidationProcess.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/EmptyValidationProcess.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/EmptyValidationProcess.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/EmptyValidationProcess.java Wed Mar 6 16:46:35 2013
@@ -25,14 +25,15 @@ import org.apache.pdfbox.preflight.Prefl
import org.apache.pdfbox.preflight.exception.ValidationException;
/**
- * This class is used to return a non null ValidationProcess when a missing process is asked
- * to the ConfigurationBean only if the errorOnMissingProcess configuration attribute is set to false.
- *
+ * This class is used to return a non null ValidationProcess when a missing process is asked to the ConfigurationBean
+ * only if the errorOnMissingProcess configuration attribute is set to false.
+ *
*/
-public class EmptyValidationProcess implements ValidationProcess {
-
- public void validate(PreflightContext context)
- throws ValidationException {
- // this class does nothing
- }
+public class EmptyValidationProcess implements ValidationProcess
+{
+
+ public void validate(PreflightContext context) throws ValidationException
+ {
+ // this class does nothing
+ }
}
Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/FileSpecificationValidationProcess.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/FileSpecificationValidationProcess.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/FileSpecificationValidationProcess.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/FileSpecificationValidationProcess.java Wed Mar 6 16:46:35 2013
@@ -37,51 +37,57 @@ import org.apache.pdfbox.pdmodel.PDDocum
import org.apache.pdfbox.preflight.PreflightContext;
import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
import org.apache.pdfbox.preflight.exception.ValidationException;
+
/**
*
* This validation process check that FileSpec dictionaries are confirming with the PDF/A-1b specification.
*/
-public class FileSpecificationValidationProcess extends AbstractProcess {
-
+public class FileSpecificationValidationProcess extends AbstractProcess
+{
- public void validate(PreflightContext ctx) throws ValidationException {
- PDDocument pdfDoc = ctx.getDocument();
- COSDocument cDoc = pdfDoc.getDocument();
-
- List<?> lCOSObj = cDoc.getObjects();
- for (Object o : lCOSObj) {
- COSBase cBase = ((COSObject) o).getObject();
- if (cBase instanceof COSDictionary) {
- COSDictionary dic = (COSDictionary) cBase;
- String type = dic.getNameAsString(COSName.TYPE);
- if (FILE_SPECIFICATION_VALUE_TYPE.equals(type)) {
- // ---- It is a file specification
- validateFileSpecification(ctx, dic);
- }
- }
- }
- }
-
-
- /**
- * Validate a FileSpec dictionary, a FileSpec dictionary mustn't have the EF
- * (EmbeddedFile) entry.
- *
- * @param ctx
- * The document handler
- * @param cObj
- * the FileSpec Dictionary
- * @return
- */
- public List<ValidationError> validateFileSpecification(PreflightContext ctx, COSDictionary fileSpec) {
- List<ValidationError> result = new ArrayList<ValidationError>(0);
-
- // ---- Check dictionary entries
- // ---- Only the EF entry is forbidden
- if (fileSpec.getItem(COSName.getPDFName(FILE_SPECIFICATION_KEY_EMBEDDED_FILE)) != null) {
- addValidationError(ctx, new ValidationError(ERROR_SYNTAX_EMBEDDED_FILES,"EmbeddedFile entry is present in a FileSpecification dictionary"));
- }
+ public void validate(PreflightContext ctx) throws ValidationException
+ {
+ PDDocument pdfDoc = ctx.getDocument();
+ COSDocument cDoc = pdfDoc.getDocument();
+
+ List<?> lCOSObj = cDoc.getObjects();
+ for (Object o : lCOSObj)
+ {
+ COSBase cBase = ((COSObject) o).getObject();
+ if (cBase instanceof COSDictionary)
+ {
+ COSDictionary dic = (COSDictionary) cBase;
+ String type = dic.getNameAsString(COSName.TYPE);
+ if (FILE_SPECIFICATION_VALUE_TYPE.equals(type))
+ {
+ // ---- It is a file specification
+ validateFileSpecification(ctx, dic);
+ }
+ }
+ }
+ }
+
+ /**
+ * Validate a FileSpec dictionary, a FileSpec dictionary mustn't have the EF (EmbeddedFile) entry.
+ *
+ * @param ctx
+ * The document handler
+ * @param cObj
+ * the FileSpec Dictionary
+ * @return
+ */
+ public List<ValidationError> validateFileSpecification(PreflightContext ctx, COSDictionary fileSpec)
+ {
+ List<ValidationError> result = new ArrayList<ValidationError>(0);
+
+ // ---- Check dictionary entries
+ // ---- Only the EF entry is forbidden
+ if (fileSpec.getItem(COSName.getPDFName(FILE_SPECIFICATION_KEY_EMBEDDED_FILE)) != null)
+ {
+ addValidationError(ctx, new ValidationError(ERROR_SYNTAX_EMBEDDED_FILES,
+ "EmbeddedFile entry is present in a FileSpecification dictionary"));
+ }
- return result;
- }
+ return result;
+ }
}
Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/MetadataValidationProcess.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/MetadataValidationProcess.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/MetadataValidationProcess.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/MetadataValidationProcess.java Wed Mar 6 16:46:35 2013
@@ -50,139 +50,159 @@ import org.apache.xmpbox.xml.DomXmpParse
import org.apache.xmpbox.xml.XmpParsingException;
import org.apache.xmpbox.xml.XmpParsingException.ErrorType;
+public class MetadataValidationProcess extends AbstractProcess
+{
-public class MetadataValidationProcess extends AbstractProcess {
-
-
- public void validate(PreflightContext ctx) throws ValidationException {
- try {
- PDDocument document = ctx.getDocument();
-
- byte[] tmp = getXpacket(document.getDocument());
- DomXmpParser builder;
- builder = new DomXmpParser();
- XMPMetadata metadata;
- metadata = builder.parse(tmp);
- ctx.setMetadata(metadata);
-
- // 6.7.5 no deprecated attribute in xpacket processing instruction
- if (metadata.getXpacketBytes() != null) {
- addValidationError(ctx, new ValidationError(
- PreflightConstants.ERROR_METADATA_XPACKET_DEPRECATED,
- "bytes attribute is forbidden"));
- }
- if (metadata.getXpacketEncoding() != null) {
- addValidationError(ctx, new ValidationError(
- PreflightConstants.ERROR_METADATA_XPACKET_DEPRECATED,
- "encoding attribute is forbidden"));
- }
-
- // Call metadata synchronization checking
- addValidationErrors(ctx, new SynchronizedMetaDataValidation()
- .validateMetadataSynchronization(document, metadata));
-
- // Call PDF/A Identifier checking
- addValidationErrors(ctx, new PDFAIdentificationValidation()
- .validatePDFAIdentifer(metadata));
-
- // Call rdf:about checking
- try {
- new RDFAboutAttributeConcordanceValidation().validateRDFAboutAttributes(metadata);
- } catch (DifferentRDFAboutException e) {
- addValidationError(ctx, new ValidationError(
- PreflightConstants.ERROR_METADATA_RDF_ABOUT_ATTRIBUTE_INEQUAL_VALUE, e
- .getMessage()));
- }
-
- } catch (XpacketParsingException e) {
- if (e.getError() != null) {
- addValidationError(ctx, e.getError());
- } else {
- addValidationError(ctx, new ValidationError(PreflightConstants.ERROR_METADATA_MAIN,
- "Unexpected error"));
- }
- } catch (XmpParsingException e) {
- if (e.getErrorType()==ErrorType.NoValueType) {
- addValidationError(ctx, new ValidationError(
- PreflightConstants.ERROR_METADATA_UNKNOWN_VALUETYPE, e
- .getMessage()));
- } else if (e.getErrorType()==ErrorType.RequiredProperty) {
- addValidationError(ctx, new ValidationError(
- PreflightConstants.ERROR_METADATA_PROPERTY_MISSING, e.getMessage()));
- } else if (e.getErrorType()==ErrorType.InvalidPrefix) {
- addValidationError(ctx, new ValidationError(
- PreflightConstants.ERROR_METADATA_ABSENT_DESCRIPTION_SCHEMA, e
- .getMessage()));
- } else if (e.getErrorType()==ErrorType.InvalidType) {
- addValidationError(ctx, new ValidationError(
- PreflightConstants.ERROR_METADATA_PROPERTY_UNKNOWN, e.getMessage()));
- } else if (e.getErrorType()==ErrorType.XpacketBadEnd) {
- throw new ValidationException("Unable to parse font metadata due to : "
- + e.getMessage(), e);
- } else if (e.getErrorType()==ErrorType.NoSchema) {
- addValidationError(ctx, new ValidationError(
- PreflightConstants.ERROR_METADATA_ABSENT_DESCRIPTION_SCHEMA, e
- .getMessage()));
- } else if (e.getErrorType()==ErrorType.InvalidPdfaSchema) {
- addValidationError(ctx, new ValidationError(
- PreflightConstants.ERROR_METADATA_WRONG_NS_URI, e.getMessage()));
- } else {
- addValidationError(ctx, new ValidationError(PreflightConstants.ERROR_METADATA_FORMAT, e
- .getMessage()));
- }
- } catch (IOException e) {
- throw new ValidationException("Failed while validating", e);
- }
- }
-
- /**
- * Return the xpacket from the dictionary's stream
- */
- public static byte[] getXpacket(COSDocument cdocument) throws IOException,
- XpacketParsingException {
- COSObject catalog = cdocument.getCatalog();
- COSBase cb = catalog.getDictionaryObject(COSName.METADATA);
- if (cb == null) {
- // missing Metadata Key in catalog
- ValidationError error = new ValidationError(
- PreflightConstants.ERROR_METADATA_FORMAT,
- "Missing Metadata Key in catalog");
- throw new XpacketParsingException("Failed while retrieving xpacket",
- error);
- }
- // no filter key
- COSDictionary metadataDictionnary = COSUtils.getAsDictionary(cb, cdocument);
- if (metadataDictionnary.getItem(COSName.FILTER) != null) {
- // should not be defined
- ValidationError error = new ValidationError(
- PreflightConstants.ERROR_SYNTAX_STREAM_INVALID_FILTER,
- "Filter specified in metadata dictionnary");
- throw new XpacketParsingException("Failed while retrieving xpacket",
- error);
- }
-
- PDStream stream = PDStream.createFromCOS(metadataDictionnary);
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- InputStream is = stream.createInputStream();
- IOUtils.copy(is, bos);
- is.close();
- bos.close();
- return bos.toByteArray();
- }
-
- /**
- * Check if metadata dictionary has no stream filter
- *
- * @param doc
- * @return
- */
- protected List<ValidationError> checkStreamFilterUsage(PDDocument doc) {
- List<ValidationError> ve = new ArrayList<ValidationError>();
- List<?> filters = doc.getDocumentCatalog().getMetadata().getFilters();
- if (filters != null && !filters.isEmpty()) {
- ve.add(new ValidationError(PreflightConstants.ERROR_METADATA_MAIN,
- "Using stream filter on metadata dictionary is forbidden"));
- }
- return ve;
- }
+ public void validate(PreflightContext ctx) throws ValidationException
+ {
+ try
+ {
+ PDDocument document = ctx.getDocument();
+
+ byte[] tmp = getXpacket(document.getDocument());
+ DomXmpParser builder;
+ builder = new DomXmpParser();
+ XMPMetadata metadata;
+ metadata = builder.parse(tmp);
+ ctx.setMetadata(metadata);
+
+ // 6.7.5 no deprecated attribute in xpacket processing instruction
+ if (metadata.getXpacketBytes() != null)
+ {
+ addValidationError(ctx, new ValidationError(PreflightConstants.ERROR_METADATA_XPACKET_DEPRECATED,
+ "bytes attribute is forbidden"));
+ }
+ if (metadata.getXpacketEncoding() != null)
+ {
+ addValidationError(ctx, new ValidationError(PreflightConstants.ERROR_METADATA_XPACKET_DEPRECATED,
+ "encoding attribute is forbidden"));
+ }
+
+ // Call metadata synchronization checking
+ addValidationErrors(ctx,
+ new SynchronizedMetaDataValidation().validateMetadataSynchronization(document, metadata));
+
+ // Call PDF/A Identifier checking
+ addValidationErrors(ctx, new PDFAIdentificationValidation().validatePDFAIdentifer(metadata));
+
+ // Call rdf:about checking
+ try
+ {
+ new RDFAboutAttributeConcordanceValidation().validateRDFAboutAttributes(metadata);
+ }
+ catch (DifferentRDFAboutException e)
+ {
+ addValidationError(ctx, new ValidationError(
+ PreflightConstants.ERROR_METADATA_RDF_ABOUT_ATTRIBUTE_INEQUAL_VALUE, e.getMessage()));
+ }
+
+ }
+ catch (XpacketParsingException e)
+ {
+ if (e.getError() != null)
+ {
+ addValidationError(ctx, e.getError());
+ }
+ else
+ {
+ addValidationError(ctx, new ValidationError(PreflightConstants.ERROR_METADATA_MAIN, "Unexpected error"));
+ }
+ }
+ catch (XmpParsingException e)
+ {
+ if (e.getErrorType() == ErrorType.NoValueType)
+ {
+ addValidationError(ctx,
+ new ValidationError(PreflightConstants.ERROR_METADATA_UNKNOWN_VALUETYPE, e.getMessage()));
+ }
+ else if (e.getErrorType() == ErrorType.RequiredProperty)
+ {
+ addValidationError(ctx,
+ new ValidationError(PreflightConstants.ERROR_METADATA_PROPERTY_MISSING, e.getMessage()));
+ }
+ else if (e.getErrorType() == ErrorType.InvalidPrefix)
+ {
+ addValidationError(ctx, new ValidationError(
+ PreflightConstants.ERROR_METADATA_ABSENT_DESCRIPTION_SCHEMA, e.getMessage()));
+ }
+ else if (e.getErrorType() == ErrorType.InvalidType)
+ {
+ addValidationError(ctx,
+ new ValidationError(PreflightConstants.ERROR_METADATA_PROPERTY_UNKNOWN, e.getMessage()));
+ }
+ else if (e.getErrorType() == ErrorType.XpacketBadEnd)
+ {
+ throw new ValidationException("Unable to parse font metadata due to : " + e.getMessage(), e);
+ }
+ else if (e.getErrorType() == ErrorType.NoSchema)
+ {
+ addValidationError(ctx, new ValidationError(
+ PreflightConstants.ERROR_METADATA_ABSENT_DESCRIPTION_SCHEMA, e.getMessage()));
+ }
+ else if (e.getErrorType() == ErrorType.InvalidPdfaSchema)
+ {
+ addValidationError(ctx,
+ new ValidationError(PreflightConstants.ERROR_METADATA_WRONG_NS_URI, e.getMessage()));
+ }
+ else
+ {
+ addValidationError(ctx, new ValidationError(PreflightConstants.ERROR_METADATA_FORMAT, e.getMessage()));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new ValidationException("Failed while validating", e);
+ }
+ }
+
+ /**
+ * Return the xpacket from the dictionary's stream
+ */
+ public static byte[] getXpacket(COSDocument cdocument) throws IOException, XpacketParsingException
+ {
+ COSObject catalog = cdocument.getCatalog();
+ COSBase cb = catalog.getDictionaryObject(COSName.METADATA);
+ if (cb == null)
+ {
+ // missing Metadata Key in catalog
+ ValidationError error = new ValidationError(PreflightConstants.ERROR_METADATA_FORMAT,
+ "Missing Metadata Key in catalog");
+ throw new XpacketParsingException("Failed while retrieving xpacket", error);
+ }
+ // no filter key
+ COSDictionary metadataDictionnary = COSUtils.getAsDictionary(cb, cdocument);
+ if (metadataDictionnary.getItem(COSName.FILTER) != null)
+ {
+ // should not be defined
+ ValidationError error = new ValidationError(PreflightConstants.ERROR_SYNTAX_STREAM_INVALID_FILTER,
+ "Filter specified in metadata dictionnary");
+ throw new XpacketParsingException("Failed while retrieving xpacket", error);
+ }
+
+ PDStream stream = PDStream.createFromCOS(metadataDictionnary);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ InputStream is = stream.createInputStream();
+ IOUtils.copy(is, bos);
+ is.close();
+ bos.close();
+ return bos.toByteArray();
+ }
+
+ /**
+ * Check if metadata dictionary has no stream filter
+ *
+ * @param doc
+ * @return
+ */
+ protected List<ValidationError> checkStreamFilterUsage(PDDocument doc)
+ {
+ List<ValidationError> ve = new ArrayList<ValidationError>();
+ List<?> filters = doc.getDocumentCatalog().getMetadata().getFilters();
+ if (filters != null && !filters.isEmpty())
+ {
+ ve.add(new ValidationError(PreflightConstants.ERROR_METADATA_MAIN,
+ "Using stream filter on metadata dictionary is forbidden"));
+ }
+ return ve;
+ }
}
Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/PageTreeValidationProcess.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/PageTreeValidationProcess.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/PageTreeValidationProcess.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/PageTreeValidationProcess.java Wed Mar 6 16:46:35 2013
@@ -31,21 +31,28 @@ import org.apache.pdfbox.preflight.Prefl
import org.apache.pdfbox.preflight.exception.ValidationException;
import org.apache.pdfbox.preflight.utils.ContextHelper;
-public class PageTreeValidationProcess extends AbstractProcess {
+public class PageTreeValidationProcess extends AbstractProcess
+{
- public void validate(PreflightContext context) throws ValidationException {
- PDDocumentCatalog catalog = context.getDocument().getDocumentCatalog();
- if (catalog != null) {
- List<?> pages = catalog.getAllPages();
- for (int i = 0; i < pages.size(); ++i) {
- validatePage(context,(PDPage) pages.get(i));
- }
- } else {
- throw new ValidationException("There are no Catalog entry in the Document.");
- }
- }
+ public void validate(PreflightContext context) throws ValidationException
+ {
+ PDDocumentCatalog catalog = context.getDocument().getDocumentCatalog();
+ if (catalog != null)
+ {
+ List<?> pages = catalog.getAllPages();
+ for (int i = 0; i < pages.size(); ++i)
+ {
+ validatePage(context, (PDPage) pages.get(i));
+ }
+ }
+ else
+ {
+ throw new ValidationException("There are no Catalog entry in the Document.");
+ }
+ }
- protected void validatePage(PreflightContext context, PDPage page) throws ValidationException {
- ContextHelper.validateElement(context, page, PAGE_PROCESS);
- }
+ protected void validatePage(PreflightContext context, PDPage page) throws ValidationException
+ {
+ ContextHelper.validateElement(context, page, PAGE_PROCESS);
+ }
}
Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/StreamValidationProcess.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/StreamValidationProcess.java?rev=1453416&r1=1453415&r2=1453416&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/StreamValidationProcess.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/process/StreamValidationProcess.java Wed Mar 6 16:46:35 2013
@@ -45,249 +45,314 @@ import org.apache.pdfbox.preflight.excep
import org.apache.pdfbox.preflight.utils.COSUtils;
import org.apache.pdfbox.preflight.utils.FilterHelper;
-public class StreamValidationProcess extends AbstractProcess {
+public class StreamValidationProcess extends AbstractProcess
+{
-
- public void validate(PreflightContext ctx) throws ValidationException {
- PDDocument pdfDoc = ctx.getDocument();
- COSDocument cDoc = pdfDoc.getDocument();
-
- List<?> lCOSObj = cDoc.getObjects();
- for (Object o : lCOSObj) {
- COSObject cObj = (COSObject) o;
- /*
- * If this object represents a Stream, the Dictionary must contain the Length key
- */
- COSBase cBase = cObj.getObject();
- if (cBase instanceof COSStream) {
- validateStreamObject(ctx, cObj);
- }
- }
- }
-
- public void validateStreamObject(PreflightContext context, COSObject cObj)
- throws ValidationException {
- COSStream streamObj = (COSStream) cObj.getObject();
-
- // ---- Check dictionary entries
- // ---- Only the Length entry is mandatory
- // ---- In a PDF/A file, F, FFilter and FDecodeParms are forbidden
- checkDictionaryEntries(context, streamObj);
- // ---- check stream length
- checkStreamLength(context, cObj);
- // ---- Check the Filter value(s)
- checkFilters(streamObj, context);
- }
-
- /**
- * This method checks if one of declared Filter is LZWdecode. If LZW is found,
- * the result list is updated with an error code.
- *
- * @param stream
- * @param handler
- * @param result
- */
- protected void checkFilters(COSStream stream, PreflightContext context) {
- COSBase bFilter = stream.getItem(COSName.FILTER);
- if (bFilter != null) {
- COSDocument cosDocument = context.getDocument().getDocument();
- if (COSUtils.isArray(bFilter, cosDocument)) {
- COSArray afName = (COSArray) bFilter;
- for (int i = 0; i < afName.size(); ++i) {
- FilterHelper.isAuthorizedFilter(context, afName.getString(i));
- }
- } else if (bFilter instanceof COSName) {
- String fName = ((COSName) bFilter).getName();
- FilterHelper.isAuthorizedFilter(context, fName);
- } else {
- // ---- The filter type is invalid
- addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_INVALID_FILTER, "Filter should be a Name or an Array"));
- }
- }
- // else Filter entry is optional
- }
-
- private boolean readUntilStream(InputStream ra) throws IOException {
- boolean search = true;
- // String stream = "";
- boolean maybe = false;
- int lastChar = -1;
- do {
- int c = ra.read();
- switch (c) {
- case 's':
- // stream = "s";
- maybe = true;
- lastChar = c;
- break;
- case 't':
- // if (maybe && stream.endsWith("s")) {
- if (maybe && lastChar == 's') {
- // stream = stream + "t";
- lastChar = c;
- } else {
- maybe = false;
- lastChar = -1;
- }
- break;
- case 'r':
- // if (maybe && stream.endsWith("t")) {
- if (maybe && lastChar == 't') {
- // stream = stream + "r";
- lastChar = c;
- } else {
- maybe = false;
- lastChar = -1;
- }
- break;
- case 'e':
- // if (maybe && stream.endsWith("r")) {
- if (maybe && lastChar == 'r') {
- lastChar = c;
- // stream = stream + "e";
- } else {
- maybe = false;
- }
- break;
- case 'a':
- // if (maybe && stream.endsWith("e")) {
- if (maybe && lastChar == 'e') {
- lastChar = c;
- // stream = stream + "a";
- } else {
- maybe = false;
- }
- break;
- case 'm':
- // if (maybe && stream.endsWith("a")) {
- if (maybe && lastChar == 'a') {
- return true;
- } else {
- maybe = false;
- }
- break;
- case -1:
- search = false;
- break;
- default:
- maybe = false;
- break;
- }
- } while (search);
- return false;
- }
-
- protected void checkStreamLength(PreflightContext context, COSObject cObj) throws ValidationException {
- COSStream streamObj = (COSStream) cObj.getObject();
- int length = streamObj.getInt(COSName.LENGTH);
- InputStream ra = null;
- try {
- ra = context.getSource().getInputStream();
- Long offset = context.getDocument().getDocument()
- .getXrefTable().get(new COSObjectKey(cObj));
-
- // ---- go to the beginning of the object
- long skipped = 0;
- if (offset != null) {
- while (skipped != offset) {
- long curSkip = ra.skip(offset - skipped);
- if (curSkip < 0) {
- throw new ValidationException(
- "Unable to skip bytes in the PDFFile to check stream length");
- }
- skipped += curSkip;
- }
-
- // ---- go to the stream key word
- if (readUntilStream(ra)) {
- int c = ra.read();
- if (c == '\r') {
- ra.read();
- } // else c is '\n' no more character to read
-
-
- // ---- Here is the true beginning of the Stream Content.
- // ---- Read the given length of bytes and check the 10 next bytes
- // ---- to see if there are endstream.
- byte[] buffer = new byte[1024];
- int nbBytesToRead = length;
-
- do {
- int cr = 0;
- if (nbBytesToRead > 1024) {
- cr = ra.read(buffer, 0, 1024);
- } else {
- cr = ra.read(buffer, 0, nbBytesToRead);
- }
- if (cr == -1) {
- addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID, "Stream length is invalide"));
- return;
- } else {
- nbBytesToRead = nbBytesToRead - cr;
- }
- } while (nbBytesToRead > 0);
-
- int len = "endstream".length() + 2;
- byte[] buffer2 = new byte[len];
- for (int i = 0; i < len; ++i) {
- buffer2[i] = (byte) ra.read();
- }
-
- // ---- check the content of 10 last characters
- String endStream = new String(buffer2);
- if (buffer2[0] == '\r' && buffer2[1] == '\n') {
- if (!endStream.contains("endstream")) {
- addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
- "Stream length is invalide"));
- }
- } else if (buffer2[0] == '\r' && buffer2[1] == 'e') {
- if (!endStream.contains("endstream")) {
- addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
- "Stream length is invalide"));
- }
- } else if (buffer2[0] == '\n' && buffer2[1] == 'e') {
- if (!endStream.contains("endstream")) {
- addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
- "Stream length is invalide"));
- }
- } else {
- addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
- "Stream length is invalide"));
- }
-
- } else {
- addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
- "Stream length is invalide"));
- }
- }
- } catch (IOException e) {
- throw new ValidationException("Unable to read a stream to validate it due to : " + e.getMessage(), e);
- } finally {
- if ( ra != null) {
- IOUtils.closeQuietly(ra);
- }
- }
- }
-
- /**
- * Check dictionary entries. Only the Length entry is mandatory. In a PDF/A
- * file, F, FFilter and FDecodeParms are forbidden
- *
- * @param streamObj
- * @param result
- */
- protected void checkDictionaryEntries(PreflightContext context, COSStream streamObj) {
- boolean len = streamObj.containsKey(COSName.LENGTH);
- boolean f = streamObj.containsKey(COSName.F);
- boolean ffilter = streamObj.containsKey(COSName.F_FILTER);
- boolean fdecParams = streamObj.containsKey(COSName.F_DECODE_PARMS);
-
- if (!len) {
- addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_MISSING, "Stream length is missing"));
- }
-
- if (f || ffilter || fdecParams) {
- addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_FX_KEYS, "F, FFilter or FDecodeParms keys are present in the stream dictionary"));
- }
- }
+ public void validate(PreflightContext ctx) throws ValidationException
+ {
+ PDDocument pdfDoc = ctx.getDocument();
+ COSDocument cDoc = pdfDoc.getDocument();
+
+ List<?> lCOSObj = cDoc.getObjects();
+ for (Object o : lCOSObj)
+ {
+ COSObject cObj = (COSObject) o;
+ /*
+ * If this object represents a Stream, the Dictionary must contain the Length key
+ */
+ COSBase cBase = cObj.getObject();
+ if (cBase instanceof COSStream)
+ {
+ validateStreamObject(ctx, cObj);
+ }
+ }
+ }
+
+ public void validateStreamObject(PreflightContext context, COSObject cObj) throws ValidationException
+ {
+ COSStream streamObj = (COSStream) cObj.getObject();
+
+ // ---- Check dictionary entries
+ // ---- Only the Length entry is mandatory
+ // ---- In a PDF/A file, F, FFilter and FDecodeParms are forbidden
+ checkDictionaryEntries(context, streamObj);
+ // ---- check stream length
+ checkStreamLength(context, cObj);
+ // ---- Check the Filter value(s)
+ checkFilters(streamObj, context);
+ }
+
+ /**
+ * This method checks if one of declared Filter is LZWdecode. If LZW is found, the result list is updated with an
+ * error code.
+ *
+ * @param stream
+ * @param handler
+ * @param result
+ */
+ protected void checkFilters(COSStream stream, PreflightContext context)
+ {
+ COSBase bFilter = stream.getItem(COSName.FILTER);
+ if (bFilter != null)
+ {
+ COSDocument cosDocument = context.getDocument().getDocument();
+ if (COSUtils.isArray(bFilter, cosDocument))
+ {
+ COSArray afName = (COSArray) bFilter;
+ for (int i = 0; i < afName.size(); ++i)
+ {
+ FilterHelper.isAuthorizedFilter(context, afName.getString(i));
+ }
+ }
+ else if (bFilter instanceof COSName)
+ {
+ String fName = ((COSName) bFilter).getName();
+ FilterHelper.isAuthorizedFilter(context, fName);
+ }
+ else
+ {
+ // ---- The filter type is invalid
+ addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_INVALID_FILTER,
+ "Filter should be a Name or an Array"));
+ }
+ }
+ // else Filter entry is optional
+ }
+
+ private boolean readUntilStream(InputStream ra) throws IOException
+ {
+ boolean search = true;
+ // String stream = "";
+ boolean maybe = false;
+ int lastChar = -1;
+ do
+ {
+ int c = ra.read();
+ switch (c)
+ {
+ case 's':
+ // stream = "s";
+ maybe = true;
+ lastChar = c;
+ break;
+ case 't':
+ // if (maybe && stream.endsWith("s")) {
+ if (maybe && lastChar == 's')
+ {
+ // stream = stream + "t";
+ lastChar = c;
+ }
+ else
+ {
+ maybe = false;
+ lastChar = -1;
+ }
+ break;
+ case 'r':
+ // if (maybe && stream.endsWith("t")) {
+ if (maybe && lastChar == 't')
+ {
+ // stream = stream + "r";
+ lastChar = c;
+ }
+ else
+ {
+ maybe = false;
+ lastChar = -1;
+ }
+ break;
+ case 'e':
+ // if (maybe && stream.endsWith("r")) {
+ if (maybe && lastChar == 'r')
+ {
+ lastChar = c;
+ // stream = stream + "e";
+ }
+ else
+ {
+ maybe = false;
+ }
+ break;
+ case 'a':
+ // if (maybe && stream.endsWith("e")) {
+ if (maybe && lastChar == 'e')
+ {
+ lastChar = c;
+ // stream = stream + "a";
+ }
+ else
+ {
+ maybe = false;
+ }
+ break;
+ case 'm':
+ // if (maybe && stream.endsWith("a")) {
+ if (maybe && lastChar == 'a')
+ {
+ return true;
+ }
+ else
+ {
+ maybe = false;
+ }
+ break;
+ case -1:
+ search = false;
+ break;
+ default:
+ maybe = false;
+ break;
+ }
+ } while (search);
+ return false;
+ }
+
+ protected void checkStreamLength(PreflightContext context, COSObject cObj) throws ValidationException
+ {
+ COSStream streamObj = (COSStream) cObj.getObject();
+ int length = streamObj.getInt(COSName.LENGTH);
+ InputStream ra = null;
+ try
+ {
+ ra = context.getSource().getInputStream();
+ Long offset = context.getDocument().getDocument().getXrefTable().get(new COSObjectKey(cObj));
+
+ // ---- go to the beginning of the object
+ long skipped = 0;
+ if (offset != null)
+ {
+ while (skipped != offset)
+ {
+ long curSkip = ra.skip(offset - skipped);
+ if (curSkip < 0)
+ {
+ throw new ValidationException("Unable to skip bytes in the PDFFile to check stream length");
+ }
+ skipped += curSkip;
+ }
+
+ // ---- go to the stream key word
+ if (readUntilStream(ra))
+ {
+ int c = ra.read();
+ if (c == '\r')
+ {
+ ra.read();
+ } // else c is '\n' no more character to read
+
+ // ---- Here is the true beginning of the Stream Content.
+ // ---- Read the given length of bytes and check the 10 next bytes
+ // ---- to see if there are endstream.
+ byte[] buffer = new byte[1024];
+ int nbBytesToRead = length;
+
+ do
+ {
+ int cr = 0;
+ if (nbBytesToRead > 1024)
+ {
+ cr = ra.read(buffer, 0, 1024);
+ }
+ else
+ {
+ cr = ra.read(buffer, 0, nbBytesToRead);
+ }
+ if (cr == -1)
+ {
+ addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
+ "Stream length is invalide"));
+ return;
+ }
+ else
+ {
+ nbBytesToRead = nbBytesToRead - cr;
+ }
+ } while (nbBytesToRead > 0);
+
+ int len = "endstream".length() + 2;
+ byte[] buffer2 = new byte[len];
+ for (int i = 0; i < len; ++i)
+ {
+ buffer2[i] = (byte) ra.read();
+ }
+
+ // ---- check the content of 10 last characters
+ String endStream = new String(buffer2);
+ if (buffer2[0] == '\r' && buffer2[1] == '\n')
+ {
+ if (!endStream.contains("endstream"))
+ {
+ addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
+ "Stream length is invalide"));
+ }
+ }
+ else if (buffer2[0] == '\r' && buffer2[1] == 'e')
+ {
+ if (!endStream.contains("endstream"))
+ {
+ addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
+ "Stream length is invalide"));
+ }
+ }
+ else if (buffer2[0] == '\n' && buffer2[1] == 'e')
+ {
+ if (!endStream.contains("endstream"))
+ {
+ addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
+ "Stream length is invalide"));
+ }
+ }
+ else
+ {
+ addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
+ "Stream length is invalide"));
+ }
+
+ }
+ else
+ {
+ addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_INVALID,
+ "Stream length is invalide"));
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ throw new ValidationException("Unable to read a stream to validate it due to : " + e.getMessage(), e);
+ }
+ finally
+ {
+ if (ra != null)
+ {
+ IOUtils.closeQuietly(ra);
+ }
+ }
+ }
+
+ /**
+ * Check dictionary entries. Only the Length entry is mandatory. In a PDF/A file, F, FFilter and FDecodeParms are
+ * forbidden
+ *
+ * @param streamObj
+ * @param result
+ */
+ protected void checkDictionaryEntries(PreflightContext context, COSStream streamObj)
+ {
+ boolean len = streamObj.containsKey(COSName.LENGTH);
+ boolean f = streamObj.containsKey(COSName.F);
+ boolean ffilter = streamObj.containsKey(COSName.F_FILTER);
+ boolean fdecParams = streamObj.containsKey(COSName.F_DECODE_PARMS);
+
+ if (!len)
+ {
+ addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_LENGTH_MISSING,
+ "Stream length is missing"));
+ }
+
+ if (f || ffilter || fdecParams)
+ {
+ addValidationError(context, new ValidationError(ERROR_SYNTAX_STREAM_FX_KEYS,
+ "F, FFilter or FDecodeParms keys are present in the stream dictionary"));
+ }
+ }
}