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 2012/07/14 21:53:50 UTC

svn commit: r1361579 [2/3] - in /pdfbox/trunk: pdfbox/src/main/java/org/apache/pdfbox/cos/ preflight/src/main/java/org/apache/padaf/preflight/contentstream/ preflight/src/main/java/org/apache/pdfbox/preflight/ preflight/src/main/java/org/apache/pdfbox/...

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/Type3FontValidator.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/Type3FontValidator.java?rev=1361579&r1=1361578&r2=1361579&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/Type3FontValidator.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/Type3FontValidator.java Sat Jul 14 19:53:48 2012
@@ -21,16 +21,20 @@
 
 package org.apache.pdfbox.preflight.font;
 
-
 import static org.apache.pdfbox.preflight.PreflightConfiguration.RESOURCES_PROCESS;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_DICTIONARY_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_ENCODING;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_METRICS;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_TYPE3_DAMAGED;
 
 import java.io.IOException;
+import java.util.List;
 import java.util.Set;
 
 import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSInteger;
+import org.apache.pdfbox.cos.COSDocument;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.encoding.DictionaryEncoding;
@@ -40,157 +44,115 @@ import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDResources;
 import org.apache.pdfbox.pdmodel.font.PDFont;
 import org.apache.pdfbox.pdmodel.font.PDFontFactory;
-import org.apache.pdfbox.pdmodel.font.PDType3Font;
+import org.apache.pdfbox.preflight.PreflightConstants;
 import org.apache.pdfbox.preflight.PreflightContext;
 import org.apache.pdfbox.preflight.PreflightPath;
 import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
 import org.apache.pdfbox.preflight.content.ContentStreamException;
 import org.apache.pdfbox.preflight.exception.ValidationException;
+import org.apache.pdfbox.preflight.font.container.FontContainer;
+import org.apache.pdfbox.preflight.font.container.Type3Container;
+import org.apache.pdfbox.preflight.font.util.GlyphException;
+import org.apache.pdfbox.preflight.font.util.PDFAType3StreamParser;
 import org.apache.pdfbox.preflight.utils.COSUtils;
 import org.apache.pdfbox.preflight.utils.ContextHelper;
 
-public class Type3FontValidator extends AbstractFontValidator {
-	protected PDType3Font pdType3 = null;
-
-	protected COSBase fontBBox = null;
-	protected COSBase fontMatrix = null;
-	protected COSBase charProcs = null;
-	protected COSBase fontEncoding = null;
-	protected COSBase firstChar = null;
-	protected COSBase lastChar = null;
-	protected COSBase widths = null;
-	protected COSBase toUnicode = null;
-	protected COSBase resources = null;
-
-	protected Encoding type3Encoding = null;
-
-
-	public Type3FontValidator(PreflightContext context, PDFont font)
-			throws ValidationException {
-		super(context, font);
-		this.pdType3 = (PDType3Font) this.pFont;
+public class Type3FontValidator extends FontValidator<Type3Container> {
+	protected COSDictionary fontDictionary;
+	protected COSDocument cosDocument;
+	protected Encoding encoding;
+
+	public Type3FontValidator(PreflightContext context, PDFont font) {
+		super(context, font, new Type3Container(font));
+		this.cosDocument = context.getDocument().getDocument();
+		this.fontDictionary = (COSDictionary)font.getCOSObject();
 	}
 
-	/**
-	 * This methods stores in attributes all required element. We extract these
-	 * elements because of the PDType3Font object returns sometime default value
-	 * if the field is missing, so to avoid mistake during required field
-	 * validation we store them.
-	 */
-	private void extractFontDictionaryEntries() {
-		COSDictionary fDictionary = (COSDictionary)this.pFont.getCOSObject();
-		// ---- required elements
-		this.fontBBox = fDictionary.getItem(COSName
-				.getPDFName(FONT_DICTIONARY_KEY_FONTBBOX));
-		this.fontMatrix = fDictionary.getItem(COSName
-				.getPDFName(FONT_DICTIONARY_KEY_FONTMATRIX));
-		this.charProcs = fDictionary.getItem(COSName
-				.getPDFName(FONT_DICTIONARY_KEY_CHARPROCS));
-		this.fontEncoding = fDictionary.getItem(COSName
-				.getPDFName(FONT_DICTIONARY_KEY_ENCODING));
-		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));
-
-		// ---- Optional elements
-		this.toUnicode = fDictionary.getItem(COSName.TO_UNICODE);
-		this.resources = fDictionary.getItem(COSName.RESOURCES);
+	public void validate() throws ValidationException {
+		checkMandatoryField();
+		checkFontBBox();
+		checkFontMatrix();
+		checkEncoding();
+		checkResources();
+		checkCharProcsAndMetrics();
+		checkToUnicode();
 	}
 
-	/**
-	 * Returns true if all required fields are present. Otherwise, this method
-	 * returns false and the FontContainer is updated.
-	 * 
-	 * @return
-	 */
-	private boolean checkMandatoryFields() {
-		boolean all = (this.fontBBox != null);
-		all = all && (this.fontMatrix != null);
-		all = all && (this.charProcs != null);
-		all = all && (this.fontEncoding != null);
-		all = all && (this.firstChar != null);
-		all = all && (this.lastChar != null);
-		all = all && (this.widths != null);
-		if (!all) {
-			this.fontContainer.addError(new ValidationError(
-					ERROR_FONTS_DICTIONARY_INVALID));
-		}
+	protected void checkMandatoryField() {
+		boolean areFieldsPResent = fontDictionary.containsKey(COSName.FONT_BBOX);
+		areFieldsPResent &= fontDictionary.containsKey(COSName.FONT_MATRIX);
+		areFieldsPResent &= fontDictionary.containsKey(COSName.CHAR_PROCS);
+		areFieldsPResent &= fontDictionary.containsKey(COSName.ENCODING);
+		areFieldsPResent &= fontDictionary.containsKey(COSName.FIRST_CHAR);
+		areFieldsPResent &= fontDictionary.containsKey(COSName.LAST_CHAR);
+		areFieldsPResent &= fontDictionary.containsKey(COSName.WIDTHS);
 
-		/*
-		 * ---- Since PDF 1.5 : FontDescriptor is mandatory for Type3 font. However
-		 * because of the FontDescriptor is optional in PDF-1.4 no specific checks
-		 * are processed for PDF/A validation.
-		 */
-		return all;
+		if (!areFieldsPResent) {
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "Some required fields are missing from the Font dictionary."));
+		}
 	}
 
 	/**
-	 * FontBBox and FontMatrix are required. This method checks the type and the
-	 * content of the FontBBox and FontMatrix element (Array of 4/6 number). If a
-	 * type is invalid, the FontContainer is updated and the method returns false.
-	 * 
-	 * @return
+	 * Check that the FontBBox element has the right format as declared in the PDF reference document.
 	 */
-	private boolean checkFontBBoxMatrix() {
-		// ---- both elements are an array
-		if (!COSUtils.isArray(this.fontBBox, cosDocument)) {
-			this.fontContainer
-			.addError(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
-					"The FontBBox element isn't an array"));
-			return false;
-		}
-
-		if (!COSUtils.isArray(this.fontMatrix, cosDocument)) {
-			this.fontContainer.addError(new ValidationError(
-					ERROR_FONTS_DICTIONARY_INVALID,
-					"The FontMatrix element isn't an array"));
-			return false;
+	private void checkFontBBox() {
+		COSBase fontBBox = fontDictionary.getItem(COSName.FONT_BBOX);
+
+		if (!COSUtils.isArray(fontBBox, cosDocument)) {
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,	"The FontBBox element isn't an array"));
+			return;
 		}
 
-		// ---- check the content of the FontBBox.
-		// ---- Should be an array with 4 numbers
+		/*
+		 * check the content of the FontBBox.
+		 * Should be an array with 4 numbers
+		 */
 		COSArray bbox = COSUtils.getAsArray(fontBBox, cosDocument);
 		if (bbox.size() != 4) {
-			this.fontContainer.addError(new ValidationError(
-					ERROR_FONTS_DICTIONARY_INVALID, "The FontBBox element is invalid"));
-			return false;
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "The FontBBox element is invalid"));
+			return ;
 		} else {
 			for (int i = 0; i < 4; i++) {
 				COSBase elt = bbox.get(i);
 				if (!(COSUtils.isFloat(elt, cosDocument) || COSUtils.isInteger(elt, cosDocument))) {
-					this.fontContainer.addError(new ValidationError(
-							ERROR_FONTS_DICTIONARY_INVALID,
-							"An element of FontBBox isn't a number"));
-					return false;
+					this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "An element of FontBBox isn't a number"));
+					return;
 				}
 			}
 		}
