You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2011/07/24 16:02:33 UTC

svn commit: r1150373 [5/12] - in /pdfbox/trunk/preflight: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/padaf/ src/main/java/org/apache/padaf/preflight/ src/main/java/org/apache/padaf/preflight/a...

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/CompositeFontValidator.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/CompositeFontValidator.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/CompositeFontValidator.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/CompositeFontValidator.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,883 @@
+/*****************************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ ****************************************************************************/
+
+package org.apache.padaf.preflight.font;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.CFFParser;
+import org.apache.fontbox.cmap.CMap;
+import org.apache.fontbox.cmap.CMapParser;
+import org.apache.fontbox.ttf.CIDFontType2Parser;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.padaf.preflight.DocumentHandler;
+import org.apache.padaf.preflight.ValidationConstants;
+import org.apache.padaf.preflight.ValidationException;
+import org.apache.padaf.preflight.ValidationResult;
+import org.apache.padaf.preflight.ValidationResult.ValidationError;
+import org.apache.padaf.preflight.utils.COSUtils;
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSDocument;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSObject;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+
+public class CompositeFontValidator extends AbstractFontValidator {
+	protected String basefont;
+	protected COSBase descendantFonts;
+	protected COSDictionary cidFont;
+	protected COSBase encoding;
+	protected COSStream cmap;
+	protected COSBase toUnicode;
+
+	protected CMap cidToGidMap = null;
+
+	protected boolean isIdentityCMap = false;
+
+	public CompositeFontValidator(DocumentHandler handler, COSObject obj)
+	throws ValidationException {
+		super(handler, obj);
+	}
+
+	/**
+	 * This methods extracts from the Font dictionary all mandatory fields. If a
+	 * mandatory field is missing, the list of ValidationError in the
+	 * FontContainer is updated. On error, the method returns false.
+	 * 
+	 * @return
+	 */
+	protected boolean checkMandatoryFields() {
+		String type = fDictionary.getNameAsString(COSName
+				.getPDFName(DICTIONARY_KEY_TYPE));
+		String subtype = fDictionary.getNameAsString(COSName
+				.getPDFName(DICTIONARY_KEY_SUBTYPE));
+
+		// ---- just check if they are present because of the Helper has already
+		// checked them.
+		if ((type == null || "".equals(type))
+				|| (subtype == null || "".equals(subtype))) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID,
+			"Type and/or Subtype keys are missing"));
+			return false;
+		}
+
+		// ---- Check presence of baseFont, CMap and CIDFont
+		this.basefont = fDictionary.getNameAsString(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_BASEFONT));
+		this.descendantFonts = fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_DESCENDANT_FONTS));
+		this.encoding = fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_ENCODING));
+
+		if ((basefont == null || "".equals(basefont)) || descendantFonts == null
+				|| encoding == null) {
+			// ---- baseFont syntax isn't checked because of it is a convention not a
+			// rule
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID,
+			"BaseFont, Encoding or DescendantFonts keys are missing"));
+			return false;
+		}
+
+		// ---- toUnicode is optional, but keep the value if present.
+		this.toUnicode = fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_TOUNICODE));
+		return true;
+	}
+
+	/**
+	 * This method validates the CIDFont dictionary.
+	 * 
+	 * This method returns false and updates the list of errors in the
+	 * FontContainer if some mandatory fields are missing.
+	 * 
+	 * This method calls the processCIDFontTypeX method to check if the font is
+	 * damaged or not. If the font is damaged, the errors list is updated and the
+	 * method return false.
+	 * 
+	 * @return
+	 * @throws ValidationException
+	 */
+	protected boolean checkCIDFont() throws ValidationException {
+
+		// ---- a CIDFont is contained in the DescendantFonts array
+		COSDocument cDoc = this.handler.getDocument().getDocument();
+		COSArray array = COSUtils.getAsArray(descendantFonts, cDoc);
+
+		if (array == null) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_CIDKEYED_INVALID,
+			"CIDFont is missing from the DescendantFonts array"));
+			return false;
+		}
+		// ---- in PDF 1.4, this array must contain only one element,
+		// because of a PDF/A should be a PDF 1.4, this method returns an error if
+		// the array
+		// has more than one element.
+		if (array.size() != 1) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_CIDKEYED_INVALID,
+			"The DescendantFonts array should have one element."));
+			return false;
+		}
+
+		this.cidFont = COSUtils.getAsDictionary(array.get(0), cDoc);
+		if (this.cidFont == null) {
+			this.fontContainer
+			.addError(new ValidationError(ERROR_FONTS_CIDKEYED_INVALID,
+			"The DescendantFonts array should have one element with is a dictionary."));
+			return false;
+		}
+
+		String type = cidFont.getNameAsString(COSName
+				.getPDFName(DICTIONARY_KEY_TYPE));
+		String subtype = cidFont.getNameAsString(COSName
+				.getPDFName(DICTIONARY_KEY_SUBTYPE));
+
+		if ((type == null || "".equals(type))
+				|| (subtype == null || "".equals(subtype))) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID,
+			"Type and/or Subtype keys are missing"));
+			return false;
+		}
+
+		boolean isT0 = FONT_DICTIONARY_VALUE_TYPE0.equals(subtype);
+		boolean isT2 = FONT_DICTIONARY_VALUE_TYPE2.equals(subtype);
+		// ---- Even if these entries are present, values must be checked.
+		if (!FONT_DICTIONARY_VALUE_FONT.equals(type) || !(isT0 || isT2)) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID,
+			"Type and/or Subtype keys are missing"));
+			return false;
+		}
+
+		// ---- BaseFont is mandatory
+		String bf = cidFont.getNameAsString(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_BASEFONT));
+		if (bf == null || "".equals(bf)) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID, "BaseFont is missing"));
+			return false;
+		}
+
+		// ---- checks others mandatory fields
+		COSBase sysinfo = cidFont.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_CID_SYSINFO));
+		COSBase fontDesc = cidFont.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_FONT_DESC));
+		COSBase cidToGid = cidFont.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_CID_GIDMAP));
+
+		boolean result = checkCIDSystemInfo(sysinfo, cDoc);
+		if (isT0) {
+			result = result && checkCIDToGIDMap(cidToGid, cDoc, false);
+			result = result && processCIDFontType0(fontDesc);
+		} else {
+			result = result && checkCIDToGIDMap(cidToGid, cDoc, true);
+			result = result && processCIDFontType2(fontDesc);
+		}
+		return result;
+	}
+
+	/**
+	 * Check the content of the CIDSystemInfo dictionary. A CIDSystemInfo
+	 * dictionary must contain :
+	 * <UL>
+	 * <li>a Name - Registry
+	 * <li>a Name - Ordering
+	 * <li>a Integer - Supplement
+	 * </UL>
+	 * 
+	 * @param sysinfo
+	 * @param cDoc
+	 * @return
+	 */
+	private boolean checkCIDSystemInfo(COSBase sysinfo, COSDocument cDoc) {
+		COSDictionary cidSysInfo = COSUtils.getAsDictionary(sysinfo, cDoc);
+		if (cidSysInfo == null) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_CIDKEYED_SYSINFO));
+			return false;
+		}
+
+		COSBase reg = cidSysInfo.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_SYSINFO_REGISTRY));
+		COSBase ord = cidSysInfo.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_SYSINFO_ORDERING));
+		COSBase sup = cidSysInfo.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_SYSINFO_SUPPLEMENT));
+
+		if (!(COSUtils.isString(reg, cDoc) && COSUtils.isString(ord, cDoc) && COSUtils
+				.isInteger(sup, cDoc))) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_CIDKEYED_SYSINFO));
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * This method checks the CIDtoGIDMap entry of the Font dictionary. This
+	 * element must be a Stream or a Name. If it is a name, it must be "Identity"
+	 * otherwise, the PDF file isn't a PDF/A-1b.
+	 * 
+	 * If the validation fails, the method returns false and the list of error in
+	 * the FontContainer is updated.
+	 * 
+	 * If the CIDtoGIDMap is a Stream, it is parsed as a CMap and the result is
+	 * kept in the cidToGidMap attribute.
+	 * 
+	 * @param ctog
+	 * @param cDoc
+	 * @param mandatory
+	 * @return
+	 */
+	private boolean checkCIDToGIDMap(COSBase ctog, COSDocument cDoc,
+			boolean mandatory) {
+		if (COSUtils.isString(ctog, cDoc)) {
+			// ---- valid only if the string is Identity
+			String ctogStr = COSUtils.getAsString(ctog, cDoc);
+			if (!FONT_DICTIONARY_VALUE_CMAP_IDENTITY.equals(ctogStr)) {
+				this.fontContainer.addError(new ValidationError(
+						ERROR_FONTS_CIDKEYED_CIDTOGID,"The CIDToGID entry is invalid"));
+				return false;
+			}
+		} else if (COSUtils.isStream(ctog, cDoc)) {
+			try {
+				COSStream ctogMap = COSUtils.getAsStream(ctog, cDoc);
+				this.cidToGidMap = new CMapParser().parse(null, ctogMap
+						.getUnfilteredStream());
+			} catch (IOException e) {
+				// ---- map can be invalid, return a Validation Error
+				this.fontContainer.addError(new ValidationError(
+						ERROR_FONTS_CIDKEYED_CIDTOGID));
+				return false;
+			}
+		} else if (mandatory) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_CIDKEYED_CIDTOGID));
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Check the CMap entry.
+	 * 
+	 * The CMap entry must be a dictionary in a PDF/A. This entry can be a String
+	 * only if the String value is Identity-H or Identity-V
+	 * 
+	 * @param errors
+	 * @return
+	 */
+	protected boolean checkCMap(COSBase aEncoding) {
+		COSDocument cDoc = this.handler.getDocument().getDocument();
+
+		if (COSUtils.isString(aEncoding, cDoc)) {
+			// ---- if encoding is a string, only 2 values are allowed
+			String str = COSUtils.getAsString(aEncoding, cDoc);
+			if (!(FONT_DICTIONARY_VALUE_CMAP_IDENTITY_V.equals(str) || FONT_DICTIONARY_VALUE_CMAP_IDENTITY_H
+					.equals(str))) {
+				this.fontContainer.addError(new ValidationError(
+						ERROR_FONTS_CIDKEYED_INVALID,
+				"The CMap is a string but it isn't an Identity-H/V"));
+				return false;
+			}
+			isIdentityCMap = true;
+		} else if (COSUtils.isStream(aEncoding, cDoc)) {
+			// ---- If the CMap is a stream, some fields are mandatory
+			// and the CIDSytemInfo must be compared with the CIDSystemInfo
+			// entry of the CIDFont.
+			return processCMapAsStream(COSUtils.getAsStream(aEncoding, cDoc));
+		} else {
+			// ---- CMap type is invalid
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_CIDKEYED_CMAP_INVALID_OR_MISSING,
+			"The CMap type is invalid"));
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Standard information of a stream element will be checked by the
+	 * StreamHelper.
+	 * 
+	 * This method checks mandatory fields of the CMap stream. This method checks
+	 * too if the CMap stream is damaged using the CMapParser of the fontbox api.
+	 * 
+	 * @param aCMap
+	 * @return
+	 */
+	private boolean processCMapAsStream(COSStream aCMap) {
+		COSDocument cDoc = handler.getDocument().getDocument();
+
+		String type = aCMap
+		.getNameAsString(COSName.getPDFName(DICTIONARY_KEY_TYPE));
+		String cmapName = aCMap.getNameAsString(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_CMAP_NAME));
+		COSBase sysinfo = aCMap.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_CID_SYSINFO));
+		int wmode = aCMap
+		.getInt(COSName.getPDFName(FONT_DICTIONARY_KEY_CMAP_WMODE));
+		COSBase cmapUsed = aCMap.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_CMAP_USECMAP));
+
+		if (!FONT_DICTIONARY_VALUE_TYPE_CMAP.equals(type)) {
+			// ---- CMap type is invalid
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_CIDKEYED_CMAP_INVALID_OR_MISSING,
+			"The CMap type is invalid"));
+			return false;
+		}
+
+		// ---- check the content of the CIDSystemInfo
+		if (!checkCIDSystemInfo(sysinfo, cDoc)) {
+			return false;
+		}
+
+		if (cmapName == null || "".equals(cmapName) || wmode > 1) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_CIDKEYED_CMAP_INVALID_OR_MISSING,
+			"Some elements in the CMap dictionary are missing or invalid"));
+			return false;
+		}
+
+		try {
+
+			CMap fontboxCMap = new CMapParser().parse(null, aCMap
+					.getUnfilteredStream());
+			int wmValue = fontboxCMap.getWMode();
+			String cmnValue = fontboxCMap.getName(); //getCmapEntry("CMapName");
+
+
+			if (wmValue != wmode) {
+
+				this.fontContainer.addError(new ValidationError(
+						ERROR_FONTS_CIDKEYED_CMAP_INVALID_OR_MISSING,
+				"WMode is inconsistent"));
+				return false;
+			}
+
+			if (!cmnValue.equals(cmapName)) {
+
+				this.fontContainer.addError(new ValidationError(
+						ERROR_FONTS_CIDKEYED_CMAP_INVALID_OR_MISSING,
+				"CMapName is inconsistent"));
+				return false;
+			}
+
+		} catch (IOException e) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_CID_CMAP_DAMAGED, "The CMap type is damaged"));
+			return false;
+		}
+
+		if (cmapUsed != null) {
+			return checkCMap(cmapUsed);
+		}
+
+		return true;
+	}
+
+	/**
+	 * The CIDSystemInfo must have the same Registry and Ordering for CMap and
+	 * CIDFont. This control is useless if CMap is Identity-H or Identity-V so
+	 * this method is called by the checkCMap method.
+	 * 
+	 * @param errors
+	 * @return
+	 */
+	private boolean compareCIDSystemInfo() {
+		COSDocument cDoc = handler.getDocument().getDocument();
+		if (!isIdentityCMap) {
+			COSDictionary cmsi = COSUtils.getAsDictionary(this.cmap.getItem(COSName
+					.getPDFName(FONT_DICTIONARY_KEY_CID_SYSINFO)), cDoc);
+			COSDictionary cfsi = COSUtils.getAsDictionary(this.cidFont
+					.getItem(COSName.getPDFName(FONT_DICTIONARY_KEY_CID_SYSINFO)), cDoc);
+
+			String regCM = COSUtils.getAsString(cmsi.getItem(COSName
+					.getPDFName(FONT_DICTIONARY_KEY_SYSINFO_REGISTRY)), cDoc);
+			String ordCM = COSUtils.getAsString(cmsi.getItem(COSName
+					.getPDFName(FONT_DICTIONARY_KEY_SYSINFO_ORDERING)), cDoc);
+
+			String regCF = COSUtils.getAsString(cfsi.getItem(COSName
+					.getPDFName(FONT_DICTIONARY_KEY_SYSINFO_REGISTRY)), cDoc);
+			String ordCF = COSUtils.getAsString(cfsi.getItem(COSName
+					.getPDFName(FONT_DICTIONARY_KEY_SYSINFO_ORDERING)), cDoc);
+
+			if (!regCF.equals(regCM) || !ordCF.equals(ordCM)) {
+				this.fontContainer.addError(new ValidationError(
+						ERROR_FONTS_CIDKEYED_SYSINFO, "The CIDSystemInfo is inconsistent"));
+				return false;
+			}
+		} // else cmap is null because it is a Identity-H/V
+		return true;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * net.awl.edoc.pdfa.validation.font.FontValidator#validate(java.util.List)
+	 */
+	public boolean validate() throws ValidationException {
+		boolean result = checkMandatoryFields();
+		result = result && checkCIDFont();
+		result = result && checkCMap(encoding);
+		if (result) {
+			this.cmap = COSUtils.getAsStream(encoding, handler.getDocument()
+					.getDocument());
+		}
+		result = result && compareCIDSystemInfo();
+		return result;
+	}
+
+	/**
+	 * Check if all required fields are present in the PDF file to describe the
+	 * Font Descriptor.
+	 * 
+	 * @param handler
+	 * @param fontDescriptor
+	 * @param result
+	 */
+	protected boolean checkFontDescriptorMandatoryFields(
+			PDFontDescriptorDictionary pdFontDesc) {
+		boolean fname = false, flags = false, itangle = false, cheight = false;
+		boolean fbbox = false, asc = false, desc = false, stemv = false;
+
+		COSDictionary fontDescDictionary = pdFontDesc.getCOSDictionary();
+		for (Object key : fontDescDictionary.keySet()) {
+
+			if (!(key instanceof COSName)) {
+				this.fontContainer.addError(new ValidationResult.ValidationError(
+						ValidationConstants.ERROR_SYNTAX_DICTIONARY_KEY_INVALID,
+				"Invalid key in The font descriptor"));
+				return false;
+			}
+
+			String cosName = ((COSName) key).getName();
+			if (cosName.equals(FONT_DICTIONARY_KEY_FONTNAME)) {
+				fname = true;
+			}
+			if (cosName.equals(FONT_DICTIONARY_KEY_FLAGS)) {
+				flags = true;
+			}
+			if (cosName.equals(FONT_DICTIONARY_KEY_ITALICANGLE)) {
+				itangle = true;
+			}
+			if (cosName.equals(FONT_DICTIONARY_KEY_CAPHEIGHT)) {
+				cheight = true;
+			}
+			if (cosName.equals(FONT_DICTIONARY_KEY_FONTBBOX)) {
+				fbbox = true;
+			}
+			if (cosName.equals(FONT_DICTIONARY_KEY_ASCENT)) {
+				asc = true;
+			}
+			if (cosName.equals(FONT_DICTIONARY_KEY_DESCENT)) {
+				desc = true;
+			}
+			if (cosName.equals(FONT_DICTIONARY_KEY_STEMV)) {
+				stemv = true;
+			}
+
+		}
+
+		if (!(fname && flags && itangle && cheight && fbbox && asc && desc && stemv)) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DESCRIPTOR_INVALID, "Some mandatory fields are missing"));
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Process the CIDFontType0 validation.
+	 * 
+	 * @param fontDesc
+	 *          The FontDescriptor which contains the Font Program
+	 * @return
+	 * @throws ValidationException
+	 */
+	protected boolean processCIDFontType0(COSBase fontDesc)
+	throws ValidationException {
+		COSDictionary fontDescDic = COSUtils.getAsDictionary(fontDesc, handler
+				.getDocument().getDocument());
+		if (fontDescDic == null) {
+			throw new ValidationException(
+			"Unable to process CIDFontType0 because of the font descriptor is invalid.");
+		}
+		PDFontDescriptorDictionary pfDescriptor = new PDFontDescriptorDictionary(
+				fontDescDic);
+		boolean isValid = checkFontDescriptorMandatoryFields(pfDescriptor);
+		isValid = isValid && checkCIDKeyedFontName(pfDescriptor, true);
+		isValid = isValid && checkFontFileElement_CIDFontType0(pfDescriptor);
+		isValid = isValid && checkCIDSet(pfDescriptor);
+		return isValid;
+	}
+
+	/**
+	 * Checks if the FontName contained in the FontDescriptor dictionary of the
+	 * CID-Keyed Font is present. (The FontName is mandatory according to the PDF
+	 * Reference.) If the consistency must be checked, the FontName contained in
+	 * the FontDescriptor is consistent with the BaseName of the font dictionary.
+	 * If font name is invalid, the list of validation errors in the FontContainer
+	 * is updated.
+	 * 
+	 * @param pfDescriptor
+	 *          The FontDescriptor dictionary which contains the FontName to check
+	 * @param checkConsistency
+	 *          true if the font name must be consistent with the BaseName of the
+	 *          Font dictionary
+	 * @return
+	 */
+	protected boolean checkCIDKeyedFontName(
+			PDFontDescriptorDictionary pfDescriptor, boolean checkConsistency) {
+		String fontName = pfDescriptor.getFontName();
+		String baseName = this.pFont.getBaseFont();
+
+		if (fontName == null) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ERROR_FONTS_DESCRIPTOR_INVALID,
+			"The FontName in font descriptor is missing"));
+			return false;
+		}
+
+		if (checkConsistency
+				&& !(fontName.equals(baseName) || fontName.contains(baseName) || baseName
+						.contains(fontName))) {
+			this.fontContainer
+			.addError(new ValidationResult.ValidationError(
+					ERROR_FONTS_DESCRIPTOR_INVALID,
+			"The FontName in font descriptor isn't the same as the BaseFont in the Font dictionary"));
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * This method return false and updates the FontContainer if the Composite
+	 * Font TYPE 0 or TYPE1C is damaged. This method checks the Widths
+	 * consistency.
+	 * 
+	 * @param pfDescriptor
+	 * @return
+	 */
+	boolean checkFontFileElement_CIDFontType0(
+			PDFontDescriptorDictionary pfDescriptor) throws ValidationException {
+		// ---- FontFile Validation
+		PDStream ff1 = pfDescriptor.getFontFile();
+		PDStream ff2 = pfDescriptor.getFontFile2();
+		PDStream ff3 = pfDescriptor.getFontFile3();
+
+		boolean onlyOne = (ff1 != null && ff2 == null && ff3 == null)
+		|| (ff1 == null && ff2 != null && ff3 == null)
+		|| (ff1 == null && ff2 == null && ff3 != null);
+
+		if ((ff3 == null) || !onlyOne) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is invalid"));
+			return false;
+		}
+
+		// ---- Stream validation should be done by the StreamValidateHelper.
+		// ---- Process font specific check
+		COSStream stream = ff3.getStream();
+		if (stream == null) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is missing"));
+			this.fontContainer.setFontProgramEmbedded(false);
+			return false;
+		}
+
+		// ---- Lengthx aren't mandatory for this type of font
+		// ---- But the Subtype is a mandatory field with specific values
+		String st = stream.getNameAsString(COSName
+				.getPDFName(DICTIONARY_KEY_SUBTYPE));
+		if (!(FONT_DICTIONARY_VALUE_TYPE0C.equals(st) || FONT_DICTIONARY_VALUE_TYPE1C
+				.equals(st))) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ERROR_FONTS_FONT_FILEX_INVALID,
+			"The FontFile3 stream doesn't have the right Subtype"));
+			return false;
+		}
+
+		// ---- try to load the font using the java.awt.font object.
+		// ---- if the font is invalid, an exception will be thrown
+		try {
+			CFFParser cffParser = new CFFParser();
+			List<CFFFont> lCFonts = cffParser.parse(ff3.getByteArray());
+
+			if (lCFonts == null || lCFonts.isEmpty()) {
+				this.fontContainer.addError(new ValidationResult.ValidationError(
+						ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
+				return false;
+			}
+
+			return checkCIDFontWidths(lCFonts)
+			&& checkFontFileMetaData(pfDescriptor, ff3);
+		} catch (IOException e) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
+			return false;
+		}
+	}
+
+	/**
+	 * This method checks the metric consistency of a CIDFontType2.
+	 * 
+	 * @param ttf
+	 *          The TrueTypeFont object which represent the CIDFontType2 Font
+	 *          Program.
+	 * @return
+	 * @throws ValidationException
+	 */
+	protected boolean checkTTFontMetrics(TrueTypeFont ttf)
+	throws ValidationException {
+		LinkedHashMap<Integer, Integer> widths = getWidthsArray();
+		int defaultWidth = this.cidFont.getInt("DW", 1000);
+		int unitsPerEm = ttf.getHeader().getUnitsPerEm();
+		int[] glyphWidths = ttf.getHorizontalMetrics().getAdvanceWidth();
+		/* In a Mono space font program, the length of the AdvanceWidth array must be one.
+		 * According to the TrueType font specification, the Last Value of the AdvanceWidth array
+		 * is apply to the subsequent glyphs. So if the GlyphId is greater than the length of the array
+		 * the last entry is used.
+		 */
+		int numberOfLongHorMetrics = ttf.getHorizontalHeader().getNumberOfHMetrics();
+		CFFType2FontContainer type2FontContainer = ((CompositeFontContainer)this.fontContainer).getCFFType2();
+		type2FontContainer.setPdfWidths(widths);
+		type2FontContainer.setCmap(this.cidToGidMap);
+		type2FontContainer.setDefaultGlyphWidth(defaultWidth);
+		type2FontContainer.setFontObject(ttf);
+		type2FontContainer.setGlyphWidths(glyphWidths);
+		type2FontContainer.setNumberOfLongHorMetrics(numberOfLongHorMetrics);
+		type2FontContainer.setUnitsPerEm(unitsPerEm);
+
+		return true;
+	}
+
+	/**
+	 * This method check Metrics consistency of the CIDFontType0.
+	 * 
+	 * @param lCFonts
+	 * @return
+	 * @throws ValidationException
+	 */
+	protected boolean checkCIDFontWidths(List<CFFFont> lCFonts)
+	throws ValidationException {
+		// ---- Extract Widths and default Width from the CIDFont dictionary
+		LinkedHashMap<Integer, Integer> widths = getWidthsArray();
+		int defaultWidth = this.cidFont.getInt("DW", 1000);
+		CFFType0FontContainer type0FontContainer = ((CompositeFontContainer)this.fontContainer).getCFFType0();
+		type0FontContainer.setFontObject(lCFonts);
+		type0FontContainer.setDefaultGlyphWidth(defaultWidth);
+		type0FontContainer.setWidthsArray(widths);
+
+		return true;
+	}
+
+	/**
+	 * This method return false and updates the FontContainer if the Composite
+	 * Font TYPE 2 is damaged or missing.
+	 * 
+	 * @param pfDescriptor
+	 * @return
+	 */
+	boolean checkFontFileElement_CIDFontType2(
+			PDFontDescriptorDictionary pfDescriptor) throws ValidationException {
+
+		// ---- FontFile Validation
+		PDStream ff1 = pfDescriptor.getFontFile();
+		PDStream ff2 = pfDescriptor.getFontFile2();
+		PDStream ff3 = pfDescriptor.getFontFile3();
+
+		boolean onlyOne = (ff1 != null && ff2 == null && ff3 == null)
+		|| (ff1 == null && ff2 != null && ff3 == null)
+		|| (ff1 == null && ff2 == null && ff3 != null);
+
+		if ((ff2 == null) || !onlyOne) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is invalid"));
+			return false;
+		}
+
+		// ---- Stream validation should be done by the StreamValidateHelper.
+		// ---- Process font specific check
+		COSStream stream = ff2.getStream();
+		if (stream == null) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is missing"));
+			this.fontContainer.setFontProgramEmbedded(false);
+			return false;
+		}
+
+		boolean hasLength1 = stream.getInt(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_LENGTH1)) > 0;
+				if (!hasLength1) {
+					this.fontContainer.addError(new ValidationResult.ValidationError(
+							ValidationConstants.ERROR_FONTS_FONT_FILEX_INVALID,
+					"The FontFile is invalid"));
+					return false;
+				}
+
+				// ---- try to load the font using the java.awt.font object.
+				// ---- if the font is invalid, an exception will be thrown
+				TrueTypeFont ttf = null;
+				try {
+					// ---- According to PDF Reference, CIDFontType2 is a TrueType font.
+					// ---- Remark : Java.awt.Font throws exception when a CIDFontType2 is
+					// parsed even if it is valid.
+					ttf = new CIDFontType2Parser(true).parseTTF(new ByteArrayInputStream(ff2
+							.getByteArray()));
+				} catch (Exception e) {
+					// ---- Exceptionally, Exception is catched Here because of damaged font
+					// can throw NullPointer Exception...
+					this.fontContainer.addError(new ValidationResult.ValidationError(
+							ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
+					return false;
+				}
+
+				return checkTTFontMetrics(ttf) && checkFontFileMetaData(pfDescriptor, ff2);
+	}
+
+	/**
+	 * For a CIDFont the width array, there are two formats of width array :
+	 * <UL>
+	 * <li>C [W1...Wn] : C is an integer specifying a starting CID value and the
+	 * array of n numbers specify widths for n consecutive CIDs.
+	 * <li>Cf Cl W : Defines the same width W for the range Cf to Cl
+	 * </UL>
+	 * This method gets a linked hash map of width where the key is a CID and the
+	 * value is the Width.
+	 * 
+	 * @return
+	 * @throws ValidationException
+	 */
+	protected LinkedHashMap<Integer, Integer> getWidthsArray()
+	throws ValidationException {
+		LinkedHashMap<Integer, Integer> widthsMap = new LinkedHashMap<Integer, Integer>();
+		COSDocument cDoc = handler.getDocument().getDocument();
+		COSBase cBase = this.cidFont.getItem(COSName.getPDFName("W"));
+		COSArray wArr = COSUtils.getAsArray(cBase, cDoc);
+
+		for (int i = 0; i < wArr.size();) {
+
+			int firstCid = wArr.getInt(i);
+
+			if (i + 1 >= wArr.size()) {
+				throw new ValidationException("Invalid format of the W entry");
+			}
+
+			COSBase cb = wArr.getObject(i + 1);
+			if (COSUtils.isArray(cb, cDoc)) {
+
+				// ---- First Format
+				COSArray seqWidths = COSUtils.getAsArray(cb, cDoc);
+				widthsMap.put(firstCid, seqWidths.getInt(0));
+				for (int jw = 1; jw < seqWidths.size(); jw++) {
+					widthsMap.put((firstCid + jw), seqWidths.getInt(jw));
+				}
+
+				i = i + 2;
+
+			} else {
+
+				// ---- Second Format
+				if (i + 2 >= wArr.size()) {
+					throw new ValidationException("Invalid format of the W entry");
+				}
+
+				int lastCid = wArr.getInt(i + 1);
+				int commonWidth = wArr.getInt(i + 2);
+				for (int jw = firstCid; jw <= lastCid; ++jw) {
+					widthsMap.put((firstCid + jw), commonWidth);
+				}
+
+				i = i + 3;
+
+			}
+
+		}
+
+		return widthsMap;
+	}
+
+	/**
+	 * If the embedded font is a subset, the CIDSet entry is mandatory and must be
+	 * a Stream. This method returns true if the CIDSet entry respects conditions,
+	 * otherwise the method returns false and the FontContainer is updated.
+	 * 
+	 * @param pfDescriptor
+	 * @return
+	 */
+	protected boolean checkCIDSet(PDFontDescriptorDictionary pfDescriptor) {
+		if (isSubSet(pfDescriptor.getFontName())) {
+			COSBase cidset = pfDescriptor.getCOSDictionary().getItem(
+					COSName.getPDFName(FONT_DICTIONARY_KEY_CIDSET));
+			if (cidset == null
+					|| !COSUtils.isStream(cidset, this.handler.getDocument()
+							.getDocument())) {
+				this.fontContainer.addError(new ValidationResult.ValidationError(
+						ERROR_FONTS_CIDSET_MISSING_FOR_SUBSET,
+				"The CIDSet entry is missing for the Composite Subset"));
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * 
+	 * @param fontDesc
+	 * @return
+	 * @throws ValidationException
+	 */
+	protected boolean processCIDFontType2(COSBase fontDesc)
+	throws ValidationException {
+		COSDictionary fontDescDic = COSUtils.getAsDictionary(fontDesc, handler
+				.getDocument().getDocument());
+		if (fontDescDic == null) {
+			throw new ValidationException(
+			"Unable to process CIDFontType2 because of the font descriptor is invalid.");
+		}
+		PDFontDescriptorDictionary pfDescriptor = new PDFontDescriptorDictionary(
+				fontDescDic);
+		boolean isValid = checkFontDescriptorMandatoryFields(pfDescriptor);
+		isValid = isValid && checkCIDKeyedFontName(pfDescriptor, false);
+		isValid = isValid && checkFontFileElement_CIDFontType2(pfDescriptor);
+		isValid = isValid && checkCIDSet(pfDescriptor);
+		return isValid;
+	}
+}

Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/CompositeFontValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontMetaDataValidation.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontMetaDataValidation.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontMetaDataValidation.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontMetaDataValidation.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,219 @@
+/*****************************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ ****************************************************************************/
+
+package org.apache.padaf.preflight.font;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+
+import org.apache.padaf.preflight.ValidationConstants;
+import org.apache.padaf.preflight.ValidationException;
+import org.apache.padaf.preflight.ValidationResult.ValidationError;
+import org.apache.padaf.xmpbox.XMPMetadata;
+import org.apache.padaf.xmpbox.schema.DublinCoreSchema;
+import org.apache.padaf.xmpbox.schema.XMPRightsManagementSchema;
+import org.apache.padaf.xmpbox.type.AbstractField;
+import org.apache.padaf.xmpbox.type.BooleanType;
+import org.apache.padaf.xmpbox.type.ComplexProperty;
+import org.apache.padaf.xmpbox.type.TextType;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
+
+/**
+ * Class used to validate the MetaData entry of the Font File Stream dictionary.
+ */
+public class FontMetaDataValidation {
+
+  public List<ValidationError> validatePDFAIdentifer(XMPMetadata metadata,
+      PDFontDescriptor fontDesc) throws ValidationException {
+    List<ValidationError> ve = new ArrayList<ValidationError>();
+
+    analyseFontName(metadata, fontDesc, ve);
+    analyseRights(metadata, fontDesc, ve);
+
+    return ve;
+  }
+
+  /**
+   * Value of the dc:title must be the same as the FontName in the font
+   * descriptor.
+   * 
+   * @param metadata
+   *          XMPMetaData of the Font File Stream
+   * @param fontDesc
+   *          The FontDescriptor dictionary
+   * @param ve
+   *          the list of validation error to update if the validation fails
+   * @throws ValidationException
+   */
+  public boolean analyseFontName(XMPMetadata metadata,
+      PDFontDescriptor fontDesc, List<ValidationError> ve)
+      throws ValidationException {
+    String fontName = fontDesc.getFontName();
+    String noSubSetName = fontName;
+    if (AbstractFontValidator.isSubSet(fontName)) {
+      noSubSetName = fontName.split(AbstractFontValidator
+          .getSubSetPatternDelimiter())[1];
+    }
+
+    DublinCoreSchema dc = metadata.getDublinCoreSchema();
+    if (dc.getTitle() != null) {
+      String defaultTitle = dc.getTitleValue("x-default");
+      if (defaultTitle != null) {
+
+        if (!defaultTitle.equals(fontName)
+            && (noSubSetName != null && !defaultTitle.equals(noSubSetName))) {
+          StringBuilder sb = new StringBuilder(80);
+          sb
+              .append("FontName")
+              .append(
+                  " present in the FontDescriptor dictionary doesn't match with XMP information dc:title of the Font File Stream.");
+          ve.add(new ValidationError(
+              ValidationConstants.ERROR_METADATA_MISMATCH, sb.toString()));
+          return false;
+        }
+
+        // --- default value is the right one
+        return true;
+      } else {
+        Iterator<AbstractField> it = dc.getTitle().getContainer()
+            .getAllProperties().iterator();
+        boolean empty = true;
+        while (it.hasNext()) {
+          empty = false;
+          AbstractField tmp = it.next();
+          if (tmp != null && tmp instanceof TextType) {
+            if (((TextType) tmp).getStringValue().equals(fontName)
+                || (noSubSetName != null && ((TextType) tmp).getStringValue()
+                    .equals(noSubSetName))) {
+              // value found, return
+              return true;
+            }
+          }
+        }
+
+        // title doesn't match, it is an error.
+        StringBuilder sb = new StringBuilder(80);
+        sb.append("FontName");
+        if (empty) {
+          sb
+              .append(" present in the FontDescriptor dictionary can't be found in XMP information the Font File Stream.");
+          ve.add(new ValidationError(
+              ValidationConstants.ERROR_METADATA_PROPERTY_MISSING, sb
+                  .toString()));
+        } else {
+          sb
+              .append(" present in the FontDescriptor dictionary doesn't match with XMP information dc:title of the Font File Stream.");
+          ve.add(new ValidationError(
+              ValidationConstants.ERROR_METADATA_MISMATCH, sb.toString()));
+        }
+        return false;
+      }
+    }
+
+    // ---- dc:title is required
+    ve.add(new ValidationError(
+        ValidationConstants.ERROR_METADATA_PROPERTY_MISSING,
+        "dc:title is missing from the FontFile MetaData"));
+    return false;
+  }
+
+  /**
+   * If XMP MetaData are present, they must have followings information :
+   * <UL>
+   * <li>dc:rights
+   * <li>Marked (with the value true)
+   * <li>Owner
+   * <li>UsageTerms
+   * </UL>
+   * 
+   * @param metadata
+   *          XMPMetaData of the Font File Stream
+   * @param fontDesc
+   *          The FontDescriptor dictionary
+   * @param ve
+   *          the list of validation error to update if the validation fails
+   * @throws ValidationException
+   */
+  public boolean analyseRights(XMPMetadata metadata, PDFontDescriptor fontDesc,
+      List<ValidationError> ve) throws ValidationException {
+    DublinCoreSchema dc = metadata.getDublinCoreSchema();
+    ComplexProperty copyrights = dc.getRights();
+    if (copyrights == null || copyrights.getContainer() == null
+        || copyrights.getContainer().getAllProperties().isEmpty()) {
+      ve
+          .add(new ValidationError(
+              ValidationConstants.ERROR_METADATA_PROPERTY_MISSING,
+              "CopyRights is missing from the XMP information (dc:rights) of the Font File Stream."));
+      return false;
+    }
+
+    XMPRightsManagementSchema rights = metadata.getXMPRightsManagementSchema();
+    BooleanType marked = rights.getMarked();
+    if (marked == null) {
+      ve
+          .add(new ValidationError(
+              ValidationConstants.ERROR_METADATA_PROPERTY_MISSING,
+              "the XMP information (xmpRights:Marked) missing for the Font File Stream."));
+      return false;
+    } else if (!marked.getValue()) {
+      ve
+          .add(new ValidationError(
+              ValidationConstants.ERROR_METADATA_PROPERTY_MISSING,
+              "the XMP information (xmpRights:Marked) is invalid for the Font File Stream."));
+      return false;
+    }
+
+    ComplexProperty usage = rights.getUsageTerms();
+    if (usage == null || usage.getContainer() == null
+        || usage.getContainer().getAllProperties().isEmpty()) {
+      ve
+          .add(new ValidationError(
+              ValidationConstants.ERROR_METADATA_PROPERTY_MISSING,
+              "Usage Terms are missing from the XMP information (xmpRights:UsageTerms) of the Font File Stream."));
+      return false;
+    }
+
+    List<String> owners = rights.getOwnerValue();
+    if (owners == null || owners.isEmpty()) {
+      ve.add(new ValidationError(
+              ValidationConstants.ERROR_METADATA_PROPERTY_MISSING,
+              "Owner missing from the XMP information (xmpRights:Owner) of the Font File Stream."));
+      return false;
+    } else {
+    	boolean allEmpty = true;
+    	for (String owner : owners) {
+			if (!"".equals(owner)) {
+				allEmpty = false;
+			}
+		}
+    	if (allEmpty) {
+    		ve.add(new ValidationError(
+    	              ValidationConstants.ERROR_METADATA_PROPERTY_MISSING,
+    	              "Owner missing from the XMP information (xmpRights:Owner) of the Font File Stream."));
+    	      return false;	
+    	}
+    }
+
+    return true;
+  }
+}

Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontMetaDataValidation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontValidator.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontValidator.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontValidator.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontValidator.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ ****************************************************************************/
+
+package org.apache.padaf.preflight.font;
+
+import java.util.List;
+
+import org.apache.padaf.preflight.ValidationException;
+import org.apache.padaf.preflight.ValidationResult.ValidationError;
+import org.apache.padaf.preflight.font.AbstractFontContainer.State;
+
+
+public interface FontValidator {
+
+  /**
+   * Call this method to validate the font wrapped by this interface
+   * implementation. Return true if the validation succeed, false otherwise. If
+   * the validation failed, the error is updated in the FontContainer with the
+   * right error code.
+   * 
+   * @return
+   */
+  public abstract boolean validate() throws ValidationException;
+
+  /**
+   * Return the State of the Font Validation. Three values are possible :
+   * <UL>
+   * <li>VALID : there are no errors
+   * <li>MAYBE : Metrics aren't consistent of the FontProgram isn't embedded,
+   * but it can be valid.
+   * <li>INVALID : the validation fails
+   * </UL>
+   * 
+   * @return
+   */
+  public State getState();
+
+  /**
+   * Return all validation errors.
+   * 
+   * @return
+   */
+  public List<ValidationError> getValdiationErrors();
+}

Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontValidatorFactory.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontValidatorFactory.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontValidatorFactory.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontValidatorFactory.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,81 @@
+/*****************************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ ****************************************************************************/
+
+package org.apache.padaf.preflight.font;
+
+import static org.apache.padaf.preflight.ValidationConstants.DICTIONARY_KEY_SUBTYPE;
+import static org.apache.padaf.preflight.ValidationConstants.DICTIONARY_KEY_TYPE;
+import static org.apache.padaf.preflight.ValidationConstants.ERROR_FONTS_DICTIONARY_INVALID;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_COMPOSITE;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_MMTYPE;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_TRUETYPE;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_TYPE0;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_TYPE0C;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_TYPE1;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_TYPE1C;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_TYPE2;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_TYPE3;
+
+import org.apache.padaf.preflight.DocumentHandler;
+import org.apache.padaf.preflight.ValidationException;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSObject;
+
+/**
+ * This class returns a FontValidator object according to the Font dictionary.
+ */
+public class FontValidatorFactory {
+
+  public FontValidator getFontValidator(COSObject cObj,
+      DocumentHandler handler) throws ValidationException {
+    COSDictionary dic = (COSDictionary) cObj.getObject();
+    String type = dic.getNameAsString(COSName.getPDFName(DICTIONARY_KEY_TYPE));
+    String subtype = dic.getNameAsString(COSName
+        .getPDFName(DICTIONARY_KEY_SUBTYPE));
+
+    if ((type == null || "".equals(type))
+        || (subtype == null || "".equals(subtype))) {
+      throw new ValidationException("Type and/or Subtype keys are missing : "
+          + ERROR_FONTS_DICTIONARY_INVALID);
+    } else {
+      if (FONT_DICTIONARY_VALUE_TRUETYPE.equals(subtype)) {
+        return new TrueTypeFontValidator(handler, cObj);
+      } else if (FONT_DICTIONARY_VALUE_MMTYPE.equals(subtype)
+          || FONT_DICTIONARY_VALUE_TYPE1.equals(subtype)) {
+        return new Type1FontValidator(handler, cObj);
+      } else if (FONT_DICTIONARY_VALUE_TYPE3.equals(subtype)) {
+        return new Type3FontValidator(handler, cObj);
+      } else if (FONT_DICTIONARY_VALUE_COMPOSITE.equals(subtype)) {
+       return new CompositeFontValidator(handler, cObj);
+      } else if (FONT_DICTIONARY_VALUE_TYPE2.equals(subtype)
+          || FONT_DICTIONARY_VALUE_TYPE1C.equals(subtype)
+          || FONT_DICTIONARY_VALUE_TYPE0C.equals(subtype)
+          || FONT_DICTIONARY_VALUE_TYPE0.equals(subtype)) {
+        // ---- Font managed by a Composite font.
+        // this dictionary will be checked by a CompositeFontValidator
+        return null;
+      } else {
+        throw new ValidationException("Unknown font type : " + subtype);
+      }
+    }
+  }
+}

Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/FontValidatorFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/GlyphDetail.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/GlyphDetail.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/GlyphDetail.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/GlyphDetail.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ ****************************************************************************/
+
+package org.apache.padaf.preflight.font;
+
+public class GlyphDetail {
+	private GlyphException invalidGlyphError = null;
+	private int charecterIdentifier = 0;
+	
+	public GlyphDetail(int cid) {
+		this.charecterIdentifier = cid;
+	}
+
+	public GlyphDetail(int cid, GlyphException error) {
+		this.charecterIdentifier = cid;
+		this.invalidGlyphError = error;
+	}
+
+	public void throwExceptionIfNotValid() throws GlyphException {
+		if (this.invalidGlyphError != null) {
+			throw this.invalidGlyphError;
+		}
+	}
+
+	public int getCID() {
+		return this.charecterIdentifier;
+	}
+}

Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/GlyphDetail.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/GlyphException.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/GlyphException.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/GlyphException.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/GlyphException.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ ****************************************************************************/
+
+package org.apache.padaf.preflight.font;
+
+public class GlyphException extends Exception {
+	private String errorCode;
+	private int invalidCid;
+	
+	public GlyphException(String code, int cid) {
+		super();
+		this.errorCode = code;
+		this.invalidCid = cid;
+	}
+
+	public GlyphException(String code, int cid, String message) {
+		super(message);
+		this.errorCode = code;
+		this.invalidCid = cid;
+	}
+	
+	public String getErrorCode() {
+		return errorCode;
+	}
+
+	public int getInvalidCid() {
+		return invalidCid;
+	}
+
+}

Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/GlyphException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/PDFAType3StreamParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/PDFAType3StreamParser.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/PDFAType3StreamParser.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/PDFAType3StreamParser.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,168 @@
+/*****************************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ ****************************************************************************/
+
+package org.apache.padaf.preflight.font;
+
+import java.awt.Image;
+import java.io.IOException;
+import java.util.List;
+
+
+import org.apache.fontbox.util.BoundingBox;
+import org.apache.padaf.preflight.DocumentHandler;
+import org.apache.padaf.preflight.utils.ContentStreamEngine;
+import org.apache.pdfbox.cos.COSFloat;
+import org.apache.pdfbox.cos.COSInteger;
+import org.apache.pdfbox.cos.COSNumber;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDInlinedImage;
+import org.apache.pdfbox.util.ImageParameters;
+import org.apache.pdfbox.util.PDFOperator;
+
+/**
+ * This class is used to parse a glyph of a Type3 font program. If the glyph is
+ * parsed without error, the width of the glyph is accessible through the
+ * getWidth method.
+ */
+public class PDFAType3StreamParser extends ContentStreamEngine {
+  private boolean firstOperator = true;
+  private float width = 0;
+
+  private PDInlinedImage image = null;
+  private BoundingBox box = null;
+
+  public PDFAType3StreamParser(DocumentHandler handler) {
+    super(handler);
+  }
+
+  /**
+   * This will parse a type3 stream and create an image from it.
+   * 
+   * @param type3Stream
+   *          The stream containing the operators to draw the image.
+   * 
+   * @return The image that was created.
+   * 
+   * @throws IOException
+   *           If there is an error processing the stream.
+   */
+  public Image createImage(COSStream type3Stream) throws IOException {
+  	resetEngine();
+    processSubStream(null, null, type3Stream);
+    return image.createImage();
+  }
+
+  /**
+   * This is used to handle an operation.
+   * 
+   * @param operator
+   *          The operation to perform.
+   * @param arguments
+   *          The list of arguments.
+   * 
+   * @throws IOException
+   *           If there is an error processing the operation.
+   */
+  protected void processOperator(PDFOperator operator, List arguments)
+      throws IOException {
+    super.processOperator(operator, arguments);
+    String operation = operator.getOperation();
+
+    if (operation.equals("BI")) {
+      ImageParameters params = operator.getImageParameters();
+      image = new PDInlinedImage();
+      image.setImageParameters(params);
+      image.setImageData(operator.getImageData());
+
+      validImageFilter(operator);
+      validImageColorSpace(operator);
+    }
+
+    if (operation.equals("d0")) {
+      // set glyph with for a type3 font
+      // COSNumber horizontalWidth = (COSNumber)arguments.get( 0 );
+      // COSNumber verticalWidth = (COSNumber)arguments.get( 1 );
+      // width = horizontalWidth.intValue();
+      // height = verticalWidth.intValue();
+
+      checkType3FirstOperator(arguments);
+
+    } else if (operation.equals("d1")) {
+      // set glyph with and bounding box for type 3 font
+      // COSNumber horizontalWidth = (COSNumber)arguments.get( 0 );
+      // COSNumber verticalWidth = (COSNumber)arguments.get( 1 );
+      COSNumber llx = (COSNumber) arguments.get(2);
+      COSNumber lly = (COSNumber) arguments.get(3);
+      COSNumber urx = (COSNumber) arguments.get(4);
+      COSNumber ury = (COSNumber) arguments.get(5);
+
+      // width = horizontalWidth.intValue();
+      // height = verticalWidth.intValue();
+      box = new BoundingBox();
+      box.setLowerLeftX(llx.floatValue());
+      box.setLowerLeftY(lly.floatValue());
+      box.setUpperRightX(urx.floatValue());
+      box.setUpperRightY(ury.floatValue());
+
+      checkType3FirstOperator(arguments);
+    }
+
+    checkColorOperators(operation);
+    validRenderingIntent(operator, arguments);
+    checkSetColorSpaceOperators(operator, arguments);
+    validNumberOfGraphicStates(operator);
+    firstOperator = false;
+  }
+
+  /**
+   * According to the PDF Reference, the first operator in a CharProc of a Type3
+   * font must be "d0" or "d1". This method process this validation. This method
+   * is called by the processOperator method.
+   * 
+   * @param arguments
+   * @throws IOException
+   */
+  private void checkType3FirstOperator(List arguments) throws IOException {
+    if (!firstOperator) {
+      throw new IOException("Type3 CharProc : First operator must be d0 or d1");
+    }
+
+    Object obj = arguments.get(0);
+    if (obj instanceof Number) {
+      width = ((Number) obj).intValue();
+    } else if (obj instanceof COSInteger) {
+      width = ((COSInteger) obj).floatValue();
+    } else if (obj instanceof COSFloat) {
+    	width = ((COSFloat)obj).floatValue();
+    } else {
+      throw new IOException(
+          "Unexpected argument type. Expected : COSInteger or Number / Received : "
+              + obj.getClass().getName());
+    }
+  }
+
+  /**
+   * @return the width of the CharProc glyph description
+   */
+  public float getWidth() {
+    return this.width;
+  }
+}

Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/PDFAType3StreamParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/SimpleFontValidator.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/SimpleFontValidator.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/SimpleFontValidator.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/SimpleFontValidator.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,269 @@
+/*****************************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ ****************************************************************************/
+
+package org.apache.padaf.preflight.font;
+
+
+import org.apache.padaf.preflight.DocumentHandler;
+import org.apache.padaf.preflight.ValidationConstants;
+import org.apache.padaf.preflight.ValidationException;
+import org.apache.padaf.preflight.ValidationResult;
+import org.apache.padaf.preflight.ValidationResult.ValidationError;
+import org.apache.padaf.preflight.utils.COSUtils;
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSDocument;
+import org.apache.pdfbox.cos.COSInteger;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSObject;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+
+public abstract class SimpleFontValidator extends AbstractFontValidator {
+  protected String basefont;
+  protected COSBase firstChar;
+  protected COSBase lastChar;
+  protected COSBase widths;
+  protected COSBase encoding;
+  protected COSBase toUnicode;
+  /**
+   * The PdfBox font descriptor dictionary wrapper.
+   */
+  protected PDFontDescriptorDictionary pFontDesc = null;
+  /**
+   * The font descriptor dictionary linked with the font dictionary
+   */
+  protected COSDictionary fDescriptor = null;
+
+  public SimpleFontValidator(DocumentHandler handler, COSObject obj)
+      throws ValidationException {
+    super(handler, obj);
+    COSBase tmpFontDesc = fDictionary.getItem(COSName
+        .getPDFName(FONT_DICTIONARY_KEY_FONT_DESC));
+    this.fDescriptor = COSUtils.getAsDictionary(tmpFontDesc, handler
+        .getDocument().getDocument());
+    if (this.fDescriptor != null) {
+      this.pFontDesc = new PDFontDescriptorDictionary(this.fDescriptor);
+    }
+  }
+
+  /**
+   * Extract element from the COSObject to avoid useless access to this object.
+   */
+  private void extractElementsToCheck() {
+    // ---- Here is required elements
+    this.basefont = fDictionary.getNameAsString(COSName
+        .getPDFName(FONT_DICTIONARY_KEY_BASEFONT));
+    this.firstChar = fDictionary.getItem(COSName
+        .getPDFName(FONT_DICTIONARY_KEY_FIRSTCHAR));
+    this.lastChar = fDictionary.getItem(COSName
+        .getPDFName(FONT_DICTIONARY_KEY_LASTCHAR));
+    this.widths = fDictionary.getItem(COSName
+        .getPDFName(FONT_DICTIONARY_KEY_WIDTHS));
+    // ---- Here is optional elements
+    this.encoding = fDictionary.getItem(COSName
+        .getPDFName(FONT_DICTIONARY_KEY_ENCODING));
+    this.toUnicode = fDictionary.getItem(COSName
+        .getPDFName(FONT_DICTIONARY_KEY_TOUNICODE));
+  }
+
+  /**
+   * Check if All required fields of a Font Dictionary are present. If there are
+   * some missing fields, this method returns false and the FontContainer is
+   * updated.
+   * 
+   * @return
+   */
+  protected boolean checkMandatoryFields() {
+    String type = fDictionary.getNameAsString(COSName
+        .getPDFName(DICTIONARY_KEY_TYPE));
+    String subtype = fDictionary.getNameAsString(COSName
+        .getPDFName(DICTIONARY_KEY_SUBTYPE));
+
+    if (this.fDescriptor == null) {
+      this.fontContainer
+          .addError(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID,
+              "The FontDescriptor is missing, so the Font Program isn't embedded."));
+      this.fontContainer.setFontProgramEmbedded(false);
+      return false;
+    }
+
+    if ((type == null || "".equals(type))
+        || (subtype == null || "".equals(subtype))) {
+      this.fontContainer.addError(new ValidationError(
+          ERROR_FONTS_DICTIONARY_INVALID,
+          "Type and/or Subtype keys are missing"));
+      return false;
+    } else {
+      extractElementsToCheck();
+      // ---- according to the subtype, the validation process isn't the same.
+      return checkSpecificMandatoryFields();
+    }
+  }
+
+  /**
+   * This method checks the presence of some fields according to the Font type
+   * 
+   * @return
+   */
+  protected abstract boolean checkSpecificMandatoryFields();
+
+  /**
+   * Check if the widths array contains integer and if its length is valid. If
+   * the validation fails, the FontContainer is updated.
+   * 
+   * @param cDoc
+   */
+  protected boolean checkWidthsArray(COSDocument cDoc) {
+    // ---- the Widths value can be a reference to an object
+    // ---- Access the object using the COSkey
+    COSArray wArr = COSUtils.getAsArray(this.widths, cDoc);
+
+    if (wArr == null) {
+      this.fontContainer.addError(new ValidationError(
+          ERROR_FONTS_DICTIONARY_INVALID, "The Witdhs array is unreachable"));
+      return false;
+    }
+
+    // ---- firstChar and lastChar must be integer.
+    int fc = ((COSInteger) this.firstChar).intValue();
+    int lc = ((COSInteger) this.lastChar).intValue();
+
+    // ---- wArr length = (lc - fc) +1 and it is an array of int.
+    // ---- If FirstChar is greater than LastChar, the validation will fail
+    // because of
+    // ---- the array will have an expected size <= 0.
+    int expectedLength = (lc - fc) + 1;
+    if (wArr.size() != expectedLength) {
+      this.fontContainer.addError(new ValidationError(
+          ERROR_FONTS_DICTIONARY_INVALID,
+          "The length of Witdhs array is invalid. Expected : \""
+              + expectedLength + "\" Current : \"" + wArr.size() + "\""));
+      return false;
+    }
+
+    for (Object arrContent : wArr.toList()) {
+      boolean isInt = false;
+      if (arrContent instanceof COSBase) {
+        isInt = COSUtils.isInteger((COSBase) arrContent, cDoc);
+      }
+
+      if (!isInt) {
+        this.fontContainer.addError(new ValidationError(
+            ERROR_FONTS_DICTIONARY_INVALID,
+            "The Witdhs array is invalid. (some element aren't integer)"));
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  protected boolean checkEncoding(COSDocument cDoc) {
+    return true;
+  }
+
+  protected boolean checkToUnicode(COSDocument cDoc) {
+    // Check the toUnicode -- Useless for PDF/A 1-b
+    return true;
+  }
+
+  /**
+   * This method checks the font descriptor dictionary and embedded font files.
+   * If the FontDescriptor validation fails, the FontContainer is updated.
+   * 
+   * @return
+   */
+  protected abstract boolean checkFontDescriptor() throws ValidationException;
+
+  /**
+   * Check if all required fields are present in the PDF file to describe the
+   * Font Descriptor. If validation fails, FontConatiner is updated and false is
+   * returned.
+   */
+  protected boolean checkFontDescriptorMandatoryFields() {
+    boolean fname = false, flags = false, itangle = false, cheight = false;
+    boolean fbbox = false, asc = false, desc = false, stemv = false;
+
+    for (Object key : this.fDescriptor.keySet()) {
+      if (!(key instanceof COSName)) {
+        this.fontContainer.addError(new ValidationResult.ValidationError(
+            ValidationConstants.ERROR_SYNTAX_DICTIONARY_KEY_INVALID,
+            "Invalid key in The font descriptor"));
+        return false;
+      }
+
+      String cosName = ((COSName) key).getName();
+      if (cosName.equals(FONT_DICTIONARY_KEY_FONTNAME)) {
+        fname = true;
+      }
+      if (cosName.equals(FONT_DICTIONARY_KEY_FLAGS)) {
+        flags = true;
+      }
+      if (cosName.equals(FONT_DICTIONARY_KEY_ITALICANGLE)) {
+        itangle = true;
+      }
+      if (cosName.equals(FONT_DICTIONARY_KEY_CAPHEIGHT)) {
+        cheight = true;
+      }
+      if (cosName.equals(FONT_DICTIONARY_KEY_FONTBBOX)) {
+        fbbox = true;
+      }
+      if (cosName.equals(FONT_DICTIONARY_KEY_ASCENT)) {
+        asc = true;
+      }
+      if (cosName.equals(FONT_DICTIONARY_KEY_DESCENT)) {
+        desc = true;
+      }
+      if (cosName.equals(FONT_DICTIONARY_KEY_STEMV)) {
+        stemv = true;
+      }
+    }
+
+    if (!(fname && flags && itangle && cheight && fbbox && asc && desc && stemv)) {
+      this.fontContainer.addError(new ValidationError(
+          ERROR_FONTS_DESCRIPTOR_INVALID, "Some mandatory fields are missing"));
+      return false;
+    }
+
+    return true;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * net.awl.edoc.pdfa.validation.font.FontValidator#validate(java.util.List)
+   */
+  public boolean validate() throws ValidationException {
+    COSDocument cDoc = handler.getDocument().getDocument();
+    if (!checkMandatoryFields()) {
+      return false;
+    }
+
+    boolean result = true;
+    result = result && checkWidthsArray(cDoc);
+    result = result && checkFontDescriptor();
+    result = result && checkEncoding(cDoc);
+    result = result && checkToUnicode(cDoc);
+    return result;
+  }
+}

Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/SimpleFontValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/TrueTypeFontContainer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/TrueTypeFontContainer.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/TrueTypeFontContainer.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/TrueTypeFontContainer.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,175 @@
+/*****************************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ ****************************************************************************/
+
+package org.apache.padaf.preflight.font;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+
+import org.apache.fontbox.ttf.CMAPEncodingEntry;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.padaf.preflight.ValidationConstants;
+import org.apache.pdfbox.cos.COSInteger;
+import org.apache.pdfbox.encoding.Encoding;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+
+public class TrueTypeFontContainer extends AbstractFontContainer {
+	private List<?> widthsArray = new ArrayList(0);
+	private int firstCharInWidthsArray = 0;
+
+	/**
+	 * Represent the missingWidth value of the FontDescriptor dictionary.
+	 * According to the PDF Reference, if this value is missing, the default 
+	 * one is 0.
+	 */
+	private float defaultGlyphWidth = 0;
+	/**
+	 * Object which contains the TrueType font data extracted by the
+	 * TrueTypeParser object
+	 */
+	private TrueTypeFont fontObject = null;
+	private CMAPEncodingEntry cmap = null;
+
+	private int numberOfLongHorMetrics;
+	private int unitsPerEm;
+	private int[] glyphWidths;
+
+	public TrueTypeFontContainer(PDFont fd) {
+		super(fd);
+	}
+
+	void setWidthsArray(List<?> widthsArray) {
+		this.widthsArray = widthsArray;
+	}
+
+	void setFirstCharInWidthsArray(int firstCharInWidthsArray) {
+		this.firstCharInWidthsArray = firstCharInWidthsArray;
+	}
+
+	void setDefaultGlyphWidth(float defaultGlyphWidth) {
+		this.defaultGlyphWidth = defaultGlyphWidth;
+	}
+
+	void setFontObjectAndInitializeInnerFields(TrueTypeFont fontObject) {
+		this.fontObject = fontObject;
+		this.unitsPerEm = this.fontObject.getHeader().getUnitsPerEm();
+		this.glyphWidths = this.fontObject.getHorizontalMetrics().getAdvanceWidth();
+		// ---- In a Mono space font program, the length of the AdvanceWidth array must be one.
+		// ---- According to the TrueType font specification, the Last Value of the AdvanceWidth array
+		// ---- is apply to the subsequent glyphs. So if the GlyphId is greater than the length of the array
+		// ---- the last entry is used.
+		this.numberOfLongHorMetrics = this.fontObject.getHorizontalHeader().getNumberOfHMetrics();
+	}
+
+	void setCMap(CMAPEncodingEntry cmap) {
+		this.cmap = cmap;
+	}
+
+	@Override
+	public void checkCID(int cid) throws GlyphException {
+		if (isAlreadyComputedCid(cid)) {
+			return;
+		}
+
+		int indexOfWidth = (cid - firstCharInWidthsArray);
+		float widthProvidedByPdfDictionary = this.defaultGlyphWidth;
+		float widthInFontProgram ;
+
+		int innerFontCid = cid;
+		if (cmap.getPlatformEncodingId() == 1 && cmap.getPlatformId() == 3) {
+			try {
+				Encoding fontEncoding = this.font.getFontEncoding();
+				String character = fontEncoding.getCharacter(cid);
+				if (character == null) {
+					GlyphException e = new GlyphException(ValidationConstants.ERROR_FONTS_GLYPH_MISSING, 
+							cid, 
+							"The character \"" + cid 
+							+ "\" in the font program \""
+							+ this.font.getBaseFont() 
+							+ "\"is missing from the Charater Encoding.");
+					addKnownCidElement(new GlyphDetail(cid, e));
+					throw e;	
+				}
+
+				char[] characterArray = character.toCharArray();
+				if (characterArray.length == 1 ) {
+					innerFontCid = (int)characterArray[0];
+				} else {
+					// TODO OD-PDFA-87 A faire?
+					innerFontCid = (int)characterArray[0];
+					for (int i = 1; i < characterArray.length; ++i) {
+						if (cmap.getGlyphId((int)characterArray[i]) == 0) {
+							GlyphException e = new GlyphException(ValidationConstants.ERROR_FONTS_GLYPH_MISSING, 
+									cid, 
+									"A glyph for the character \"" + cid 
+									+ "\" in the font program \""
+									+ this.font.getBaseFont() 
+									+ "\"is missing. There are " + characterArray.length + " glyph used by this character...");
+							addKnownCidElement(new GlyphDetail(cid, e));
+							throw e;	
+						}
+					}
+				}
+			} catch (IOException ioe) {
+				GlyphException e = new GlyphException(ValidationConstants.ERROR_FONTS_ENCODING_IO, 
+						cid, 
+						"Unable to get the encoding object from the PDFont object during the validation of cid \"" + cid 
+						+ "\" in the font program \""
+						+ this.font.getBaseFont() 
+						+ "\".");
+				addKnownCidElement(new GlyphDetail(cid, e));
+				throw e;	
+			}
+		}
+
+		// search glyph
+		int glyphId = cmap.getGlyphId(innerFontCid);
+		if (glyphId == 0) {
+			GlyphException e = new GlyphException(ValidationConstants.ERROR_FONTS_GLYPH_MISSING, 
+					cid, 
+					"Glyph for the character \"" + cid 
+					+ "\" in the font program \""
+					+ this.font.getBaseFont() 
+					+ "\"is missing.");
+			addKnownCidElement(new GlyphDetail(cid, e));
+			throw e;	
+		}
+
+		// compute glyph width
+		float glypdWidth = glyphWidths[numberOfLongHorMetrics - 1];
+		if (glyphId < numberOfLongHorMetrics) {
+			glypdWidth = glyphWidths[glyphId];
+		}
+		widthInFontProgram = ((glypdWidth * 1000) / unitsPerEm);
+
+		// search width in the PDF file
+		if (indexOfWidth >= 0 && indexOfWidth < this.widthsArray.size()) {
+			COSInteger w = (COSInteger)this.widthsArray.get(indexOfWidth);
+			widthProvidedByPdfDictionary = w.intValue(); 
+		}
+
+		checkWidthsConsistency(cid, widthProvidedByPdfDictionary, widthInFontProgram);
+		addKnownCidElement(new GlyphDetail(cid));
+	}
+
+}
\ No newline at end of file

Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/TrueTypeFontContainer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/TrueTypeFontValidator.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/TrueTypeFontValidator.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/TrueTypeFontValidator.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/TrueTypeFontValidator.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,296 @@
+/*****************************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ ****************************************************************************/
+
+package org.apache.padaf.preflight.font;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.List;
+
+
+import org.apache.commons.io.IOUtils;
+import org.apache.fontbox.ttf.CMAPEncodingEntry;
+import org.apache.fontbox.ttf.CMAPTable;
+import org.apache.fontbox.ttf.TTFParser;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.padaf.preflight.DocumentHandler;
+import org.apache.padaf.preflight.ValidationConstants;
+import org.apache.padaf.preflight.ValidationException;
+import org.apache.padaf.preflight.ValidationResult;
+import org.apache.padaf.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSObject;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.encoding.Encoding;
+import org.apache.pdfbox.encoding.MacRomanEncoding;
+import org.apache.pdfbox.encoding.WinAnsiEncoding;
+import org.apache.pdfbox.pdmodel.common.COSArrayList;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+
+public class TrueTypeFontValidator extends SimpleFontValidator {
+	/**
+	 * @param handler
+	 * @param obj
+	 */
+	public TrueTypeFontValidator(DocumentHandler handler, COSObject obj)
+	throws ValidationException {
+		super(handler, obj);
+	}
+
+	/**
+	 * Check if mandatory fields are present. Return false if a field is missing,
+	 * true otherwise. If validation fails, the FontContainer is updated.
+	 */
+	protected boolean checkSpecificMandatoryFields() {
+		// ---- name is required only in a PDF-1.0.
+		// ---- Currently our grammar matches only with PDF-1.[1-4]
+		// ---- BaseFont is required and is usually the FontName
+		if (basefont == null || "".equals(basefont)) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID, "BaseFont is missing"));
+			// continue to process this font dictionary is useless
+			return false;
+		}
+
+		boolean allPresent = (firstChar != null && lastChar != null && widths != null);
+		if (!allPresent) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID, "Required keys are missing"));
+			return false;
+		} // else  ok
+
+
+		return true;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * net.awl.edoc.pdfa.validation.font.SimpleFontValidator#checkFontDescriptor()
+	 */
+	@Override
+	protected boolean checkFontDescriptor() throws ValidationException {
+		boolean res = checkFontDescriptorMandatoryFields();
+		res = res && checkFontName();
+		res = res && checkFontFileElement();
+		return res;
+	}
+
+	/**
+	 * If the FontName is missing from the FontDescriptor dictionary, this method
+	 * returns false and the FontContainer is updated.
+	 * 
+	 * @return
+	 */
+	protected boolean checkFontName() {
+		String fontName = this.pFontDesc.getFontName();
+		if (fontName == null) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ValidationConstants.ERROR_FONTS_DESCRIPTOR_INVALID,
+					"The FontName in font descriptor is null"));
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * This methods validates the Font Stream. If the font is damaged or missing
+	 * the FontContainer is updated and false is returned. Moreover, this method
+	 * checks the Encoding property of the FontDescriptor dictionary.
+	 * 
+	 * @return
+	 */
+	protected boolean checkFontFileElement() throws ValidationException {
+		PDStream ff1 = pFontDesc.getFontFile();
+		PDStream ff2 = pFontDesc.getFontFile2();
+		PDStream ff3 = pFontDesc.getFontFile3();
+		boolean onlyOne = (ff1 != null && ff2 == null && ff3 == null)
+		|| (ff1 == null && ff2 != null && ff3 == null)
+		|| (ff1 == null && ff2 == null && ff3 != null);
+
+		if (ff2 == null || !onlyOne) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ValidationConstants.ERROR_FONTS_FONT_FILEX_INVALID,
+					"The FontFile2 is invalid"));
+			return false;
+		}
+
+		// ---- Stream validation should be done by the StreamValidateHelper.
+		// ---- Process font specific check
+		COSStream stream = ff2.getStream();
+		if (stream == null) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ValidationConstants.ERROR_FONTS_FONT_FILEX_INVALID,
+					"The FontFile is missing"));
+			this.fontContainer.setFontProgramEmbedded(false);
+			return false;
+		}
+
+		boolean hasLength1 = stream.getInt(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_LENGTH1)) > 0;
+				if (!hasLength1) {
+					this.fontContainer.addError(new ValidationResult.ValidationError(
+							ValidationConstants.ERROR_FONTS_FONT_FILEX_INVALID,
+							"The FontFile is invalid"));
+					return false;
+				}
+
+				// ---- check the encoding part.
+					if (pFontDesc.isNonSymbolic()) {
+						// ---- only MacRomanEncoding or WinAnsiEncoding are allowed for a non
+						// symbolic font
+						Encoding encodingValue = this.pFont.getFontEncoding();
+						if (encodingValue == null
+								|| !(encodingValue instanceof MacRomanEncoding || encodingValue instanceof WinAnsiEncoding)) {
+							this.fontContainer.addError(new ValidationResult.ValidationError(
+									ValidationConstants.ERROR_FONTS_ENCODING,
+									"The Encoding is invalid for the NonSymbolic TTF"));
+							return false;
+						}
+					} else if (pFontDesc.isSymbolic()) {
+						// ---- For symbolic font, no encoding entry is allowed and only one
+						// encoding entry is expected into the FontFile CMap
+						if (((COSDictionary) this.fDictionary.getCOSObject()).getItem(COSName
+								.getPDFName(FONT_DICTIONARY_KEY_ENCODING)) != null) {
+							this.fontContainer.addError(new ValidationResult.ValidationError(
+									ValidationConstants.ERROR_FONTS_ENCODING,
+									"The Encoding should be missing for the Symbolic TTF"));
+							return false;
+						} // else check the content of the Font CMap (see below)
+
+					} else {
+						// ----- should never happen
+						return true;
+					}
+
+				/*
+				 * ---- try to load the font using the TTFParser object. If the font is
+				 * invalid, an exception will be thrown. Because of it is a Embedded Font
+				 * Program, some tables are required and other are optional see PDF
+				 * Reference (§5.8)
+				 */
+				ByteArrayInputStream bis = null;
+				try {
+					bis = new ByteArrayInputStream(ff2.getByteArray());
+					TrueTypeFont ttf = new TTFParser(true).parseTTF(bis);
+					if (pFontDesc.isSymbolic() && ttf.getCMAP().getCmaps().length != 1) {
+						this.fontContainer.addError(new ValidationResult.ValidationError(
+								ValidationConstants.ERROR_FONTS_ENCODING,
+								"The Encoding should be missing for the Symbolic TTF"));
+						return false;
+					}
+
+					return checkFontMetrics(ttf) && checkFontFileMetaData(pFontDesc, ff2);
+				} catch (IOException e) {
+					this.fontContainer.addError(new ValidationResult.ValidationError(
+							ValidationConstants.ERROR_FONTS_TRUETYPE_DAMAGED,
+							"The FontFile can't be read"));
+					return false;
+				} finally {
+					if (bis != null) {
+						IOUtils.closeQuietly(bis);
+					}
+				}
+	}
+
+	/**
+	 * This method checks the metric consistency. If the validation fails, the
+	 * FontContainer is updated. If the validation is a success, the
+	 * FontContainer.cidKnownByFont map is updated.
+	 * 
+	 * @param ttf
+	 * @return
+	 * @throws IOException
+	 */
+	protected boolean checkFontMetrics(TrueTypeFont ttf) throws IOException,
+	ValidationException {
+
+		int firstChar = pFont.getFirstChar();
+		float defaultGlyphWidth = this.pFontDesc.getMissingWidth();
+
+		List<?> pdfWidths = this.pFont.getWidths();
+		COSArray widths = null;
+		if (pdfWidths instanceof COSArrayList) {
+			widths = ((COSArrayList) pdfWidths).toList();
+		} else {
+			widths = ((COSArray) pdfWidths);
+		}
+
+		((TrueTypeFontContainer)this.fontContainer).setWidthsArray(widths.toList());
+		((TrueTypeFontContainer)this.fontContainer).setFirstCharInWidthsArray(firstChar);
+		((TrueTypeFontContainer)this.fontContainer).setDefaultGlyphWidth(defaultGlyphWidth);
+		((TrueTypeFontContainer)this.fontContainer).setFontObjectAndInitializeInnerFields(ttf);
+		((TrueTypeFontContainer)this.fontContainer).setCMap(getCMapOfFontProgram(ttf));
+
+		return true;
+	}
+
+	/**
+	 * Return the CMap encoding entry to use. This CMap belong to the TrueType
+	 * Font Program.
+	 * 
+	 * Here the selection rules :
+	 * <UL>
+	 * <li>For a Symbolic TrueType, the Font Program has only one CMap (Checked in
+	 * the checkFontFileElement method)
+	 * <li>For a Non-Symbolic TrueType, only two CMap can be used (WinAnsi
+	 * (plateformId : 3 / encodingId : 1) or MacRoman (plateformId : 1 /
+	 * encodingId : 0) ). This CMap returns the CMap which corresponds to the
+	 * Encoding value of the FontDescriptor dictionary.
+	 * </UL>
+	 * 
+	 * @param ttf
+	 *          The FontBox object which manages a TrueType Font program.
+	 * @return
+	 * @throws ValidationException
+	 *           if the FontProgram doesn't have the expected CMap
+	 */
+	protected CMAPEncodingEntry getCMapOfFontProgram(TrueTypeFont ttf)
+	throws ValidationException {
+		CMAPTable cmap = ttf.getCMAP();
+		if (this.pFontDesc.isSymbolic()) {
+			return cmap.getCmaps()[0];
+		} else {
+				if (this.pFont.getFontEncoding() instanceof WinAnsiEncoding) {
+					for (CMAPEncodingEntry cmapEntry : cmap.getCmaps()) {
+						// ---- Returns the WinAnsiEncoding CMap
+						if ((cmapEntry.getPlatformId() == 3)
+								&& (cmapEntry.getPlatformEncodingId() == 1)) {
+							return cmapEntry;
+						}
+					}
+				} else {
+					// ---- Returns the MacRomanEncoding CMap
+					for (CMAPEncodingEntry cmapEntry : cmap.getCmaps()) {
+						if ((cmapEntry.getPlatformId() == 1)
+								&& (cmapEntry.getPlatformEncodingId() == 0)) {
+							return cmapEntry;
+						}
+					}
+				}
+		}
+
+		throw new ValidationException("CMap not found in the TrueType FontProgam");
+	}
+}

Propchange: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/TrueTypeFontValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native