+	}
+
+	/**
+	 * Check that the FontMatrix element has the right format as declared in the PDF reference document.
+	 */
+	private void checkFontMatrix() {
+		COSBase fontMatrix = fontDictionary.getItem(COSName.FONT_MATRIX);
+
+		if (!COSUtils.isArray(fontMatrix, cosDocument)) {
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,	"The FontMatrix element isn't an array"));
+			return;
+		}
 
-		// ---- check the content of the FontMatrix.
-		// ---- Should be an array with 6 numbers
+		/*
+		 * Check the content of the FontMatrix.
+		 * Should be an array with 6 numbers
+		 */
 		COSArray matrix = COSUtils.getAsArray(fontMatrix, cosDocument);
 		if (matrix.size() != 6) {
-			this.fontContainer.addError(new ValidationError(
-					ERROR_FONTS_DICTIONARY_INVALID, "The FontMatrix element is invalid"));
-			return false;
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID, "The FontMatrix element is invalid"));
+			return;
 		} else {
 			for (int i = 0; i < 6; i++) {
 				COSBase elt = matrix.get(i);
 				if (!(COSUtils.isFloat(elt, cosDocument) || COSUtils.isInteger(elt, cosDocument))) {
-					this.fontContainer.addError(new ValidationError(
-							ERROR_FONTS_DICTIONARY_INVALID,
-							"An element of FontMatrix isn't a number"));
-					return false;
+					this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,	"An element of FontMatrix isn't a number"));
+					return;
 				}
 			}
 		}
-
-		return true;
 	}
 
+	@Override
 	/**
 	 * For a Type3 font, the mapping between the Character Code and the Character
 	 * name is entirely defined in the Encoding Entry. The Encoding Entry can be a
@@ -206,71 +168,63 @@ public class Type3FontValidator extends 
 	 * a well formed "Differences" array (the array is optional)
 	 * </UL>
 	 * 
+	 * At the end of this method, if the validation succeed the Font encoding is kept in the {@link #encoding} attribute
 	 * @return
 	 */
-	private boolean checkEncoding() {
-		EncodingManager emng = new EncodingManager();
-		if (COSUtils.isString(this.fontEncoding, cosDocument)) {
-			// ---- Encoding is a Name, check if it is an Existing Encoding
-			String enc = COSUtils.getAsString(this.fontEncoding, cosDocument);
-			try {
-				type3Encoding = emng.getEncoding(COSName.getPDFName(enc));
-			} catch (IOException e) {
-				// ---- the encoding doesn't exist
-				this.fontContainer.addError(new ValidationError(ERROR_FONTS_ENCODING));
-				return false;
-			}
-		} else if (COSUtils.isDictionary(this.fontEncoding, cosDocument)) {
-			COSDictionary encodingDictionary = COSUtils.getAsDictionary(this.fontEncoding, cosDocument);
-			try {
-				type3Encoding = new DictionaryEncoding(encodingDictionary);
-			} catch (IOException e) {
-				// ---- the encoding doesn't exist
-				this.fontContainer.addError(new ValidationError(ERROR_FONTS_ENCODING));
-				return false;
-			}
-
-			COSBase diff = encodingDictionary.getItem(COSName
-					.getPDFName(FONT_DICTIONARY_KEY_DIFFERENCES));
-			if (diff != null) {
-				if (!COSUtils.isArray(diff, cosDocument)) {
-					this.fontContainer
-					.addError(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,
-							"The differences element of the encoding dictionary isn't an array"));
-					return false;
-				}
-
-				// ---- The DictionaryEncoding object doesn't throw exception if the
-				// Differences isn't well formed.
-				// So check if the array has the right format.
-				COSArray differences = COSUtils.getAsArray(diff, cosDocument);
-				for (int i = 0; i < differences.size(); ++i) {
-					COSBase item = differences.get(i);
-					if (!(item instanceof COSInteger || item instanceof COSName)) {
-						// ---- Error, the Differences array is invalid
-						this.fontContainer
-						.addError(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,
-								"Differences Array should contain COSInt or COSName, no other type"));
-						return false;
-					}
-				}
-			}
+	protected void checkEncoding() {
+		COSBase fontEncoding = fontDictionary.getItem(COSName.ENCODING);
+		if (COSUtils.isString(fontEncoding, cosDocument)) {
+			checkEncodingAsString(fontEncoding);
+		} else if (COSUtils.isDictionary(fontEncoding, cosDocument)) {
+			checkEncodingAsDictionary(fontEncoding);
 		} else {
-			// ---- the encoding entry is invalid
-			this.fontContainer.addError(new ValidationError(
-					ERROR_FONTS_TYPE3_DAMAGED,
-					"The Encoding entry doesn't have the right type"));
-			return false;
+			// the encoding entry is invalid
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,"The Encoding entry doesn't have the right type"));
 		}
+	}
 
-		return true;
+	/**
+	 * This method is called by the CheckEncoding method if the Encoding entry is a String.
+	 * In this case, the String must be an existing encoding name. (WinAnsi, MacRoman...)
+	 * @param fontEncoding
+	 */
+	private void checkEncodingAsString(COSBase fontEncoding) {
+		EncodingManager emng = new EncodingManager();
+		// Encoding is a Name, check if it is an Existing Encoding
+		String enc = COSUtils.getAsString(fontEncoding, cosDocument);
+		try {
+			this.encoding = emng.getEncoding(COSName.getPDFName(enc));
+		} catch (IOException e) {
+			// the encoding doesn't exist
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_ENCODING));
+			return;
+		}
+	}
+
+	/**
+	 * This method is called by the CheckEncoding method if the Encoding entry is an instance of COSDictionary.
+	 * In this case, a new instance of {@link DictionaryEncoding} is created. If an IOException is thrown by the DictionaryEncoding
+	 * constructor the {@link PreflightConstants.ERROR_FONTS_ENCODING} is pushed in the FontContainer.
+	 * 
+	 * Differences entry validation is implicitly done by the DictionaryEncoding constructor.
+	 * @param fontEncoding
+	 */
+	private void checkEncodingAsDictionary(COSBase fontEncoding) {
+		COSDictionary encodingDictionary = COSUtils.getAsDictionary(fontEncoding, cosDocument);
+		try {
+			this.encoding = new DictionaryEncoding(encodingDictionary);
+		} catch (IOException e) {
+			// the encoding doesn't exist
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_ENCODING));
+			return;
+		}
 	}
 
 	/**
 	 * CharProcs is a dictionary where the key is a character name and the value
 	 * is a Stream which contains the glyph representation of the key.
 	 * 
-	 * This method checks that all character code defined in the Widths Array
+	 * This method checks that all characters codes defined in the Widths Array
 	 * exist in the CharProcs dictionary. If the CharProcs doesn't know the
 	 * Character, it is mapped with the .notdef one.
 	 * 
@@ -280,183 +234,156 @@ public class Type3FontValidator extends 
 	 * @param errors
 	 * @return
 	 */
-	private boolean checkCharProcsAndMetrics() throws ValidationException {
-		// ---- the Widths value can be a reference to an object
-		// ---- Access the object using the COSkey
-		COSArray wArr = COSUtils.getAsArray(this.widths, cosDocument);
-		if (wArr == null) {
-			this.fontContainer.addError(new ValidationError(
-					ERROR_FONTS_DICTIONARY_INVALID, 
-					"The Witdhs array is unreachable"));
-			return false;
-		}
-
-		COSDictionary charProcsDictionary = COSUtils.getAsDictionary(this.charProcs, cosDocument);
-		if (charProcsDictionary == null) {
-			this.fontContainer.addError(new ValidationError(
-					ERROR_FONTS_DICTIONARY_INVALID,
-					"The CharProcs element isn't a dictionary"));
-			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.
+	private void checkCharProcsAndMetrics() throws ValidationException {
+		List<Float> widths = font.getWidths();
+		if (widths == null || widths.isEmpty()) {
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,	"The Witdhs array is unreachable"));
+			return;
+		}
+
+		COSDictionary charProcs = COSUtils.getAsDictionary(fontDictionary.getItem(COSName.CHAR_PROCS), cosDocument);
+		if (charProcs == null) {
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,	"The CharProcs element isn't a dictionary"));
+			return;
+		}
+
+		int fc = this.font.getFirstChar();
+		int lc = this.font.getLastChar();
+
+		/*
+		 * 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;
+		if (widths.size() != expectedLength) {
+			this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
+					"The length of Witdhs array is invalid. Expected : \"" + expectedLength + "\" Current : \"" + widths.size() + "\""));
+			return;
 		}
 
-		// ---- Check width consistency
+		// Check width consistency
+		PDResources pResources = getPDResources();
 		for (int i = 0; i < expectedLength; i++) {
 			int cid = fc + i;
-			COSBase arrContent = wArr.get(i);
-			if (COSUtils.isNumeric(arrContent, cosDocument)) {
-				float width = COSUtils.getAsFloat(arrContent, cosDocument);
-
-				String charName = null;
+			float width = widths.get(i);
+			
+			COSStream charStream = getCharacterStreamDescription(cid, charProcs);
+			
+			if (charStream != null) {
 				try {
-					charName = this.type3Encoding.getName(cid);
-				} catch (IOException e) {
-					// shouldn't occur
-					throw new ValidationException("Unable to check Widths consistency", e);
-				}
-
-				COSBase item = charProcsDictionary.getItem(COSName.getPDFName(charName));
-				COSStream charStream = COSUtils.getAsStream(item, cosDocument);
-				if (charStream == null) {
-					/* There are no character description, we declare the Glyph as Invalid.
-					 * If the character is used in a Stream, the GlyphDetail will throw an exception.
-					 */
-					GlyphException glyphEx = new GlyphException(ERROR_FONTS_METRICS, cid, 
-							"The CharProcs \"" + charName
-							+ "\" doesn't exist, the width defines in the Font Dictionary is " + width);
-					GlyphDetail glyphDetail = new GlyphDetail(cid, glyphEx);
-					this.fontContainer.addKnownCidElement(glyphDetail);
-				} else {
-					try {
-						PreflightPath vPath = context.getValidationPath();
-						// --- Parse the Glyph description to obtain the Width
-						PDFAType3StreamParser parser = new PDFAType3StreamParser(context, vPath.getClosestPathElement(PDPage.class)); // TODO pass the page or the Font???
-						PDResources pRes = null;
-						if (this.resources != null) {
-							COSDictionary resAsDict = COSUtils.getAsDictionary(this.resources, cosDocument);
-							if (resAsDict != null) {
-								pRes = new PDResources(resAsDict);
-							}
-						}
-						parser.resetEngine();
-						parser.processSubStream(null, pRes, charStream);
-
-						if (width != parser.getWidth()) {
-							GlyphException glyphEx = new GlyphException(ERROR_FONTS_METRICS, cid, 
-									"The CharProcs \"" + charName
-									+ "\" should have a width equals to " + width);
-							GlyphDetail glyphDetail = new GlyphDetail(cid, glyphEx);
-							this.fontContainer.addKnownCidElement(glyphDetail);
-						} else {
-							// Glyph is OK, we keep the CID.
-							GlyphDetail glyphDetail = new GlyphDetail(cid);
-							this.fontContainer.addKnownCidElement(glyphDetail);
-						}
-					}  catch (ContentStreamException e) {
-						// TODO spaces/isartor-6-2-3-3-t02-fail-h.pdf --> si ajout de l'erreur dans le container le test echoue... pourquoi si la font est utilisée ca devrait planter???
-						this.context.addValidationError(new ValidationError(
-								((ContentStreamException)e).getErrorCode(),
-								e.getMessage()));
-						return false;
-					} catch (IOException e) {
-						this.fontContainer.addError(new ValidationError(
-								ERROR_FONTS_TYPE3_DAMAGED,
-								"The CharProcs references an element which can't be read"));
-						return false;
+					
+					float fontProgamWidth = getWidthFromCharacterStream(pResources, charStream);
+					if (width == fontProgamWidth) {
+						// Glyph is OK, we keep the CID.
+						this.fontContainer.markCIDAsValid(cid);
+					} else {
+						GlyphException glyphEx = new GlyphException(ERROR_FONTS_METRICS, cid, 
+								"The character with CID\"" + cid	+ "\" should have a width equals to " + width);
+						this.fontContainer.markCIDAsInvalid(cid, glyphEx);
 					}
+				} catch (ContentStreamException e) {
+					// TODO spaces/isartor-6-2-3-3-t02-fail-h.pdf --> si ajout de l'erreur dans le container le test echoue... pourquoi si la font est utilisée ca devrait planter???
+					this.context.addValidationError(new ValidationError(((ContentStreamException)e).getErrorCode(),	e.getMessage()));
+					return;
+				} catch (IOException e) {
+					this.fontContainer.push(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED, "The CharProcs references an element which can't be read"));
+					return;
 				}
-
-			} else {
-				this.fontContainer.addError(new ValidationError(
-						ERROR_FONTS_DICTIONARY_INVALID,
-						"The Witdhs array is invalid. (some element aren't integer)"));
-				return false;
 			}
 		}
-		return true;
 	}
 
+	private PDResources getPDResources() {
+		COSBase res = this.fontDictionary.getItem(COSName.RESOURCES);
+		PDResources pResources = null;
+		COSDictionary resAsDict = COSUtils.getAsDictionary(res, cosDocument);
+		if (resAsDict != null) {
+			pResources = new PDResources(resAsDict);
+		}
+		return pResources;
+	}
+
+	
+	private COSStream getCharacterStreamDescription(int cid, COSDictionary charProcs) throws ValidationException {
+		String charName = getCharNameFromEncoding(cid);
+		COSBase item = charProcs.getItem(COSName.getPDFName(charName));
+		COSStream charStream = COSUtils.getAsStream(item, cosDocument);
+		if (charStream == null) {
+			/* 
+			 * There are no character description, we declare the Glyph as Invalid.
+			 * If the character is used in a Stream, the GlyphDetail will throw an exception.
+			 */
+			GlyphException glyphEx = new GlyphException(ERROR_FONTS_METRICS, cid,	"The CharProcs \"" + charName	+ "\" doesn't exist");
+			this.fontContainer.markCIDAsInvalid(cid, glyphEx);
+		} 
+		return charStream;
+	}
+	
+	private String getCharNameFromEncoding(int cid) throws ValidationException {
+		try {
+			return this.encoding.getName(cid);
+		} catch (IOException e) {
+			// shouldn't occur
+			throw new ValidationException("Unable to check Widths consistency", e);
+		}
+	}
+	
+	/**
+	 * Parse the Glyph description to obtain the Width
+	 * @return the width of the character 
+	 */
+	private float getWidthFromCharacterStream(PDResources resources, COSStream charStream) throws IOException {
+		PreflightPath vPath = context.getValidationPath();
+		PDFAType3StreamParser parser = new PDFAType3StreamParser(context, vPath.getClosestPathElement(PDPage.class));
+		parser.resetEngine();
+		parser.processSubStream(null, resources, charStream);
+		return parser.getWidth();
+	}
+	
 	/**
 	 * If the Resources entry is present, this method check its content. Only
-	 * fonts and Images are checked because this resource describes glyphs. REMARK
-	 * : The font and the image aren't validated because they will be validated by
-	 * an other ValidationHelper.
+	 * fonts and Images are checked because this resource describes glyphs.
 	 * 
 	 * @return
 	 */
-	private boolean checkResources() throws ValidationException {
-		if (this.resources == null) {
-			// ---- No resources dictionary.
-			return true;
-		}
-
-		COSDictionary dictionary = COSUtils.getAsDictionary(this.resources, cosDocument);
-		if (dictionary == null) {
-			this.fontContainer.addError(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
-					"The Resources element isn't a dictionary"));
-			return false;
-		}
-
-
-		ContextHelper.validateElement(context, new PDResources(dictionary), RESOURCES_PROCESS);
-		COSBase cbFont = dictionary.getItem(COSName.getPDFName(DICTIONARY_KEY_FONT));
+	private void checkResources() throws ValidationException {
+		COSBase resources = this.fontDictionary.getItem(COSName.RESOURCES);
+		if (resources != null) {
+
+			COSDictionary dictionary = COSUtils.getAsDictionary(resources, cosDocument);
+			if (dictionary == null) {
+				this.fontContainer.push(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,	"The Resources element isn't a dictionary"));
+				return;
+			}
 
-		if (cbFont != null) {
-			// ---- the referenced object must be present in the PDF file
-			COSDictionary dicFonts = COSUtils.getAsDictionary(cbFont, cosDocument);
-			Set<COSName> keyList = dicFonts.keySet();
-			for (Object key : keyList) {
+			// process Fonts and XObjects
+			ContextHelper.validateElement(context, new PDResources(dictionary), RESOURCES_PROCESS);
+			COSBase cbFont = dictionary.getItem(COSName.FONT);
+
+			if (cbFont != null) {
+				/*
+				 * Check that all referenced object are present in the PDF file
+				 */
+				COSDictionary dicFonts = COSUtils.getAsDictionary(cbFont, cosDocument);
+				Set<COSName> keyList = dicFonts.keySet();
+				for (Object key : keyList) {
 
-				COSBase item = dicFonts.getItem((COSName) key);
-				COSDictionary xObjFont = COSUtils.getAsDictionary(item, cosDocument);
+					COSBase item = dicFonts.getItem((COSName) key);
+					COSDictionary xObjFont = COSUtils.getAsDictionary(item, cosDocument);
 
-				try {
-					PDFont aFont = PDFontFactory.createFont(xObjFont);
-					AbstractFontContainer aContainer = this.context.getFont(aFont.getCOSObject());
-					// ---- another font is used in the Type3, check if the font is valid.
-					if (aContainer.isValid() != org.apache.pdfbox.preflight.font.AbstractFontContainer.State.VALID) {
-						this.fontContainer
-						.addError(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,
-								"The Resources dictionary of type 3 font contains invalid font"));
-						return false;
+					try {
+						PDFont aFont = PDFontFactory.createFont(xObjFont);
+						FontContainer aContainer = this.context.getFontContainer(aFont.getCOSObject());
+						// another font is used in the Type3, check if the font is valid.
+						if (!aContainer.isValid()) {
+							this.fontContainer.push(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED, "The Resources dictionary of type 3 font contains invalid font"));
+						}
+					} catch (IOException e) {
+						throw new ValidationException("Unable to valid the Type3 : " + e.getMessage());
 					}
-				} catch (IOException e) {
-					throw new ValidationException("Unable to valid the Type3 : "
-							+ e.getMessage());
 				}
 			}
 		}
-
-		return true;
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see net.awl.edoc.pdfa.validation.font.FontValidator#validate()
-	 */
-	public void validate() throws ValidationException {
-		extractFontDictionaryEntries();
-		boolean isValid = checkMandatoryFields();
-		isValid = isValid && checkFontBBoxMatrix();
-		isValid = isValid && checkEncoding();
-		isValid = isValid && checkCharProcsAndMetrics();
-		isValid = isValid && checkResources();
 	}
 }

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType0Container.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,90 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.container;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.CFFFont.Mapping;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+
+public class CIDType0Container extends FontContainer {
+	protected List<CFFFont> lCFonts = new ArrayList<CFFFont>();
+
+	public CIDType0Container(PDFont font) {
+		super(font);
+	}
+	
+	@Override
+	protected float getFontProgramWidth(int cid) {
+		// build the font container and keep it in the Handler.
+	  boolean cidFound = false;
+		for (CFFFont font : this.lCFonts) {
+			Collection<Mapping> cMapping = font.getMappings();
+			for (Mapping mapping : cMapping) {
+				/*
+				 * REMARK : May be this code must be changed like the Type1FontContainer to Map the SID with the character name?
+				 * Not enough PDF with this kind of Font to test the current implementation
+				 */
+				if (mapping.getSID()==cid) {
+					cidFound = true;
+				}
+			}
+		}
+
+		float widthInFontProgram = 0;
+		if (cidFound || cid == 0) { 
+
+			float defaultGlyphWidth = 0;
+			if (this.font.getFontDescriptor() != null) {
+				defaultGlyphWidth = this.font.getFontDescriptor().getMissingWidth();
+			}
+			
+			try {
+				// Search the CID in all CFFFont in the FontProgram
+				for (CFFFont cff : this.lCFonts) {
+					widthInFontProgram = cff.getWidth(cid);
+					if (widthInFontProgram != defaultGlyphWidth) {
+						break;
+					}
+				}
+			} catch (IOException e) {
+				widthInFontProgram = -1;
+			}
+		}else {
+			/*
+			 * Cid 0 is commonly used as the NotDef Glyph. this glyph can be used as Space.
+			 * IN PDF/A-1 the Notdef glyph can be used as space. Not in PDF/A-2
+			 */
+			widthInFontProgram = -1;
+		}
+		return widthInFontProgram;	
+	}
+
+	public void setlCFonts(List<CFFFont> lCFonts) {
+		this.lCFonts = lCFonts;
+	}
+
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/CIDType2Container.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,87 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.container;
+
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.preflight.font.util.CIDToGIDMap;
+
+public class CIDType2Container extends FontContainer {
+
+	protected CIDToGIDMap cidToGid = null;
+
+	protected TrueTypeFont ttf = null;
+
+	public CIDType2Container(PDFont font) {
+		super(font);
+	}
+	
+	@Override
+	protected float getFontProgramWidth(int cid) {
+		float foundWidth = - 1;
+		final int glyphIndex = getGlyphIndex(cid);
+		
+		// if glyph exists we can check the width
+		if(this.ttf != null && this.ttf.getGlyph().getGlyphs().length > glyphIndex) {
+			/* 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();
+			int unitsPerEm = ttf.getHeader().getUnitsPerEm();
+			int[] advanceGlyphWidths = ttf.getHorizontalMetrics().getAdvanceWidth();
+			float glypdWidth = advanceGlyphWidths[numberOfLongHorMetrics - 1];
+			if (glyphIndex < numberOfLongHorMetrics) {
+				glypdWidth = advanceGlyphWidths[glyphIndex];
+			}
+			foundWidth = ((glypdWidth * 1000) / unitsPerEm);
+		}
+		return foundWidth;
+	}
+
+	/**
+	 * If CIDToGID map is Identity, the GID equals to the CID.
+	 * Otherwise the conversion is done by the CIDToGID map
+	 * @param cid
+	 * @return -1 CID doesn't match with a GID
+	 */
+	private int getGlyphIndex(int cid){
+		int glyphIndex = cid;
+		if (this.cidToGid != null) {
+			glyphIndex = cidToGid.getGID(cid);
+			if (glyphIndex==cidToGid.NOTDEF_GLYPH_INDEX) {
+				glyphIndex = -14;
+			}
+		}
+		return glyphIndex;
+	}
+
+	public void setCidToGid(CIDToGIDMap cidToGid) {
+		this.cidToGid = cidToGid;
+	}
+
+	public void setTtf(TrueTypeFont ttf) {
+		this.ttf = ttf;
+	}
+
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/FontContainer.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,172 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.container;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.preflight.PreflightConstants;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.preflight.font.util.GlyphDetail;
+import org.apache.pdfbox.preflight.font.util.GlyphException;
+
+public abstract class FontContainer {
+	/**
+	 * List of validation errors that occur during the font validation.
+	 * If the font is used by an object in the PDF, all these errors will be appended 
+	 * to the Error list of the PreflightContext.
+	 */
+	protected List<ValidationError> errorBuffer = new ArrayList<ValidationError>();
+	/**
+	 * Boolean used to known if the font is embedded.
+	 */
+	protected boolean embeddedFont = true;
+
+	/**
+	 * Link CID to an Object that contain information about the Glyph state (Valid or no)
+	 */
+	protected Map<Integer, GlyphDetail> computedCid = new HashMap<Integer, GlyphDetail>();
+
+	protected boolean errorsAleadyMerged = false;
+	
+	protected PDFont font;
+
+	public FontContainer(PDFont font) {
+		super();
+		this.font = font;
+	}
+
+	public void push(ValidationError error) {
+		this.errorBuffer.add(error);
+	}
+
+	public void push(List<ValidationError> errors) {
+		this.errorBuffer.addAll(errors);
+	}
+
+	public List<ValidationError> getAllErrors() {
+		return this.errorBuffer;
+	}
+
+	public boolean isValid() {
+		return (this.errorBuffer.isEmpty() && isEmbeddedFont());
+	}
+	
+	public boolean errorsAleadyMerged() {
+		return errorsAleadyMerged;
+	}
+
+	public void setErrorsAleadyMerged(boolean errorsAleadyMerged) {
+		this.errorsAleadyMerged = errorsAleadyMerged;
+	}
+
+	public boolean isEmbeddedFont() {
+		return embeddedFont;
+	}
+
+	public void notEmbedded() {
+		this.embeddedFont = false;
+	}
+
+	/**
+	 * 
+	 * @param cid
+	 * @throws GlyphException
+	 */
+	public void checkGlyphWith(int cid) throws GlyphException {
+		if (isAlreadyComputedCid(cid)) {
+			return;
+		}
+
+		final float expectedWidth = this.font.getFontWidth(cid);
+		final float foundWidth = getFontProgramWidth(cid);
+		checkWidthsConsistency(cid, expectedWidth, foundWidth);
+	}
+
+	/**
+	 * Check if the given CID is already computed
+	 * 
+	 * @param cid the CID to check
+	 * @return true if the CID has previously been marked as valid, false otherwise
+	 * @throws GlyphException if the CID has previously been marked as invalid // TODO useful ??
+	 */
+	protected boolean isAlreadyComputedCid(int cid) throws GlyphException {
+		boolean already = false;
+		GlyphDetail gdetail = this.computedCid.get(cid);
+		if (gdetail != null) {
+			gdetail.throwExceptionIfNotValid();
+			already = true;
+		}
+		return already;
+	}
+	
+	/**
+	 * Extract the Glyph width for the given CID.
+	 * @param cid
+	 * @return The Glyph width in 'em' unit.
+	 */
+	protected abstract float getFontProgramWidth(int cid);
+	
+	/**
+	 * Test if both width are consistent. At the end of this method, the CID is marked as valid or invalid.
+	 * 
+	 * @param cid
+	 * @param expectedWidth
+	 * @param foundWidth the glyph width found in the font program, a negative value if the CID is missing from the font.
+	 * @throws GlyphException
+	 */
+	protected void checkWidthsConsistency(int cid, float expectedWidth, float foundWidth) throws GlyphException {
+		if (foundWidth < 0) {
+      GlyphException e = new GlyphException(PreflightConstants.ERROR_FONTS_GLYPH_MISSING, 
+      		cid, 
+      		"The character \"" + cid 
+      		+ "\" in the font program \""
+      		+ this.font.getBaseFont() 
+      		+ "\"is missing from the Charater Encoding.");
+      markCIDAsInvalid(cid, e);
+      throw e;	
+		}
+		
+		// consistent is defined to be a difference of no more than 1/1000 unit.
+		if(Math.abs(foundWidth-expectedWidth) > 1) {	
+			GlyphException e = new GlyphException(PreflightConstants.ERROR_FONTS_METRICS, cid, 
+					"Width of the character \"" + cid 
+					+ "\" in the font program \""
+					+ this.font.getBaseFont() 
+					+ "\"is inconsistent with the width in the PDF dictionary.");
+			markCIDAsInvalid(cid, e);
+			throw e;
+		}
+		markCIDAsValid(cid);
+	}
+	
+	public final void markCIDAsValid(int cid) {
+		this.computedCid.put(cid, new GlyphDetail(cid));
+	}
+
+	public final void markCIDAsInvalid(int cid, GlyphException gex) {
+		this.computedCid.put(cid, new GlyphDetail(cid, gex));
+	}
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/TrueTypeContainer.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,170 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.container;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.fontbox.ttf.CMAPEncodingEntry;
+import org.apache.fontbox.ttf.CMAPTable;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.pdfbox.encoding.Encoding;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+
+public class TrueTypeContainer extends FontContainer {
+
+	protected TrueTypeFont ttFont;
+
+	private CMAPEncodingEntry[] cmapEncodingEntries = null;
+
+	public TrueTypeContainer(PDFont font) {
+		super(font);
+	}
+
+	public void setTrueTypeFont(TrueTypeFont ttFont) {
+		this.ttFont = ttFont;
+		initCMapEncodingEntries(); // TODO appel sur le checkWidth
+	}
+
+	/**
+	 * Initialize the {@linkplain #cmapEncodingEntries} with CMaps that 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, the list of CMap is reordered to provide WinAnsi CMap first
+	 * (plateformId : 3 / encodingId : 1) followed by MacRoman CMap (plateformId : 1 /
+	 * encodingId : 0). This CMap returns the CMap which corresponds to the
+	 * Encoding value of the FontDescriptor dictionary.
+	 * </UL>
+	 */
+	protected void initCMapEncodingEntries() {
+		if (this.cmapEncodingEntries != null) return;
+
+		CMAPTable cmap = this.ttFont.getCMAP();
+		if (this.font.getFontDescriptor().isSymbolic()) {
+			this.cmapEncodingEntries = cmap.getCmaps();
+		} else {
+			this.cmapEncodingEntries = orderCMapEntries(cmap);
+		}
+	}
+
+	private CMAPEncodingEntry[] orderCMapEntries(CMAPTable cmap) {
+		List<CMAPEncodingEntry> res = new ArrayList<CMAPEncodingEntry>();
+		boolean firstIs31 = false;
+		for (CMAPEncodingEntry cmapEntry :  cmap.getCmaps()) {
+			// WinAnsi 
+			if ((cmapEntry.getPlatformId() == 3) && (cmapEntry.getPlatformEncodingId() == 1)) {
+				res.add(0,cmapEntry);
+				firstIs31 = true;
+			} else if ((cmapEntry.getPlatformId() == 1)&& (cmapEntry.getPlatformEncodingId() == 0)) {
+				// MacRoman
+				if (firstIs31) { 
+					// WinAnsi is present, MacRoman is set in second position
+					res.add(1, cmapEntry);
+				} else {
+					// WinAnsi is missing, MacRoman has the priority
+					res.add(0, cmapEntry);
+				}
+			} else {
+				res.add(cmapEntry);
+			}
+		}
+		return res.toArray(new CMAPEncodingEntry[res.size()]);
+	}
+
+	@Override
+	protected float getFontProgramWidth(int cid) {
+		float result = -1f;
+		if (cmapEncodingEntries != null) {
+			for (CMAPEncodingEntry entry : cmapEncodingEntries) {
+				int glyphID = extractGlyphID(cid, entry);
+				if (glyphID > 0) {	
+					result = extractGlyphWidth(glyphID);
+					break;
+				}
+			}
+		}
+		return  result;
+	}
+
+	/**
+	 * TrueType has internal CMap that map the CID used in the PDF file with an internal character identifier.
+	 * This method converts the given CID in the internal font program identifier. (0 if no match found)
+	 * @param cid
+	 * @param cmap
+	 * @return
+	 */
+	private int extractGlyphID(int cid, CMAPEncodingEntry cmap) {
+		int notFoundGlyphID = 0;
+
+		int innerFontCid = cid;
+		if (cmap.getPlatformEncodingId() == 1 && cmap.getPlatformId() == 3) {
+			try {
+				Encoding fontEncoding = this.font.getFontEncoding();
+				String character = fontEncoding.getCharacter(cid);
+				if (character == null) {
+					return notFoundGlyphID;
+				}
+
+				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) {
+							return notFoundGlyphID; // TODO what we have to do here ???
+						}
+					}
+				}
+			} catch (IOException ioe) {
+				// should never happen 
+				return notFoundGlyphID;
+			}
+		}
+
+		// search glyph
+		return cmap.getGlyphId(innerFontCid);
+	}
+
+	private float extractGlyphWidth(int glyphID) {
+		int unitsPerEm = this.ttFont.getHeader().getUnitsPerEm();
+		int[] glyphWidths = this.ttFont.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 = this.ttFont.getHorizontalHeader().getNumberOfHMetrics();
+		float glypdWidth = glyphWidths[numberOfLongHorMetrics - 1];
+		if (glyphID < numberOfLongHorMetrics) {
+			glypdWidth = glyphWidths[glyphID];
+		}
+		return ((glypdWidth * 1000) / unitsPerEm);
+	}
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type0Container.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.container;
+
+import java.util.List;
+
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+
+public class Type0Container extends FontContainer {
+
+	protected FontContainer delegateFontContainer;
+
+	public Type0Container(PDFont font) {
+		super(font);
+	}
+	
+	@Override
+	protected float getFontProgramWidth(int cid) {
+		float width = 0;
+		if (this.delegateFontContainer != null) {
+			width = this.delegateFontContainer.getFontProgramWidth(cid);
+		}
+		return width;
+	}
+
+	public void setDelegateFontContainer(FontContainer delegateFontContainer) {
+		this.delegateFontContainer = delegateFontContainer;
+	}
+	
+	public List<ValidationError> getAllErrors() {
+		if (this.delegateFontContainer != null) {
+			this.errorBuffer.addAll(this.delegateFontContainer.getAllErrors());
+		}
+		return this.errorBuffer;
+	}
+	
+	public boolean isValid() {
+		boolean result = (this.errorBuffer.isEmpty() && isEmbeddedFont()); 
+		if (this.delegateFontContainer != null) {
+			result &=  this.delegateFontContainer.isValid();
+		}
+		return result;
+	}
+	
+	public boolean isEmbeddedFont() {
+		boolean result = embeddedFont; 
+		if (this.delegateFontContainer != null) {
+			result &=  this.delegateFontContainer.isEmbeddedFont();
+		}
+		return result;
+	}
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type1Container.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,102 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.container;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.CFFFont.Mapping;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.preflight.font.util.GlyphException;
+import org.apache.pdfbox.preflight.font.util.Type1;
+
+public class Type1Container extends FontContainer {
+	/**
+	 * 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;
+
+	/**
+	 * true if information come from the FontFile1 Stream, 
+	 * false if they come from the FontFile3
+	 */
+	protected boolean isFontFile1 = true;
+
+	protected Type1 type1Font; 
+	protected List<CFFFont> lCFonts;
+
+	public Type1Container(PDFont font) {
+		super(font);
+	}
+
+	@Override
+	protected float getFontProgramWidth(int cid) {
+		float widthResult = -1;
+		try {
+			if (isFontFile1) {
+				if (type1Font != null) {
+					widthResult = this.type1Font.getWidthOfCID(cid);
+				}
+			} else {
+				/* 
+				 * Retrieves the SID with the Character Name in the encoding map
+				 * Need more PDF with a Type1C subfont to valid this implementation  
+				 */
+				String name = this.font.getFontEncoding().getName(cid);
+				for (CFFFont cff : lCFonts) {
+					int SID = cff.getEncoding().getSID(cid);
+					for (Mapping m : cff.getMappings() ){
+						if (m.getName().equals(name)) {
+							SID = m.getSID();
+							break;
+						}
+					}
+					widthResult = cff.getWidth(SID);
+					if (widthResult != defaultGlyphWidth) {
+						break;
+					}
+				}
+			}
+		} catch (GlyphException e) {
+			widthResult = -1;
+		} catch (IOException e) {
+			widthResult = -1; // TODO validation exception
+		}
+
+		return widthResult;
+	}
+
+	public void setType1Font(Type1 type1Font) {
+		this.type1Font = type1Font;
+	}
+
+	public void setFontFile1(boolean isFontFile1) {
+		this.isFontFile1 = isFontFile1;
+	}
+
+	public void setCFFFontObjects(List<CFFFont> lCFonts) {
+		this.lCFonts = lCFonts;
+	}
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/container/Type3Container.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,42 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.container;
+
+import org.apache.pdfbox.pdmodel.font.PDFont;
+
+/**
+ * Because Type3 font program is an inner type of the PDF file, 
+ * this font container is quite different from the other because
+ * all character/glyph are already checked.
+ */
+public class Type3Container extends FontContainer {
+
+	public Type3Container(PDFont font) {
+		super(font);
+	}
+	
+	@Override
+	protected float getFontProgramWidth(int cid) {
+		return 0;
+	}
+
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType0DescriptorHelper.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,119 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.descriptor;
+
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_CIDSET_MISSING_FOR_SUBSET;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_CID_DAMAGED;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_FONT_FILEX_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_CIDSET;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_VALUE_TYPE0C;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_VALUE_TYPE1C;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.CFFParser;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDocument;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+import org.apache.pdfbox.preflight.PreflightContext;
+import org.apache.pdfbox.preflight.ValidationResult;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.preflight.font.FontValidator;
+import org.apache.pdfbox.preflight.font.container.CIDType0Container;
+import org.apache.pdfbox.preflight.utils.COSUtils;
+
+public class CIDType0DescriptorHelper extends FontDescriptorHelper<CIDType0Container> {
+
+	public CIDType0DescriptorHelper(PreflightContext context, PDFont font,	CIDType0Container fontContainer) {
+		super(context, font, fontContainer);
+	}
+
+	@Override
+	public PDStream extractFontFile(PDFontDescriptorDictionary fontDescriptor) {
+		PDStream ff3 = fontDescriptor.getFontFile3();
+		if (ff3 != null) {
+			/*
+			 * Stream validation should be done by the StreamValidateHelper.
+			 * Process font specific check 
+			 */
+			COSStream stream = ff3.getStream();
+			if (stream == null) {
+				this.fContainer.push(new ValidationError(	ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is missing"));
+				this.fContainer.notEmbedded();
+			} else {
+				/*
+				 * Lengthx aren't mandatory for this type of font
+				 * But the Subtype is a mandatory field with specific values
+				 */
+				String st = stream.getNameAsString(COSName.SUBTYPE);
+				if (!(FONT_DICTIONARY_VALUE_TYPE0C.equals(st) || FONT_DICTIONARY_VALUE_TYPE1C.equals(st))) {
+					this.fContainer.push(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID,	"The FontFile3 stream doesn't have the right Subtype"));
+				}
+
+				checkCIDSet(fontDescriptor);
+			}
+		}
+		return ff3;
+	}
+
+	/**
+	 * If the embedded font is a subset, the CIDSet entry is mandatory and must be
+	 * a Stream. If the CIDSet entry doesn't respects conditions, the FontContainer is updated.
+	 * 
+	 * @param pfDescriptor
+	 */
+	protected void checkCIDSet(PDFontDescriptorDictionary pfDescriptor) {
+		if (FontValidator.isSubSet(pfDescriptor.getFontName())) {
+			COSDocument cosDocument = context.getDocument().getDocument();
+			COSBase cidset = pfDescriptor.getCOSDictionary().getItem(COSName.getPDFName(FONT_DICTIONARY_KEY_CIDSET));
+			if (cidset == null	|| !COSUtils.isStream(cidset, cosDocument)) {
+				this.fContainer.push(new ValidationResult.ValidationError(ERROR_FONTS_CIDSET_MISSING_FOR_SUBSET,
+						"The CIDSet entry is missing for the Composite Subset"));
+			}
+		}
+	}
+
+	@Override
+	protected void processFontFile(PDFontDescriptorDictionary fontDescriptor,	PDStream fontFile) {
+		/*
+		 * 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(fontFile.getByteArray());
+			if (lCFonts == null || lCFonts.isEmpty()) {
+				this.fContainer.push(new ValidationError(ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
+			}
+			fContainer.setlCFonts(lCFonts);
+		} catch (IOException e) {
+			this.fContainer.push(new ValidationError(ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
+		}
+	}
+
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/CIDType2DescriptorHelper.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,112 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.descriptor;
+
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_CIDSET_MISSING_FOR_SUBSET;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_CID_DAMAGED;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_FONT_FILEX_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_CIDSET;
+
+import java.io.ByteArrayInputStream;
+
+import org.apache.fontbox.ttf.CIDFontType2Parser;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDocument;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+import org.apache.pdfbox.preflight.PreflightContext;
+import org.apache.pdfbox.preflight.ValidationResult;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.preflight.font.FontValidator;
+import org.apache.pdfbox.preflight.font.container.CIDType2Container;
+import org.apache.pdfbox.preflight.utils.COSUtils;
+
+public class CIDType2DescriptorHelper extends FontDescriptorHelper<CIDType2Container> {
+
+	public CIDType2DescriptorHelper(PreflightContext context, PDFont font,	CIDType2Container fontContainer) {
+		super(context, font, fontContainer);
+	}
+
+	/**
+	 * If the embedded font is a subset, the CIDSet entry is mandatory and must be
+	 * a Stream. If the CIDSet entry doesn't respects conditions, the FontContainer is updated.
+	 * 
+	 * @param pfDescriptor
+	 */
+	protected void checkCIDSet(PDFontDescriptorDictionary pfDescriptor) {
+		if (FontValidator.isSubSet(pfDescriptor.getFontName())) {
+			COSDocument cosDocument = context.getDocument().getDocument();
+			COSBase cidset = pfDescriptor.getCOSDictionary().getItem(COSName.getPDFName(FONT_DICTIONARY_KEY_CIDSET));
+			if (cidset == null	|| !COSUtils.isStream(cidset, cosDocument)) {
+				this.fContainer.push(new ValidationResult.ValidationError(ERROR_FONTS_CIDSET_MISSING_FOR_SUBSET,
+						"The CIDSet entry is missing for the Composite Subset"));
+			}
+		}
+	}
+
+	@Override
+	public PDStream extractFontFile(PDFontDescriptorDictionary fontDescriptor) {
+		PDStream ff2 = fontDescriptor.getFontFile2();
+		if (ff2 != null) {
+			/*
+			 * Stream validation should be done by the StreamValidateHelper.
+			 * Process font specific check
+			 */
+			COSStream stream = ff2.getStream();
+			if (stream == null) {
+				this.fContainer.push(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is missing"));
+				this.fContainer.notEmbedded();
+			}
+		}
+		checkCIDSet(fontDescriptor);
+		return ff2;
+	}
+
+	@Override
+	protected void processFontFile(PDFontDescriptorDictionary fontDescriptor,	PDStream fontFile) {
+		/*
+		 * 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(fontFile.getByteArray()));
+			this.fContainer.setTtf(ttf);
+		} catch (Exception e) {
+			/*
+			 * Exceptionally, Exception is catched Here because of damaged font
+			 * can throw NullPointer Exception...
+			 */
+			this.fContainer.push(new ValidationError(ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
+		}
+	}
+
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/FontDescriptorHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/FontDescriptorHelper.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/FontDescriptorHelper.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/FontDescriptorHelper.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,208 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.descriptor;
+
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_DESCRIPTOR_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_FONT_FILEX_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_CATEGORY_PROPERTY_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_FORMAT;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_FORMAT_STREAM;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_FORMAT_UNKOWN;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_FORMAT_XPACKET;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_RDF_ABOUT_ATTRIBUTE_MISSING;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_METADATA_UNKNOWN_VALUETYPE;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_SYNTAX_STREAM_INVALID_FILTER;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_ASCENT;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_CAPHEIGHT;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_DESCENT;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_FLAGS;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_FONTBBOX;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_FONTNAME;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_ITALICANGLE;
+import static org.apache.pdfbox.preflight.PreflightConstants.FONT_DICTIONARY_KEY_STEMV;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.padaf.xmpbox.XMPMetadata;
+import org.apache.padaf.xmpbox.parser.XMPDocumentBuilder;
+import org.apache.padaf.xmpbox.parser.XmpExpectedRdfAboutAttribute;
+import org.apache.padaf.xmpbox.parser.XmpParsingException;
+import org.apache.padaf.xmpbox.parser.XmpSchemaException;
+import org.apache.padaf.xmpbox.parser.XmpUnknownValueTypeException;
+import org.apache.padaf.xmpbox.parser.XmpXpacketEndException;
+import org.apache.padaf.xmpbox.type.BadFieldValueException;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.common.PDMetadata;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+import org.apache.pdfbox.preflight.PreflightContext;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.preflight.font.container.FontContainer;
+import org.apache.pdfbox.preflight.font.util.FontMetaDataValidation;
+
+public abstract class FontDescriptorHelper <T extends FontContainer> {
+
+	protected T fContainer;
+
+	protected PreflightContext context;
+	protected PDFont font;
+
+	protected PDFontDescriptorDictionary fontDescriptor;
+	
+	public FontDescriptorHelper(PreflightContext context, PDFont font, T fontContainer) {
+		super();
+		this.fContainer = fontContainer;
+		this.context = context;
+		this.font = font;
+	}
+
+	public void validate() {
+		PDFontDescriptor fd = this.font.getFontDescriptor();
+		// Only a PDFontDescriptorDictionary provides a way to embedded the font program.
+		if(fd != null && fd instanceof PDFontDescriptorDictionary) {
+			fontDescriptor = (PDFontDescriptorDictionary)fd;
+			
+			if (checkMandatoryFields(fontDescriptor.getCOSDictionary())) {
+				if (hasOnlyOneFontFile(fontDescriptor)) {
+					PDStream fontFile = extractFontFile(fontDescriptor);
+					if (fontFile != null) {
+						processFontFile(fontDescriptor, fontFile);
+						checkFontFileMetaData(fontDescriptor, fontFile);
+					}
+				} else {
+					this.fContainer.push(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID,	"They are more than one FontFile"));
+				}
+			}
+		} else {
+			this.fContainer.push(new ValidationError(ERROR_FONTS_DESCRIPTOR_INVALID, "FontDescriptor is null or is a AFM Descriptor"));
+			this.fContainer.notEmbedded();
+		}
+	}
+
+	protected boolean checkMandatoryFields(COSDictionary fDescriptor) {
+		boolean areFieldsPresent = fDescriptor.containsKey(FONT_DICTIONARY_KEY_FONTNAME);
+		areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_FLAGS);
+		areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_ITALICANGLE);
+		areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_CAPHEIGHT);
+		areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_FONTBBOX);
+		areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_ASCENT);
+		areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_DESCENT);
+		areFieldsPresent &= fDescriptor.containsKey(FONT_DICTIONARY_KEY_STEMV);
+		areFieldsPresent &= fDescriptor.containsKey(COSName.FONT_NAME);
+		if (!areFieldsPresent) {
+			this.fContainer.push(new ValidationError(ERROR_FONTS_DESCRIPTOR_INVALID, "Some mandatory fields are missing from the FontDescriptor"));
+		}
+		return areFieldsPresent;
+	}
+
+	public abstract PDStream extractFontFile(PDFontDescriptorDictionary fontDescriptor);
+
+	/**
+	 * Return true if the FontDescriptor has only one FontFile entry.
+	 * @param fontDescriptor
+	 * @return
+	 */
+	protected boolean hasOnlyOneFontFile(PDFontDescriptorDictionary fontDescriptor) {
+		PDStream ff1 = fontDescriptor.getFontFile();
+		PDStream ff2 = fontDescriptor.getFontFile2();
+		PDStream ff3 = fontDescriptor.getFontFile3();
+		return (ff1 != null ^ ff2 != null ^ ff3 != null);
+	}
+
+	protected abstract void processFontFile(PDFontDescriptorDictionary fontDescriptor, PDStream fontFile);
+
+	/**
+	 * Type0, Type1 and TrueType FontValidator call this method to check the FontFile meta data.
+	 * 
+	 * @param fontDescriptor The FontDescriptor which contains the FontFile stream
+	 * @param fontFile The font file stream to check
+	 */
+	protected void checkFontFileMetaData(PDFontDescriptor fontDescriptor, PDStream fontFile)  {
+		PDMetadata metadata = null;
+		try {
+			metadata = fontFile.getMetadata();
+			
+			if (metadata != null) {
+				// Filters are forbidden in a XMP stream
+				if (metadata.getFilters() != null && !metadata.getFilters().isEmpty()) {
+					this.fContainer.push(new ValidationError(ERROR_SYNTAX_STREAM_INVALID_FILTER,	"Filter specified in font file metadata dictionnary"));
+					return;
+				}
+
+				byte[] mdAsBytes = getMetaDataStreamAsBytes(metadata);
+
+				try {
+
+					XMPDocumentBuilder xmpBuilder = new XMPDocumentBuilder();
+					XMPMetadata xmpMeta = xmpBuilder.parse(mdAsBytes);
+
+					FontMetaDataValidation fontMDval = new FontMetaDataValidation();
+					List<ValidationError> ve = new ArrayList<ValidationError>();
+					fontMDval.analyseFontName(xmpMeta, fontDescriptor, ve);
+					fontMDval.analyseRights(xmpMeta, fontDescriptor, ve);
+					this.fContainer.push(ve);
+
+				} catch (XmpUnknownValueTypeException e) {
+					this.fContainer.push(new ValidationError(ERROR_METADATA_UNKNOWN_VALUETYPE, e.getMessage()));
+				} catch (XmpParsingException e) {
+					this.fContainer.push(new ValidationError(ERROR_METADATA_FORMAT, e.getMessage()));
+				} catch (XmpSchemaException e) {
+					this.fContainer.push(new ValidationError(ERROR_METADATA_FORMAT, e.getMessage()));
+				} catch (XmpExpectedRdfAboutAttribute e) {
+					this.fContainer.push(new ValidationError(ERROR_METADATA_RDF_ABOUT_ATTRIBUTE_MISSING,e.getMessage()));
+				} catch (BadFieldValueException e) {
+					this.fContainer.push(new ValidationError(ERROR_METADATA_CATEGORY_PROPERTY_INVALID,e.getMessage()));
+				} catch (XmpXpacketEndException e) {
+					this.fContainer.push(new ValidationError(ERROR_METADATA_FORMAT_XPACKET, "Unable to parse font metadata due to : "  + e.getMessage()));
+				}
+			}
+		} catch (IllegalStateException e) {
+			this.fContainer.push(new ValidationError(ERROR_METADATA_FORMAT_UNKOWN,	"The Metadata entry doesn't reference a stream object"));
+		}
+	}
+	
+	protected final byte[] getMetaDataStreamAsBytes(PDMetadata metadata) {
+		byte[] result = null;
+		ByteArrayOutputStream bos = null;
+		InputStream metaDataContent = null;
+		try {
+			bos = new ByteArrayOutputStream();
+			metaDataContent = metadata.createInputStream();
+			IOUtils.copyLarge(metaDataContent, bos);
+			result = bos.toByteArray();
+		} catch (IOException e) {
+			this.fContainer.push(new ValidationError(ERROR_METADATA_FORMAT_STREAM, "Unable to read font metadata due to : " + e.getMessage()));
+		} finally {
+			IOUtils.closeQuietly(metaDataContent);
+			IOUtils.closeQuietly(bos);
+		}
+		return result;
+	}
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/TrueTypeDescriptorHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/TrueTypeDescriptorHelper.java?rev=1361579&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/TrueTypeDescriptorHelper.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/descriptor/TrueTypeDescriptorHelper.java Sat Jul 14 19:53:48 2012
@@ -0,0 +1,91 @@
+/*****************************************************************************
+ * 
+ * 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.pdfbox.preflight.font.descriptor;
+
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_ENCODING;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_FONT_FILEX_INVALID;
+import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_TRUETYPE_DAMAGED;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.fontbox.ttf.TTFParser;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+import org.apache.pdfbox.preflight.PreflightContext;
+import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
+import org.apache.pdfbox.preflight.font.container.TrueTypeContainer;
+
+public class TrueTypeDescriptorHelper extends FontDescriptorHelper<TrueTypeContainer> {
+
+	public TrueTypeDescriptorHelper(PreflightContext context, PDFont font, TrueTypeContainer fontContainer) {
+		super(context, font, fontContainer);
+	}
+
+	public PDStream extractFontFile(PDFontDescriptorDictionary fontDescriptor) {
+		PDStream fontFile = fontDescriptor.getFontFile2();
+		COSStream stream =  (fontFile != null ? fontFile.getStream() : null);
+		if (stream == null) {
+			this.fContainer.push(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile2 is missing"));
+			this.fContainer.notEmbedded();
+			return null;
+		}
+
+		if (stream.getInt(COSName.LENGTH1) <= 0) {
+			this.fContainer.push(new ValidationError(ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile entry /Length1 is invalid"));
+			return null;
+		}
+
+		return fontFile;
+	}
+	
+	protected void processFontFile(PDFontDescriptorDictionary fontDescriptor, PDStream fontFile) {
+		/*
+		 * 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(fontFile.getByteArray());
+			TrueTypeFont ttf = new TTFParser(true).parseTTF(bis);
+
+			if (fontDescriptor.isSymbolic() && ttf.getCMAP().getCmaps().length != 1) {
+				this.fContainer.push(new ValidationError(ERROR_FONTS_ENCODING, "The Encoding should be missing for the Symbolic TTF"));
+			} else {
+				((TrueTypeContainer)this.fContainer).setTrueTypeFont(ttf);
+				// TODO check the WIdth consistency too				
+			}
+		} catch (IOException e) {
+			this.fContainer.push(new ValidationError(ERROR_FONTS_TRUETYPE_DAMAGED, "The FontFile can't be read"));
+		} finally {
+			IOUtils.closeQuietly(bis);
+		}
+	}
+}

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