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 [6/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/Type1FontContainer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1FontContainer.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1FontContainer.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1FontContainer.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,129 @@
+/*****************************************************************************
+ * 
+ * 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.cff.CFFFont;
+import org.apache.fontbox.cff.CFFFont.Mapping;
+import org.apache.padaf.preflight.ValidationConstants;
+import org.apache.padaf.preflight.font.type1.Type1;
+import org.apache.pdfbox.cos.COSInteger;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+
+public class Type1FontContainer 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 Type1Font data extracted by the
+	 * Type1Parser object
+	 */
+	private Type1 fontObject = null;
+
+	private List<CFFFont> cffFonts= null;
+
+	public Type1FontContainer(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 setFontObject(Type1 fontObject) {
+		this.fontObject = fontObject;
+	}
+
+	void setCFFFontObjects(List<CFFFont> fontObject) {
+		this.cffFonts = fontObject;
+	}
+
+	@Override
+	public void checkCID(int cid) throws GlyphException {
+		if (isAlreadyComputedCid(cid)) {
+			return;
+		}
+
+		int indexOfWidth = (cid - firstCharInWidthsArray);
+		float widthProvidedByPdfDictionary = this.defaultGlyphWidth;
+
+		int widthInFontProgram =0;
+		try {
+			if (this.fontObject != null) {
+				widthInFontProgram = this.fontObject.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 : cffFonts) {
+					int SID = cff.getEncoding().getSID(cid);
+					for (Mapping m : cff.getMappings() ){
+						if (m.getName().equals(name)) {
+							SID = m.getSID();
+							break;
+						}
+					}
+					widthInFontProgram = cff.getWidth(SID);
+					if (widthInFontProgram != defaultGlyphWidth) {
+						break;
+					}
+				}
+			}
+		} catch (GlyphException e) {
+			addKnownCidElement(new GlyphDetail(cid, e));
+			throw e;
+		} catch (IOException e) {
+			GlyphException ge = new GlyphException(ValidationConstants.ERROR_FONTS_DAMAGED, cid, 
+					"Unable to get width of the CID/SID : " + cid);
+			addKnownCidElement(new GlyphDetail(cid, ge));
+			throw ge;
+		}
+
+		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/Type1FontContainer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1FontValidator.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1FontValidator.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1FontValidator.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1FontValidator.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,323 @@
+/*****************************************************************************
+ * 
+ * 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.Font;
+import java.awt.FontFormatException;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+
+import org.apache.commons.io.IOUtils;
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.cff.CFFParser;
+import org.apache.padaf.preflight.DocumentHandler;
+import org.apache.padaf.preflight.ValidationException;
+import org.apache.padaf.preflight.ValidationResult;
+import org.apache.padaf.preflight.ValidationResult.ValidationError;
+import org.apache.padaf.preflight.font.type1.Type1;
+import org.apache.padaf.preflight.font.type1.Type1Parser;
+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.COSArrayList;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+
+public class Type1FontValidator extends SimpleFontValidator {
+
+	public Type1FontValidator(DocumentHandler handler, COSObject obj)
+	throws ValidationException {
+		super(handler, obj);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @seenet.awl.edoc.pdfa.validation.font.SimpleFontValidator#
+	 * checkSpecificMandatoryFields()
+	 */
+	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"));
+			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
+		// ---- Event if the Font is one of the 14 standard Fonts, those keys are
+		// mandatory for a PDF/A
+		return true;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * net.awl.edoc.pdfa.validation.font.SimpleFontValidator#checkEncoding(org
+	 * .apache.pdfbox.cos.COSDocument)
+	 */
+	protected boolean checkEncoding(COSDocument cDoc) {
+		if (COSUtils.isString(this.encoding, cDoc)) {
+			String encodingName = COSUtils.getAsString(this.encoding, cDoc);
+			if (!(encodingName.equals(FONT_DICTIONARY_VALUE_ENCODING_MAC)
+					|| encodingName.equals(FONT_DICTIONARY_VALUE_ENCODING_MAC_EXP)
+					|| encodingName.equals(FONT_DICTIONARY_VALUE_ENCODING_WIN)
+					|| encodingName.equals(FONT_DICTIONARY_VALUE_ENCODING_PDFDOC) || encodingName
+					.equals(FONT_DICTIONARY_VALUE_ENCODING_STD))) {
+				this.fontContainer.addError(new ValidationError(ERROR_FONTS_ENCODING));
+				return false;
+			}
+		} else if (COSUtils.isDictionary(this.encoding, cDoc)) {
+			this.pFont.getFontEncoding();
+		} else if (this.encoding != null) {
+			this.fontContainer.addError(new ValidationError(ERROR_FONTS_ENCODING));
+			return false;
+		} 
+		//else
+		// ---- According to PDF Reference, the encoding entry is optional.
+		// PDF/A specification only speaks of TrueType encoding
+
+		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;
+	}
+
+	/**
+	 * Check if the font name is present and if fontName equals to the baseName.
+	 * If the validation fails, false is returned and the FontContainer is
+	 * updated.
+	 * 
+	 * @return
+	 */
+	boolean checkFontName() {
+		String fontName = this.pFontDesc.getFontName();
+		String baseName = this.pFont.getBaseFont();
+
+		// For a Type1 Font, the FontName is the same as the BaseName.
+		if (fontName == null || (!fontName.equals(baseName))) {
+			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 methods validates the Font Stream, if the font program is damaged or
+	 * missing the FontContainer is updated and false is returned.
+	 * 
+	 * @throws ValidationException
+	 */
+	protected boolean checkFontFileElement() throws ValidationException {
+		// ---- if the this font is a Subset, the CharSet entry must be present in
+		// the FontDescriptor
+		if (isSubSet(pFontDesc.getFontName())) {
+			String charsetStr = pFontDesc.getCharSet();
+			if (charsetStr == null || "".equals(charsetStr)) {
+				this.fontContainer.addError(new ValidationResult.ValidationError(
+						ERROR_FONTS_CHARSET_MISSING_FOR_SUBSET,
+				"The Charset entry is missing for the Type1 Subset"));
+				return false;
+			}
+		}
+
+		// ---- FontFile Validation
+		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 ((ff1 == null && (ff3 == null || !"Type1C".equals(((COSDictionary)ff3.getCOSObject()).getNameAsString(COSName.SUBTYPE)))) || !onlyOne) {
+			this.fontContainer.addError(new ValidationResult.ValidationError(
+					ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is invalid"));
+			return false;
+		}
+
+		if (ff1 != null) {
+			COSStream stream = ff1.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;
+			boolean hasLength2 = stream.getInt(COSName.getPDFName(FONT_DICTIONARY_KEY_LENGTH2)) > 0;
+			boolean hasLength3 = stream.getInt(COSName.getPDFName(FONT_DICTIONARY_KEY_LENGTH3)) > 0;
+			if (!(hasLength1 && hasLength2 && hasLength3)) {
+				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
+			// ---- try to load the font using the java.awt.font object.
+			// ---- if the font is invalid, an exception will be thrown
+			ByteArrayInputStream bis = null;
+			try {
+				bis = new ByteArrayInputStream(ff1.getByteArray());
+				Font.createFont(Font.TYPE1_FONT, bis);
+				return checkFontMetricsDataAndFeedFontContainer(ff1) && checkFontFileMetaData(pFontDesc, ff1);
+			} catch (IOException e) {
+				this.fontContainer.addError(new ValidationResult.ValidationError(
+						ERROR_FONTS_TYPE1_DAMAGED, "The FontFile can't be read"));
+				return false;
+			} catch (FontFormatException e) {
+				this.fontContainer.addError(new ValidationResult.ValidationError(
+						ERROR_FONTS_TYPE1_DAMAGED, "The FontFile is damaged"));
+				return false;
+			} finally {
+				if (bis != null) {
+					IOUtils.closeQuietly(bis);
+				}
+			}
+		} else {
+			return checkCIDFontWidths(ff3) && checkFontFileMetaData(pFontDesc, ff3);
+		}
+	}
+
+	/**
+	 * Type1C is a CFF font format, extract all CFFFont object from the stream
+	 * 
+	 * @param fontStream
+	 * @return
+	 * @throws ValidationException
+	 */
+	protected boolean checkCIDFontWidths(PDStream fontStream)
+	throws ValidationException {
+		try {
+			CFFParser cffParser = new CFFParser();
+			List<CFFFont> lCFonts = cffParser.parse(fontStream.getByteArray());
+
+			if (lCFonts == null || lCFonts.isEmpty()) {
+				this.fontContainer.addError(new ValidationResult.ValidationError(
+						ERROR_FONTS_CID_DAMAGED, "The FontFile can't be read"));
+				return false;
+			}
+
+			((Type1FontContainer)this.fontContainer).setCFFFontObjects(lCFonts);
+
+
+			List<?> pdfWidths = this.pFont.getWidths();
+			int firstChar = pFont.getFirstChar();
+			float defaultGlyphWidth = pFontDesc.getMissingWidth();
+
+			COSArray widths = null;
+			if (pdfWidths instanceof COSArrayList) {
+				widths = ((COSArrayList) pdfWidths).toList();
+			} else {
+				widths = ((COSArray) pdfWidths);
+			}
+
+			((Type1FontContainer)this.fontContainer).setWidthsArray(widths.toList());
+			((Type1FontContainer)this.fontContainer).setFirstCharInWidthsArray(firstChar);
+			((Type1FontContainer)this.fontContainer).setDefaultGlyphWidth(defaultGlyphWidth);
+
+			return true;
+		} 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 and adds the FontContainer in the
+	 * DocumentHandler.
+	 * 
+	 * @param fontStream
+	 * @return
+	 * @throws ValidationException
+	 */
+	protected boolean checkFontMetricsDataAndFeedFontContainer(PDStream fontStream)
+	throws ValidationException {
+		try {
+
+			// ---- Parse the Type1 Font program
+			ByteArrayInputStream bis = new ByteArrayInputStream(fontStream
+					.getByteArray());
+			COSStream streamObj = fontStream.getStream();
+			int length1 = streamObj.getInt(COSName
+					.getPDFName(FONT_DICTIONARY_KEY_LENGTH1));
+			int length2 = streamObj.getInt(COSName
+					.getPDFName(FONT_DICTIONARY_KEY_LENGTH2));
+
+			Type1Parser parserForMetrics = Type1Parser.createParserWithEncodingObject(bis, length1, length2, pFont.getFontEncoding());
+			Type1 parsedData = parserForMetrics.parse();
+
+			((Type1FontContainer)this.fontContainer).setFontObject(parsedData);
+
+			List<?> pdfWidths = this.pFont.getWidths();
+			int firstChar = pFont.getFirstChar();
+			float defaultGlyphWidth = pFontDesc.getMissingWidth();
+
+			COSArray widths = null;
+			if (pdfWidths instanceof COSArrayList) {
+				widths = ((COSArrayList) pdfWidths).toList();
+			} else {
+				widths = ((COSArray) pdfWidths);
+			}
+
+			((Type1FontContainer)this.fontContainer).setWidthsArray(widths.toList());
+			((Type1FontContainer)this.fontContainer).setFirstCharInWidthsArray(firstChar);
+			((Type1FontContainer)this.fontContainer).setDefaultGlyphWidth(defaultGlyphWidth);
+
+			return true;
+		} catch (IOException e) {
+			throw new ValidationException("Unable to check Type1 metrics due to : "
+					+ e.getMessage(), e);
+		}
+	}
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1MetricHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1MetricHelper.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1MetricHelper.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type1MetricHelper.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,1060 @@
+/*****************************************************************************
+ * 
+ * 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.FONT_DICTIONARY_VALUE_ENCODING_MAC;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_ENCODING_MAC_EXP;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_ENCODING_PDFDOC;
+import static org.apache.padaf.preflight.ValidationConstants.FONT_DICTIONARY_VALUE_ENCODING_WIN;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+import org.apache.commons.io.IOUtils;
+import org.apache.fontbox.cff.CharStringCommand;
+import org.apache.fontbox.cff.Type1CharStringParser;
+import org.apache.fontbox.cff.Type1FontUtil;
+import org.apache.padaf.preflight.ValidationException;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.encoding.Encoding;
+import org.apache.pdfbox.encoding.MacRomanEncoding;
+import org.apache.pdfbox.encoding.PdfDocEncoding;
+import org.apache.pdfbox.encoding.StandardEncoding;
+import org.apache.pdfbox.encoding.WinAnsiEncoding;
+
+/**
+ * This class computes a Type1 font stream to extract Glyph Metrics. The given
+ * stream must be a valid type 1 stream.
+ * 
+ * Remark : According to the PDF Reference only PostScript Type 1 binary fonts
+ * are allowed in a conforming PDF file so the encrypted "eexec" data are
+ * considered as binary data...
+ * 
+ * This class is depreciated, now it is better to use the Type1Parser. 
+ */
+@Deprecated 
+public class Type1MetricHelper {
+	protected static final char NAME_START = '/';
+
+	protected static final int FULL_NAME_TOKEN = 1;
+	protected static final int FAMILY_NAME_TOKEN = 2;
+	protected static final int DUP_TOKEN = 3;
+	protected static final int FONT_NAME_TOKEN = 4;
+	protected static final int ENCODING_TOKEN = 5;
+	protected static final int READONLY_TOKEN = 6;
+
+	protected static final int LEN_IV_TOKEN = 7;
+	protected static final int CHARSTRINGS_TOKEN = 8;
+	protected static final int CHAR_LABEL_TOKEN = 9;
+
+	protected static final int OBJ_NAME_TOKEN = 10;
+
+	protected static final String NOTDEF = "/.notdef";
+
+	private static final String PS_STANDARD_ENCODING = "StandardEncoding";
+	private static final String PS_ISOLATIN_ENCODING = "ISOLatin1Encoding";
+
+	/**
+	 * The PostScript font stream.
+	 */
+	private InputStream font = null;
+	/**
+	 * The length in bytes of the clear-text portion of the Type1 font program.
+	 */
+	private int clearTextSize = 0;
+	/**
+	 * The length in bytes of the eexec encrypted portion of the type1 font
+	 * program.
+	 */
+	private int eexecSize = 0;
+	/**
+	 * This map links the character identifier to a internal font program label
+	 * which is different from the standard Encoding
+	 */
+	private Map<Integer, String> cidToLabel = new HashMap<Integer, String>(0);
+	/**
+	 * This map links the character label to a character identifier which is
+	 * different from the standard Encoding.
+	 */
+	private Map<String, Integer> labelToCid = new HashMap<String, Integer>(0);
+	/**
+	 * This map link the character label to a container containing Glyph
+	 * description.
+	 */
+	private Map<String, Type1GlyphDescription> labelToMetric = new HashMap<String, Type1GlyphDescription>(
+			0);
+
+	/**
+	 * The character encoding of the Font
+	 */
+	private Encoding encoding = null;
+
+	/**
+	 * The family name of the font
+	 */
+	protected String familyName = null;
+	/**
+	 * The full name of the font
+	 */
+	protected String fullName = null;
+	/**
+	 * The font name of the font
+	 */
+	protected String fontName = null;
+
+	/**
+	 * 
+	 * @param type1
+	 *          The unfiltered PostScript Type 1 Font stream.
+	 * @param length1
+	 *          The length in bytes of the clear-text portion of the Type1 font
+	 *          program.
+	 * @param length2
+	 *          The length in bytes of the eexec encrypted portion of the type1
+	 *          font program.
+	 * @param encodingName
+	 *          the Encoding name, StandardEncoding is used for unknown name
+	 */
+	public Type1MetricHelper(InputStream type1, int length1, int length2,
+			String encodingName) {
+		super();
+		this.font = type1;
+		this.clearTextSize = length1;
+		this.eexecSize = length2;
+		this.cidToLabel.put(-1, NOTDEF);
+		this.labelToCid.put(NOTDEF, -1);
+		
+		
+		// ---- Instantiate the Encoding Map
+		if (FONT_DICTIONARY_VALUE_ENCODING_MAC.equals(encodingName)) {
+			this.encoding = new MacRomanEncoding();
+		} else if (FONT_DICTIONARY_VALUE_ENCODING_MAC_EXP.equals(encodingName)) {
+			this.encoding = new MacRomanEncoding();
+		} else if (FONT_DICTIONARY_VALUE_ENCODING_WIN.equals(encodingName)) {
+			this.encoding = new WinAnsiEncoding();
+		} else if (FONT_DICTIONARY_VALUE_ENCODING_PDFDOC.equals(encodingName)) {
+			this.encoding = new PdfDocEncoding();
+		} else {
+			this.encoding = new StandardEncoding();
+		}
+	}
+
+	/**
+	 * 
+	 * @param type1
+	 *          The unfiltered PostScript Type 1 Font stream.
+	 * @param length1
+	 *          The length in bytes of the clear-text portion of the Type1 font
+	 *          program.
+	 * @param length2
+	 *          The length in bytes of the eexec encrypted portion of the type1
+	 *          font program.
+	 * @param enc
+	 *          The Encoding inherited Object
+	 */
+	public Type1MetricHelper(InputStream type1, int length1, int length2,
+			Encoding enc) {
+		super();
+		this.font = type1;
+		this.clearTextSize = length1;
+		this.eexecSize = length2;
+		this.cidToLabel.put(-1, NOTDEF);
+		this.labelToCid.put(NOTDEF, -1);
+
+		// ---- Instantiate the Encoding Map
+		if (enc != null) {
+			this.encoding = enc;
+		} else {
+			this.encoding = new StandardEncoding();
+		}
+	}
+
+	/**
+	 * Close the font stream
+	 */
+	public void close() {
+		IOUtils.closeQuietly(this.font);
+	}
+
+	private void createStandardEncoding() {
+		this.labelToCid.put("/A", 0101);
+		this.labelToCid.put("/AE", 0341);
+		this.labelToCid.put("/B", 0102);
+		this.labelToCid.put("/C", 0103);
+		this.labelToCid.put("/D", 0104);
+		this.labelToCid.put("/E", 0105);
+		this.labelToCid.put("/F", 0106);
+		this.labelToCid.put("/G", 0107);
+		this.labelToCid.put("/H", 0110);
+		this.labelToCid.put("/I", 0111);
+		this.labelToCid.put("/J", 0112);
+		this.labelToCid.put("/K", 0113);
+		this.labelToCid.put("/L", 0114);
+		this.labelToCid.put("/Lslash", 0350);
+		this.labelToCid.put("/M", 0115);
+		this.labelToCid.put("/N", 0116);
+		this.labelToCid.put("/O", 0117);
+		this.labelToCid.put("/OE", 0352);
+		this.labelToCid.put("/Oslash", 0351);
+		this.labelToCid.put("/P", 0120);
+		this.labelToCid.put("/Q", 0121);
+		this.labelToCid.put("/R", 0122);
+		this.labelToCid.put("/S", 0123);
+		this.labelToCid.put("/T", 0124);
+		this.labelToCid.put("/U", 0125);
+		this.labelToCid.put("/V", 0126);
+		this.labelToCid.put("/W", 0127);
+		this.labelToCid.put("/X", 0130);
+		this.labelToCid.put("/Y", 0131);
+		this.labelToCid.put("/Z", 0132);
+		this.labelToCid.put("/a", 0141);
+		this.labelToCid.put("/acute", 0302);
+		this.labelToCid.put("/acute", 0302);
+		this.labelToCid.put("/ae", 0361);
+		this.labelToCid.put("/ampersand", 046);
+		this.labelToCid.put("/asciicircum", 0136);
+		this.labelToCid.put("/asciitilde", 0176);
+		this.labelToCid.put("/asterisk", 052);
+		this.labelToCid.put("/at", 0100);
+		this.labelToCid.put("/b", 0142);
+		this.labelToCid.put("/backslash", 0134);
+		this.labelToCid.put("/bar", 0174);
+		this.labelToCid.put("/braceleft", 0173);
+		this.labelToCid.put("/braceright", 0175);
+		this.labelToCid.put("/bracketleft", 0133);
+		this.labelToCid.put("/bracketright", 0135);
+		this.labelToCid.put("/breve", 0306);
+		this.labelToCid.put("/bullet", 0267);
+		this.labelToCid.put("/c", 0143);
+		this.labelToCid.put("/caron", 0317);
+		this.labelToCid.put("/cedilla", 0313);
+		this.labelToCid.put("/cent", 0242);
+		this.labelToCid.put("/circumflex", 0303);
+		this.labelToCid.put("/colon", 072);
+		this.labelToCid.put("/comma", 054);
+		this.labelToCid.put("/currency", 0250);
+		this.labelToCid.put("/d", 0144);
+		this.labelToCid.put("/dagger", 0262);
+		this.labelToCid.put("/daggerdbl", 0263);
+		this.labelToCid.put("/dieresis", 0310);
+		this.labelToCid.put("/dollar", 044);
+		this.labelToCid.put("/dotaccent", 0307);
+		this.labelToCid.put("/dotlessi", 0365);
+		this.labelToCid.put("/e", 0145);
+		this.labelToCid.put("/eight", 070);
+		this.labelToCid.put("/ellipsis", 274);
+		this.labelToCid.put("/emdash", 0320);
+		this.labelToCid.put("/endash", 0261);
+		this.labelToCid.put("/equal", 075);
+		this.labelToCid.put("/exclam", 041);
+		this.labelToCid.put("/exclamdown", 0241);
+		this.labelToCid.put("/f", 0146);
+		this.labelToCid.put("/fi", 0256);
+		this.labelToCid.put("/five", 0065);
+		this.labelToCid.put("/fl", 0257);
+		this.labelToCid.put("/florin", 0246);
+		this.labelToCid.put("/four", 064);
+		this.labelToCid.put("/fraction", 0244);
+		this.labelToCid.put("/g", 0147);
+		this.labelToCid.put("/germandbls", 0373);
+		this.labelToCid.put("/grave", 0301);
+		this.labelToCid.put("/greater", 0076);
+		this.labelToCid.put("/guillemotleft", 0253);
+		this.labelToCid.put("/guillemotright", 0273);
+		this.labelToCid.put("/guilsinglleft", 0254);
+		this.labelToCid.put("/guilsinglright", 0255);
+		this.labelToCid.put("/h", 0150);
+		this.labelToCid.put("/hungarumlaut", 0315);
+		this.labelToCid.put("/hyphen", 055);
+		this.labelToCid.put("/i", 0151);
+		this.labelToCid.put("/j", 0152);
+		this.labelToCid.put("/k", 0153);
+		this.labelToCid.put("/l", 0154);
+		this.labelToCid.put("/less", 0074);
+		this.labelToCid.put("/lslash", 0370);
+		this.labelToCid.put("/m", 0155);
+		this.labelToCid.put("/macron", 0305);
+		this.labelToCid.put("/n", 0156);
+		this.labelToCid.put("/nine", 071);
+		this.labelToCid.put("/numbersign", 043);
+		this.labelToCid.put("/o", 0157);
+		this.labelToCid.put("/oe", 0372);
+		this.labelToCid.put("/ogonek", 0316);
+		this.labelToCid.put("/one", 061);
+		this.labelToCid.put("/ordfeminine", 0343);
+		this.labelToCid.put("/ordmasculine", 0353);
+		this.labelToCid.put("/oslash", 0371);
+		this.labelToCid.put("/p", 0160);
+		this.labelToCid.put("/paragraph", 0266);
+		this.labelToCid.put("/parenleft", 050);
+		this.labelToCid.put("/parenright", 051);
+		this.labelToCid.put("/percent", 045);
+		this.labelToCid.put("/period", 056);
+		this.labelToCid.put("/periodcentered", 0264);
+		this.labelToCid.put("/perthousand", 0275);
+		this.labelToCid.put("/plus", 0053);
+		this.labelToCid.put("/q", 0161);
+		this.labelToCid.put("/question", 077);
+		this.labelToCid.put("/questiondown", 0277);
+		this.labelToCid.put("/quotedbl", 0042);
+		this.labelToCid.put("/quotedblbase", 0271);
+		this.labelToCid.put("/quotedblleft", 0252);
+		this.labelToCid.put("/quotedblright", 0272);
+		this.labelToCid.put("/quoteleft", 0140);
+		this.labelToCid.put("/quoteright", 047);
+		this.labelToCid.put("/quotesinglbase", 0270);
+		this.labelToCid.put("/quotesingle", 0251);
+		this.labelToCid.put("/r", 0162);
+		this.labelToCid.put("/ring", 0312);
+		this.labelToCid.put("/s", 0163);
+		this.labelToCid.put("/section", 0247);
+		this.labelToCid.put("/semicolon", 0073);
+		this.labelToCid.put("/seven", 0067);
+		this.labelToCid.put("/six", 066);
+		this.labelToCid.put("/slash", 057);
+		this.labelToCid.put("/space", 040);
+		this.labelToCid.put("/sterling", 0243);
+		this.labelToCid.put("/t", 0164);
+		this.labelToCid.put("/three", 063);
+		this.labelToCid.put("/tilde", 0304);
+		this.labelToCid.put("/two", 062);
+		this.labelToCid.put("/u", 0165);
+		this.labelToCid.put("/underscore", 0137);
+		this.labelToCid.put("/v", 0166);
+		this.labelToCid.put("/w", 0167);
+		this.labelToCid.put("/x", 0170);
+		this.labelToCid.put("/y", 0171);
+		this.labelToCid.put("/yen", 0245);
+		this.labelToCid.put("/z", 0172);
+		this.labelToCid.put("/zero", 060);
+		transafertLTOCinCTIL();
+	}
+
+	private void transafertLTOCinCTIL() {
+		for (Entry<String, Integer> entry : this.labelToCid.entrySet()) {
+			this.cidToLabel.put(entry.getValue(), entry.getKey());
+		}
+	}
+
+	private void createISOLatin1Encoding() {
+		this.labelToCid.put("/A", 0101);
+		this.labelToCid.put("/AE", 0306);
+		this.labelToCid.put("/Aacute", 0301);
+		this.labelToCid.put("/Acircumflex", 0302);
+		this.labelToCid.put("/Adieresis", 0304);
+		this.labelToCid.put("/Agrave", 0300);
+		this.labelToCid.put("/Aring", 0305);
+		this.labelToCid.put("/Atilde", 0303);
+		this.labelToCid.put("/B", 0102);
+		this.labelToCid.put("/C", 0103);
+		this.labelToCid.put("/Ccedilla", 0307);
+		this.labelToCid.put("/D", 0104);
+		this.labelToCid.put("/E", 0105);
+		this.labelToCid.put("/Eacute", 0311);
+		this.labelToCid.put("/Ecircumflex", 0312);
+		this.labelToCid.put("/Edieresis", 0313);
+		this.labelToCid.put("/Egrave", 0310);
+		this.labelToCid.put("/Eth", 0320);
+		this.labelToCid.put("/F", 0106);
+		this.labelToCid.put("/G", 0107);
+		this.labelToCid.put("/H", 0110);
+		this.labelToCid.put("/I", 0111);
+		this.labelToCid.put("/Iacute", 0315);
+		this.labelToCid.put("/Icircumflex", 0316);
+		this.labelToCid.put("/Idieresis", 0317);
+		this.labelToCid.put("/Igrave", 0314);
+		this.labelToCid.put("/J", 0112);
+		this.labelToCid.put("/K", 0113);
+		this.labelToCid.put("/L", 0114);
+		this.labelToCid.put("/M", 0115);
+		this.labelToCid.put("/N", 0116);
+		this.labelToCid.put("/Ntilde", 0321);
+		this.labelToCid.put("/O", 0117);
+		this.labelToCid.put("/Oacute", 0323);
+		this.labelToCid.put("/Ocircumflex", 0324);
+		this.labelToCid.put("/Odieresis", 0326);
+		this.labelToCid.put("/Ograve", 0322);
+		this.labelToCid.put("/Oslash", 0330);
+		this.labelToCid.put("/Otilde", 0325);
+		this.labelToCid.put("/P", 0120);
+		this.labelToCid.put("/Q", 0121);
+		this.labelToCid.put("/R", 0122);
+		this.labelToCid.put("/S", 0123);
+		this.labelToCid.put("/T", 0124);
+		this.labelToCid.put("/Thorn", 0336);
+		this.labelToCid.put("/U", 0125);
+		this.labelToCid.put("/Uacute", 0332);
+		this.labelToCid.put("/Ucircumflex", 0333);
+		this.labelToCid.put("/Udieresis", 0334);
+		this.labelToCid.put("/Ugrave", 0331);
+		this.labelToCid.put("/V", 0126);
+		this.labelToCid.put("/W", 0127);
+		this.labelToCid.put("/X", 0130);
+		this.labelToCid.put("/Y", 0131);
+		this.labelToCid.put("/Yacute", 0335);
+		this.labelToCid.put("/Z", 0132);
+		this.labelToCid.put("/a", 0141);
+		this.labelToCid.put("/aacute", 0341);
+		this.labelToCid.put("/acircumflex", 0342);
+		this.labelToCid.put("/acute", 0222);
+		this.labelToCid.put("/acute", 0264);
+		this.labelToCid.put("/adieresis", 0344);
+		this.labelToCid.put("/ae", 0346);
+		this.labelToCid.put("/agrave", 0340);
+		this.labelToCid.put("/ampersand", 0046);
+		this.labelToCid.put("/aring", 0345);
+		this.labelToCid.put("/asciicircum", 0136);
+		this.labelToCid.put("/asciitilde", 0176);
+		this.labelToCid.put("/asterisk", 0052);
+		this.labelToCid.put("/at", 0100);
+		this.labelToCid.put("/atilde", 0343);
+		this.labelToCid.put("/b", 0142);
+		this.labelToCid.put("/backslash", 0134);
+		this.labelToCid.put("/bar", 0174);
+		this.labelToCid.put("/braceleft", 0173);
+		this.labelToCid.put("/braceright", 0175);
+		this.labelToCid.put("/bracketleft", 0133);
+		this.labelToCid.put("/bracketright", 0135);
+		this.labelToCid.put("/breve", 0226);
+		this.labelToCid.put("/brokenbar", 0246);
+		this.labelToCid.put("/c", 0143);
+		this.labelToCid.put("/caron", 0237);
+		this.labelToCid.put("/ccedilla", 0347);
+		this.labelToCid.put("/cedilla", 0270);
+		this.labelToCid.put("/cent", 0242);
+		this.labelToCid.put("/circumflex", 0223);
+		this.labelToCid.put("/colon", 0072);
+		this.labelToCid.put("/comma", 0054);
+		this.labelToCid.put("/copyright", 0251);
+		this.labelToCid.put("/currency", 0244);
+		this.labelToCid.put("/d", 0144);
+		this.labelToCid.put("/degree", 0260);
+		this.labelToCid.put("/dieresis", 0250);
+		this.labelToCid.put("/divide", 0367);
+		this.labelToCid.put("/dollar", 0044);
+		this.labelToCid.put("/dotaccent", 0227);
+		this.labelToCid.put("/dotlessi", 0220);
+		this.labelToCid.put("/e", 0145);
+		this.labelToCid.put("/eacute", 0351);
+		this.labelToCid.put("/ecircumflex", 0352);
+		this.labelToCid.put("/edieresis", 0353);
+		this.labelToCid.put("/egrave", 0350);
+		this.labelToCid.put("/eight", 0070);
+		this.labelToCid.put("/equal", 0075);
+		this.labelToCid.put("/eth", 0360);
+		this.labelToCid.put("/exclam", 0041);
+		this.labelToCid.put("/exclamdown", 0241);
+		this.labelToCid.put("/f", 0146);
+		this.labelToCid.put("/five", 0065);
+		this.labelToCid.put("/four", 0064);
+		this.labelToCid.put("/g", 0147);
+		this.labelToCid.put("/germandbls", 0337);
+		this.labelToCid.put("/grave", 0221);
+		this.labelToCid.put("/greater", 0076);
+		this.labelToCid.put("/guillemotleft", 0253);
+		this.labelToCid.put("/guillemotright", 0273);
+		this.labelToCid.put("/h", 0150);
+		this.labelToCid.put("/hungarumlaut", 0235);
+		this.labelToCid.put("/hyphen", 0255);
+		this.labelToCid.put("/i", 0151);
+		this.labelToCid.put("/iacute", 0355);
+		this.labelToCid.put("/icircumflex", 0356);
+		this.labelToCid.put("/idieresis", 0357);
+		this.labelToCid.put("/igrave", 0354);
+		this.labelToCid.put("/j", 0152);
+		this.labelToCid.put("/k", 0153);
+		this.labelToCid.put("/l", 0154);
+		this.labelToCid.put("/less", 0074);
+		this.labelToCid.put("/logicalnot", 0254);
+		this.labelToCid.put("/m", 0155);
+		this.labelToCid.put("/macron", 0257);
+		this.labelToCid.put("/minus", 0055);
+		this.labelToCid.put("/mu", 0265);
+		this.labelToCid.put("/multiply", 0327);
+		this.labelToCid.put("/n", 0156);
+		this.labelToCid.put("/nine", 0071);
+		this.labelToCid.put("/ntilde", 0361);
+		this.labelToCid.put("/numbersign", 0043);
+		this.labelToCid.put("/o", 0157);
+		this.labelToCid.put("/oacute", 0363);
+		this.labelToCid.put("/ocircumflex", 0364);
+		this.labelToCid.put("/odieresis", 0366);
+		this.labelToCid.put("/ogonek", 0236);
+		this.labelToCid.put("/ograve", 0362);
+		this.labelToCid.put("/one", 0061);
+		this.labelToCid.put("/onehalf", 0275);
+		this.labelToCid.put("/onequarter", 0274);
+		this.labelToCid.put("/onesuperior", 0271);
+		this.labelToCid.put("/ordfeminine", 0252);
+		this.labelToCid.put("/ordmasculine", 0272);
+		this.labelToCid.put("/oslash", 0370);
+		this.labelToCid.put("/otilde", 0365);
+		this.labelToCid.put("/p", 0160);
+		this.labelToCid.put("/paragraph", 0266);
+		this.labelToCid.put("/parenleft", 0050);
+		this.labelToCid.put("/parenright", 0051);
+		this.labelToCid.put("/percent", 0045);
+		this.labelToCid.put("/period", 0056);
+		this.labelToCid.put("/periodcentered", 0267);
+		this.labelToCid.put("/plus", 0053);
+		this.labelToCid.put("/plusminus", 0261);
+		this.labelToCid.put("/q", 0161);
+		this.labelToCid.put("/question", 0077);
+		this.labelToCid.put("/questiondown", 0277);
+		this.labelToCid.put("/quotedbl", 0042);
+		this.labelToCid.put("/quoteleft", 0140);
+		this.labelToCid.put("/quoteright", 0047);
+		this.labelToCid.put("/r", 0162);
+		this.labelToCid.put("/registered", 0256);
+		this.labelToCid.put("/ring", 0232);
+		this.labelToCid.put("/s", 0163);
+		this.labelToCid.put("/section", 0247);
+		this.labelToCid.put("/semicolon", 0073);
+		this.labelToCid.put("/seven", 0067);
+		this.labelToCid.put("/six", 0066);
+		this.labelToCid.put("/slash", 0057);
+		this.labelToCid.put("/space", 0040);
+		this.labelToCid.put("/sterling", 0243);
+		this.labelToCid.put("/t", 0164);
+		this.labelToCid.put("/thorn", 0376);
+		this.labelToCid.put("/three", 0063);
+		this.labelToCid.put("/threequarters", 0276);
+		this.labelToCid.put("/threesuperior", 0263);
+		this.labelToCid.put("/tilde", 0224);
+		this.labelToCid.put("/two", 0062);
+		this.labelToCid.put("/twosuperior", 0262);
+		this.labelToCid.put("/u", 0165);
+		this.labelToCid.put("/uacute", 0372);
+		this.labelToCid.put("/ucircumflex", 0373);
+		this.labelToCid.put("/udieresis", 0374);
+		this.labelToCid.put("/ugrave", 0371);
+		this.labelToCid.put("/underscore", 0137);
+		this.labelToCid.put("/v", 0166);
+		this.labelToCid.put("/w", 0167);
+		this.labelToCid.put("/x", 0170);
+		this.labelToCid.put("/y", 0171);
+		this.labelToCid.put("/yacute", 0375);
+		this.labelToCid.put("/ydieresis", 0377);
+		this.labelToCid.put("/yen", 0245);
+		this.labelToCid.put("/z", 0172);
+		this.labelToCid.put("/zero", 0060);
+		transafertLTOCinCTIL();
+	}
+
+	/**
+	 * Parse the font stream to feed cidToLabel and labelToMetric with Glyphs
+	 * information.
+	 * 
+	 * @throws ValidationException
+	 *           On unexpected error
+	 */
+	public void parse() throws ValidationException {
+		readClearText();
+		computeEexec();
+	}
+
+	/**
+	 * Read eexecSize in the font stream.
+	 * 
+	 * @return
+	 * @throws IOException
+	 */
+	protected byte[] readEexec() throws IOException {
+		int BUFFER_SIZE = 1024;
+		byte[] buffer = new byte[BUFFER_SIZE];
+		ByteArrayOutputStream eexecPart = new ByteArrayOutputStream();
+		int lr = 0;
+		int total = 0;
+		do {
+			lr = this.font.read(buffer, 0, BUFFER_SIZE);
+			if (lr == BUFFER_SIZE && (total + BUFFER_SIZE < eexecSize)) {
+				eexecPart.write(buffer, 0, BUFFER_SIZE);
+				total += BUFFER_SIZE;
+			} else if (lr > 0 && (total + lr < eexecSize)) {
+				eexecPart.write(buffer, 0, lr);
+				total += lr;
+			} else if (lr > 0 && (total + lr >= eexecSize)) {
+				eexecPart.write(buffer, 0, eexecSize - total);
+				total += (eexecSize - total);
+			}
+		} while (eexecSize > total && lr > 0);
+		IOUtils.closeQuietly(eexecPart);
+		return eexecPart.toByteArray();
+	}
+
+	/**
+	 * This method read eexecSize bytes. Read bytes are decoded using the
+	 * Type1FontUtils class and FontMetrics are computed.
+	 * 
+	 * @throws ValidationException
+	 */
+	protected void computeEexec() throws ValidationException {
+		try {
+			byte[] eexec = readEexec();
+			byte[] decryptedEexec = decodeEexec(eexec);
+//			// Uncomment this to see EExec as clear text 
+//			System.out.println("DECODED EEXEC : ");
+//			System.out.println(new String(decryptedEexec));
+
+			parseDecodedEexec(decryptedEexec);
+		} catch (IOException e) {
+			throw new ValidationException("Unable to compute the eexec portion : "
+					+ e.getMessage(), e);
+		}
+	}
+
+	/**
+	 * Parse decoded eexec portion of the font program. Feeds the labelToMetric
+	 * map.
+	 * 
+	 * @param eexec
+	 * @throws IOException
+	 */
+	protected void parseDecodedEexec(byte[] eexec) throws IOException {
+		ByteArrayInputStream baisEexec = new ByteArrayInputStream(eexec);
+		boolean expectedCharString = false;
+		// ---- According to Type1 specification 4 is the default value
+		int lenIV = 4;
+		int nChars = 0;
+		for (;;) {
+
+			byte[] token = readToken(baisEexec);
+
+			switch (tokenIdentifier(token)) {
+			case DUP_TOKEN:
+				if (!expectedCharString) {
+					byte[] tokenChoice = readToken(baisEexec); // ---- numeric code
+					if (tokenIdentifier(tokenChoice) == CHARSTRINGS_TOKEN) {
+						byte[] n = readToken(baisEexec);
+						nChars = Integer.parseInt(new String(n, "US-ASCII"));
+						expectedCharString = true;
+						// ---- read the end of line "dict dup begin"
+						readToken(baisEexec);
+						readToken(baisEexec);
+						readToken(baisEexec);
+						break;
+					} else if (!"begin".equals(new String(tokenChoice, "US-ASCII"))) {
+						byte[] toskip = readToken(baisEexec); // ---- binary length
+						readToken(baisEexec); // ---- skip RD
+						int skip = Integer.parseInt(new String(toskip, "US-ASCII"));
+						readBytes(baisEexec, skip);
+					}
+				}
+				break;
+			case LEN_IV_TOKEN:
+				byte[] l = readToken(baisEexec);
+				lenIV = Integer.parseInt(new String(l, "US-ASCII"));
+				break;
+			case CHARSTRINGS_TOKEN:
+				byte[] n = readToken(baisEexec);
+				nChars = Integer.parseInt(new String(n, "US-ASCII"));
+				expectedCharString = true;
+				// ---- read the end of line "dict dup begin"
+				readToken(baisEexec);
+				readToken(baisEexec);
+				readToken(baisEexec);
+				break;
+			case OBJ_NAME_TOKEN:
+				/*
+				 * ---- OBJ_NAME_TOKEN : Some character's label aren't defined in the
+				 * Encoding object but they should be defined by the Encoding array in
+				 * the font ---- program.
+				 */
+				// break;
+			case CHAR_LABEL_TOKEN:
+				// case OBJ_NAME_TOKEN :
+				if (expectedCharString) {
+					String label = new String(token, "US-ASCII");
+					byte[] csl = readToken(baisEexec);
+					int length = Integer.parseInt(new String(csl, "US-ASCII"));
+					// ---- read the RD token
+					readToken(baisEexec);
+					this.labelToMetric.put(label, getGlyphDescription(baisEexec, length,
+							lenIV));
+					nChars--;
+					if (nChars == 0) {
+						// ---- no more character
+						return;
+					}
+				}
+			default:
+				// nothing to do
+				break;
+			}
+		}
+	}
+
+	/**
+	 * 
+	 * @param is
+	 * @param length
+	 * @return
+	 * @throws IOException
+	 */
+	protected byte[] readBytes(InputStream is, int length) throws IOException {
+		byte[] charF = new byte[length];
+		for (int i = 0; i < length; i++) {
+			charF[i] = (byte) is.read();
+		}
+		return charF;
+	}
+
+	/**
+	 * Read the CharString in the InputStream and decode it. The decoded
+	 * CharString is used to create a GlyphDescription object.
+	 * 
+	 * @param is
+	 *          the decoded eexec portion of the type 1 font program
+	 * @param length
+	 *          the number of bytes to read
+	 * @param rdBytes
+	 *          the number of padding bytes at the beginning of the decoded
+	 *          CharString
+	 * @return
+	 * @throws IOException
+	 */
+	protected Type1GlyphDescription getGlyphDescription(InputStream is,
+			int length, int rdBytes) throws IOException {
+		byte[] charF = readBytes(is, length);
+		byte[] dcs = Type1FontUtil.charstringDecrypt(charF, rdBytes);
+
+		Type1CharStringParser t1p = new Type1CharStringParser();
+		List<Object> lSequence = t1p.parse(dcs);
+
+		return new Type1GlyphDescription(lSequence);
+	}
+
+	/**
+	 * Call the Type1FontUtil.eexecDecrypt() method
+	 * 
+	 * @param eexec
+	 * @return the decrypted eexec portion of the font program
+	 */
+	protected byte[] decodeEexec(byte[] eexec) {
+		return Type1FontUtil.eexecDecrypt(eexec);
+	}
+
+	/**
+	 * Read the clear-text portion of the Type1 font program.
+	 * 
+	 * If FamillyName, FullName and FontName exist in the font program,
+	 * Type1MetricHelper updates its attributes. This method feeds the cidToLabel
+	 * map.
+	 * 
+	 * @throws ValidationException
+	 */
+	protected void readClearText() throws ValidationException {
+		int readBytes = 0;
+
+		try {
+			boolean dupAuth = false;
+			while (clearTextSize - readBytes > 0) {
+
+				byte[] token = readToken(this.font);
+				switch (tokenIdentifier(token)) {
+				case FAMILY_NAME_TOKEN:
+					byte[] fname = readToken(this.font);
+					readBytes += (fname.length + 1);
+
+					this.familyName = new String(fname, "US-ASCII");
+					break;
+				case FULL_NAME_TOKEN:
+					byte[] fullname = readToken(this.font);
+					readBytes += (fullname.length + 1);
+
+					this.fullName = new String(fullname, "US-ASCII");
+					break;
+				case DUP_TOKEN:
+					if (dupAuth) {
+						byte[] cid = readToken(this.font);
+						readBytes += (cid.length + 1);
+
+						byte[] label = readToken(this.font);
+						readBytes += (label.length + 1);
+
+						int cl = Integer.parseInt(new String(cid, "US-ASCII"));
+						String lc = new String(label, "US-ASCII");
+						this.cidToLabel.put(cl, lc);
+						this.labelToCid.put(lc, cl);
+					}
+					break;
+				case ENCODING_TOKEN:
+					byte[] tmpTok = readToken(this.font);
+					readBytes += (tmpTok.length + 1);
+					String encoding = new String(tmpTok, "US-ASCII");
+					if (PS_STANDARD_ENCODING.equals(encoding)) {
+						createStandardEncoding();
+					} else if (PS_ISOLATIN_ENCODING.equals(encoding)) {
+						createISOLatin1Encoding();
+					} else {
+						dupAuth = true;
+					}
+					break;
+				case READONLY_TOKEN:
+					dupAuth = false;
+					break;
+				default:
+					// nothing to go
+				}
+
+				// ---- add the token and the Space character length
+				readBytes += (token.length + 1);
+			}
+
+		} catch (IOException e) {
+			throw new ValidationException("Unable to read the clear text : "
+					+ e.getMessage(), e);
+		}
+	}
+
+	/**
+	 * Returns an int value which represent the token.
+	 * 
+	 * @param token
+	 * @return -1 if the token must be ignored
+	 * @throws IOException
+	 */
+	protected int tokenIdentifier(byte[] token) throws IOException {
+
+		String tokenAsStr = new String(token, "US-ASCII");
+		if ("/FamilyName".equals(tokenAsStr)) {
+			return FAMILY_NAME_TOKEN;
+		}
+
+		if ("/FullName".equals(tokenAsStr)) {
+			return FULL_NAME_TOKEN;
+		}
+
+		if ("/FontName".equals(tokenAsStr)) {
+			return FONT_NAME_TOKEN;
+		}
+
+		if ("dup".equals(tokenAsStr)) {
+			return DUP_TOKEN;
+		}
+
+		if ("/Encoding".equals(tokenAsStr)) {
+			return ENCODING_TOKEN;
+		}
+
+		if ("readonly".equals(tokenAsStr)) {
+			return READONLY_TOKEN;
+		}
+
+		if ("/lenIV".equals(tokenAsStr)) {
+			return LEN_IV_TOKEN;
+		}
+
+		if ("/CharStrings".equals(tokenAsStr)) {
+			return CHARSTRINGS_TOKEN;
+		}
+
+		if (labelToCid.containsKey(tokenAsStr)
+				|| this.encoding.getNameToCodeMap().containsKey(
+						COSName.getPDFName(tokenAsStr.replace("/", "")))) {
+			return CHAR_LABEL_TOKEN;
+		}
+
+		String regex = "/[^\\s\\(\\)\\[\\]\\{\\}/<>%]+";
+		if (tokenAsStr.matches(regex)) {
+			return OBJ_NAME_TOKEN;
+		}
+
+		return -1;
+	}
+
+	/**
+	 * Read the stream until a space character or EOL is reached.
+	 * 
+	 * @return byte array containing bytes read before the space character.
+	 * @throws IOException
+	 */
+	protected byte[] readToken(InputStream stream) throws IOException {
+		List<Integer> buffer = new ArrayList<Integer>();
+		int currentByte = -1;
+		do {
+			currentByte = stream.read();
+			// ---- Token is String literal
+			if (currentByte > 0 && currentByte == '(') {
+				int opened = 1;
+				buffer.add(currentByte);
+
+				while (opened != 0) {
+					currentByte = stream.read();
+					if (currentByte < 0) {
+						throw new IOException("Unexpected End Of File");
+					}
+
+					if (currentByte == '(') {
+						opened++;
+					} else if (currentByte == ')') {
+						opened--;
+					}
+
+					// ---- Add useful character
+					buffer.add(currentByte);
+				}
+			} else if (currentByte > 0 && currentByte == '[') {
+				// ---- token is an array
+				int opened = 1;
+				buffer.add(currentByte);
+
+				while (opened != 0) {
+					currentByte = stream.read();
+					if (currentByte < 0) {
+						throw new IOException("Unexpected End Of File");
+					}
+
+					if (currentByte == '[') {
+						opened++;
+					} else if (currentByte == ']') {
+						opened--;
+					}
+
+					// ---- Add useful character
+					buffer.add(currentByte);
+				}
+			} else if (currentByte > 0 && currentByte == '{') {
+				// ---- token is an dictionary
+				int opened = 1;
+				buffer.add(currentByte);
+
+				while (opened != 0) {
+					currentByte = stream.read();
+					if (currentByte < 0) {
+						throw new IOException("Unexpected End Of File");
+					}
+
+					if (currentByte == '{') {
+						opened++;
+					} else if (currentByte == '}') {
+						opened--;
+					}
+
+					// ---- Add useful character
+					buffer.add(currentByte);
+				}
+			} else if (currentByte > 0
+					&& (currentByte != ' ' && currentByte != '\n' && currentByte != '\r')) {
+				// ---- Add useful character
+				buffer.add(currentByte);
+			} else if (currentByte < 0) {
+				throw new IOException("Unexpected End Of File");
+			} else {
+				break;
+			}
+		} while (true);
+
+		byte[] res = new byte[buffer.size()];
+		for (int i = 0; i < res.length; ++i) {
+			res[i] = buffer.get(i).byteValue();
+		}
+
+//		 System.out.println("### READ TOKEN : " + new String(res));
+//		 if ("/CharStrings".equals(new String(res))) {
+//		 System.err.println("POUET");
+//		 }
+		return res;
+	}
+
+	/**
+	 * Returns the Character name as PDF Name Object. (Prefixed by '/'). If the
+	 * name is missing from the cidToLabel map and missing from the encoding
+	 * object, the "/.notdef" name is returned.
+	 * The pdf encoding array is used before the cidToLabel map.
+	 * @param cid
+	 * @return
+	 */
+	protected String getLabelAsName(int cid) {
+		String label = null;
+
+		try {
+			label = this.encoding.getName(cid);
+		} catch (IOException e) {
+			label = this.cidToLabel.get(cid);
+		}
+
+		if (label == null) {
+			label = NOTDEF;
+		}
+		return label.charAt(0) == NAME_START ? label : NAME_START + label;
+	}
+
+	/**
+	 * Return the Glyph width according to the Character identifier.
+	 * 
+	 * @param cid
+	 * @return
+	 */
+	public int getWidth(int cid) {
+		String label = getLabelAsName(cid);
+
+		Type1GlyphDescription glyph = this.labelToMetric.get(label);
+		if (glyph != null) {
+			return glyph.getWidth();
+		}
+
+		return 0;
+	}
+
+	/**
+	 * Container which contains all CharString Command and Operand. Currently,
+	 * only the Glyph width can be access through the "hsdw" operator.
+	 */
+	public static class Type1GlyphDescription {
+		private List<Object> lSequence = null;
+
+		private Integer width = null;
+
+		public Type1GlyphDescription(List<Object> ls) {
+			this.lSequence = ls;
+		}
+
+		public int getWidth() {
+			if (width != null) {
+				return width;
+			}
+
+			for (int i = 0; lSequence != null && i < lSequence.size(); ++i) {
+				Object obj = lSequence.get(i);
+				if (obj instanceof CharStringCommand) {
+					CharStringCommand csCmd = (CharStringCommand) obj;
+					if ("hsbw".equals(CharStringCommand.TYPE1_VOCABULARY.get(csCmd
+							.getKey()))) {
+						width = (Integer) lSequence.get(i - 1);
+						return width;
+					}
+				}
+			}
+
+			return 0;
+		}
+	}
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type3FontContainer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type3FontContainer.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type3FontContainer.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type3FontContainer.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,50 @@
+/*****************************************************************************
+ * 
+ * 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.ValidationConstants;
+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 Type3FontContainer extends AbstractFontContainer {
+
+  public Type3FontContainer(PDFont fd) {
+    super(fd);
+  }
+
+  @Override
+  public void checkCID(int cid) throws GlyphException {
+  	if (!isAlreadyComputedCid(cid)) {
+  		// missing glyph
+  		GlyphException e = new GlyphException(ValidationConstants.ERROR_FONTS_GLYPH_MISSING, cid, 
+  																					"There are no glyph in the Type 3 font for the character \"" + cid + "\"");
+	  	addKnownCidElement(new GlyphDetail(cid, e));
+	  	throw e;
+  	}  	
+  } 
+}
\ No newline at end of file

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type3FontValidator.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type3FontValidator.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type3FontValidator.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/Type3FontValidator.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,553 @@
+/*****************************************************************************
+ * 
+ * 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 java.util.Set;
+
+
+import org.apache.padaf.preflight.DocumentHandler;
+import org.apache.padaf.preflight.ValidationException;
+import org.apache.padaf.preflight.ValidationResult.ValidationError;
+import org.apache.padaf.preflight.contentstream.ContentStreamException;
+import org.apache.padaf.preflight.font.AbstractFontContainer.State;
+import org.apache.padaf.preflight.graphics.ExtGStateContainer;
+import org.apache.padaf.preflight.graphics.ShadingPattern;
+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.cos.COSStream;
+import org.apache.pdfbox.encoding.DictionaryEncoding;
+import org.apache.pdfbox.encoding.Encoding;
+import org.apache.pdfbox.encoding.EncodingManager;
+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;
+
+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(DocumentHandler handler, COSObject obj)
+	throws ValidationException {
+		super(handler, obj);
+		this.pdType3 = (PDType3Font) this.pFont;
+	}
+
+	/**
+	 * 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() {
+		// ---- required elements
+		this.fontBBox = this.fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_FONTBBOX));
+		this.fontMatrix = this.fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_FONTMATRIX));
+		this.charProcs = this.fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_CHARPROCS));
+		this.fontEncoding = this.fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_ENCODING));
+		this.firstChar = this.fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_FIRSTCHAR));
+		this.lastChar = this.fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_LASTCHAR));
+		this.widths = this.fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_WIDTHS));
+
+		// ---- Optional elements
+		this.toUnicode = this.fDictionary.getItem(COSName
+				.getPDFName(FONT_DICTIONARY_KEY_TOUNICODE));
+		this.resources = this.fDictionary.getItem(COSName
+				.getPDFName(DICTIONARY_KEY_RESOURCES));
+	}
+
+	/**
+	 * 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));
+		}
+
+		/*
+		 * ---- 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;
+	}
+
+	/**
+	 * 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
+	 */
+	private boolean checkFontBBoxMatrix() {
+		COSDocument cDoc = this.handler.getDocument().getDocument();
+
+		// ---- both elements are an array
+		if (!COSUtils.isArray(this.fontBBox, cDoc)) {
+			this.fontContainer
+			.addError(new ValidationError(ERROR_FONTS_DICTIONARY_INVALID,
+					"The FontBBox element isn't an array"));
+			return false;
+		}
+
+		if (!COSUtils.isArray(this.fontMatrix, cDoc)) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID,
+					"The FontMatrix element isn't an array"));
+			return false;
+		}
+
+		// ---- check the content of the FontBBox.
+		// ---- Should be an array with 4 numbers
+		COSArray bbox = COSUtils.getAsArray(fontBBox, cDoc);
+		if (bbox.size() != 4) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID, "The FontBBox element is invalid"));
+			return false;
+		} else {
+			for (int i = 0; i < 4; i++) {
+				COSBase elt = bbox.get(i);
+				if (!(COSUtils.isFloat(elt, cDoc) || COSUtils.isInteger(elt, cDoc))) {
+					this.fontContainer.addError(new ValidationError(
+							ERROR_FONTS_DICTIONARY_INVALID,
+							"An element of FontBBox isn't a number"));
+					return false;
+				}
+			}
+		}
+
+		// ---- check the content of the FontMatrix.
+		// ---- Should be an array with 6 numbers
+		COSArray matrix = COSUtils.getAsArray(fontMatrix, cDoc);
+		if (matrix.size() != 6) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID, "The FontMatrix element is invalid"));
+			return false;
+		} else {
+			for (int i = 0; i < 6; i++) {
+				COSBase elt = matrix.get(i);
+				if (!(COSUtils.isFloat(elt, cDoc) || COSUtils.isInteger(elt, cDoc))) {
+					this.fontContainer.addError(new ValidationError(
+							ERROR_FONTS_DICTIONARY_INVALID,
+							"An element of FontMatrix isn't a number"));
+					return false;
+				}
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * 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
+	 * Name (For the 5 predefined Encoding) or a Dictionary. If it is a
+	 * dictionary, the "Differences" array contains the correspondence between a
+	 * character code and a set of character name which are different from the
+	 * encoding entry of the dictionary.
+	 * 
+	 * This method checks that the encoding is :
+	 * <UL>
+	 * <li>An existing encoding name.
+	 * <li>A dictionary with an existing encoding name (the name is optional) and
+	 * a well formed "Differences" array (the array is optional)
+	 * </UL>
+	 * 
+	 * @return
+	 */
+	private boolean checkEncoding() {
+		COSDocument cDoc = this.handler.getDocument().getDocument();
+
+		EncodingManager emng = new EncodingManager();
+		if (COSUtils.isString(this.fontEncoding, cDoc)) {
+			// ---- Encoding is a Name, check if it is an Existing Encoding
+			String enc = COSUtils.getAsString(this.fontEncoding, cDoc);
+			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, cDoc)) {
+			COSDictionary encodingDictionary = COSUtils.getAsDictionary(
+					this.fontEncoding, cDoc);
+			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, cDoc)) {
+					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, cDoc);
+				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;
+					}
+				}
+			}
+		} 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;
+		}
+
+		return true;
+	}
+
+	/**
+	 * 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
+	 * exist in the CharProcs dictionary. If the CharProcs doesn't know the
+	 * Character, it is mapped with the .notdef one.
+	 * 
+	 * For each character, the Glyph width must be the same as the Width value
+	 * declared in the Widths array.
+	 * 
+	 * @param errors
+	 * @return
+	 */
+	private boolean checkCharProcsAndMetrics() throws ValidationException {
+		COSDocument cDoc = this.handler.getDocument().getDocument();
+
+		// ---- 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;
+		}
+
+		COSDictionary charProcsDictionary = COSUtils.getAsDictionary(this.charProcs, cDoc);
+		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.
+		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;
+		}
+
+		// ---- Check width consistency
+		for (int i = 0; i < expectedLength; i++) {
+			int cid = fc + i;
+			COSBase arrContent = wArr.get(i);
+			if (COSUtils.isNumeric(arrContent, cDoc)) {
+				float width = COSUtils.getAsFloat(arrContent, cDoc);
+
+				String charName = 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, cDoc);
+				if (charStream == null && width != 0) {
+					GlyphException glyphEx = new GlyphException(ERROR_FONTS_METRICS, cid, 
+							"The CharProcs \"" + charName
+							+ "\" doesn't exist but the width is " + width);
+					GlyphDetail glyphDetail = new GlyphDetail(cid, glyphEx);
+					this.fontContainer.addKnownCidElement(glyphDetail);
+				} else {
+					try {
+						// --- Parse the Glyph description to obtain the Width
+						PDFAType3StreamParser parser = new PDFAType3StreamParser(
+								this.handler);
+						PDResources pRes = null;
+						if (this.resources != null) {
+							COSDictionary resAsDict = COSUtils.getAsDictionary(
+									this.resources, cDoc);
+							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) {
+						this.fontContainer.addError(new ValidationError(e
+								.getValidationError()));
+						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;
+					}
+				}
+
+			} else {
+				this.fontContainer.addError(new ValidationError(
+						ERROR_FONTS_DICTIONARY_INVALID,
+						"The Witdhs array is invalid. (some element aren't integer)"));
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * 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.
+	 * 
+	 * @return
+	 */
+	private boolean checkResources() throws ValidationException {
+		if (this.resources == null) {
+			// ---- No resources dictionary.
+			return true;
+		}
+
+		COSDocument cDoc = this.handler.getDocument().getDocument();
+		COSDictionary dictionary = COSUtils.getAsDictionary(this.resources, cDoc);
+		if (dictionary == null) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_DICTIONARY_INVALID,
+					"The Resources element isn't a dictionary"));
+			return false;
+		}
+
+		COSBase cbImg = dictionary.getItem(COSName
+				.getPDFName(DICTIONARY_KEY_XOBJECT));
+		COSBase cbFont = dictionary
+		.getItem(COSName.getPDFName(DICTIONARY_KEY_FONT));
+
+		if (cbImg == null && cbFont == null) {
+			this.fontContainer.addError(new ValidationError(
+					ERROR_FONTS_TYPE3_DAMAGED,
+					"The Resources element doesn't have Glyph information"));
+			return false;
+		}
+
+		if (cbImg != null) {
+			// ---- the referenced objects must be present in the PDF file
+			COSDictionary dicImgs = COSUtils.getAsDictionary(cbImg, cDoc);
+			Set<COSName> keyList = dicImgs.keySet();
+			for (Object key : keyList) {
+
+				COSBase item = dictionary.getItem((COSName) key);
+				COSDictionary xObjImg = COSUtils.getAsDictionary(item, cDoc);
+				if (xObjImg == null) {
+					this.fontContainer.addError(new ValidationError(
+							ERROR_FONTS_DICTIONARY_INVALID,
+							"The Resources dictionary of type 3 font is invalid"));
+					return false;
+				}
+
+				if (!XOBJECT_DICTIONARY_VALUE_SUBTYPE_IMG.equals(xObjImg
+						.getString(COSName.getPDFName(DICTIONARY_KEY_SUBTYPE)))) {
+					this.fontContainer.addError(new ValidationError(
+							ERROR_FONTS_DICTIONARY_INVALID,
+							"The Resources dictionary of type 3 font is invalid"));
+					return false;
+				}
+			}
+		}
+
+		if (cbFont != null) {
+			// ---- the referenced object must be present in the PDF file
+			COSDictionary dicFonts = COSUtils.getAsDictionary(cbFont, cDoc);
+			Set<COSName> keyList = dicFonts.keySet();
+			for (Object key : keyList) {
+
+				COSBase item = dictionary.getItem((COSName) key);
+				COSDictionary xObjFont = COSUtils.getAsDictionary(item, cDoc);
+				if (xObjFont == null) {
+					this.fontContainer.addError(new ValidationError(
+							ERROR_FONTS_DICTIONARY_INVALID,
+							"The Resources dictionary of type 3 font is invalid"));
+					return false;
+				}
+
+				if (!FONT_DICTIONARY_VALUE_FONT.equals(xObjFont.getString(COSName
+						.getPDFName(DICTIONARY_KEY_TYPE)))) {
+					this.fontContainer.addError(new ValidationError(
+							ERROR_FONTS_DICTIONARY_INVALID,
+							"The Resources dictionary of type 3 font is invalid"));
+					return false;
+				}
+
+				try {
+					PDFont aFont = PDFontFactory.createFont(xObjFont);
+					// FontContainer aContainer = this.handler.retrieveFontContainer(aFont);
+					AbstractFontContainer aContainer = this.handler.getFont(aFont.getCOSObject());
+					// ---- another font is used in the Type3, check if the font is valid.
+					if (aContainer.isValid() != State.VALID) {
+						this.fontContainer
+						.addError(new ValidationError(ERROR_FONTS_TYPE3_DAMAGED,
+								"The Resources dictionary of type 3 font contains invalid font"));
+						return false;
+					}
+				} catch (IOException e) {
+					throw new ValidationException("Unable to valid the Type3 : "
+							+ e.getMessage());
+				}
+			}
+		}
+
+		List<ValidationError> errors = new ArrayList<ValidationError>();
+		ExtGStateContainer extGStates = new ExtGStateContainer(dictionary, cDoc);
+		boolean res = extGStates.validateTransparencyRules(errors);
+		for (ValidationError err : errors) {
+			this.fontContainer.addError(err);
+		}
+
+		return res && validateShadingPattern(dictionary, errors);
+	}
+
+	/**
+	 * This method check the Shading entry of the resource dictionary if exists.
+	 * 
+	 * @param result
+	 * @return
+	 * @throws ValidationException
+	 */
+	protected boolean validateShadingPattern(COSDictionary dictionary,
+			List<ValidationError> result) throws ValidationException {
+		boolean res = true;
+		if (dictionary != null) {
+			COSDictionary shadings = (COSDictionary) dictionary
+			.getDictionaryObject(PATTERN_KEY_SHADING);
+			if (shadings != null) {
+				for (COSName key : shadings.keySet()) {
+					COSDictionary aShading = (COSDictionary) shadings.getDictionaryObject(key);
+					ShadingPattern sp = new ShadingPattern(handler, aShading);
+					List<ValidationError> lErrors = sp.validate();
+					if (lErrors != null && !lErrors.isEmpty()) {
+						result.addAll(lErrors);
+						res = false;
+					}
+				}
+			}
+		}
+		return res;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see net.awl.edoc.pdfa.validation.font.FontValidator#validate()
+	 */
+	public boolean validate() throws ValidationException {
+		extractFontDictionaryEntries();
+		boolean isValid = checkMandatoryFields();
+		isValid = isValid && checkFontBBoxMatrix();
+		isValid = isValid && checkEncoding();
+		isValid = isValid && checkCharProcsAndMetrics();
+		isValid = isValid && checkResources();
+		return isValid;
+	}
+}

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/UndefFontContainer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/UndefFontContainer.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/UndefFontContainer.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/UndefFontContainer.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ * 
+ * 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.ValidationConstants;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+
+public class UndefFontContainer extends AbstractFontContainer {
+
+  public UndefFontContainer(PDFont fd) {
+    super(fd);
+  }
+
+  @Override
+  public void checkCID(int cid) throws GlyphException {
+  	throw new GlyphException(ValidationConstants.ERROR_FONTS_UNKNOWN_FONT_REF, 0, "A text content is using a undefined font type.");
+  }
+}
\ No newline at end of file

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/type1/GlyphDescription.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/type1/GlyphDescription.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/type1/GlyphDescription.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/type1/GlyphDescription.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ * 
+ * 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.type1;
+
+import java.util.List;
+
+import org.apache.fontbox.cff.CharStringCommand;
+
+public class GlyphDescription {
+	private List<Object> operations = null;
+
+	private Integer glyphWidth = null;
+
+	GlyphDescription(List<Object> operations) {
+		this.operations = operations;
+	}
+
+	public int getGlyphWidth() {
+		if (this.glyphWidth != null) {
+			return glyphWidth;
+		}
+
+		this.glyphWidth = searchWidth();
+		return this.glyphWidth;
+	}
+
+	private int searchWidth() {
+		for (int i = 0; operations != null && i < operations.size(); ++i) {
+			Object obj = operations.get(i);
+			if (obj instanceof CharStringCommand) {
+				CharStringCommand csCmd = (CharStringCommand) obj;
+				if ("hsbw".equals(CharStringCommand.TYPE1_VOCABULARY.get(csCmd.getKey()))) {
+					return (Integer) operations.get(i - 1);
+				}
+			}
+		}
+		// 0 is the default value if glyph isn't found. 
+		return 0;
+	}	
+}
\ No newline at end of file

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

Added: pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/type1/PeekInputStream.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/type1/PeekInputStream.java?rev=1150373&view=auto
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/type1/PeekInputStream.java (added)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/padaf/preflight/font/type1/PeekInputStream.java Sun Jul 24 14:02:12 2011
@@ -0,0 +1,73 @@
+/*****************************************************************************
+ * 
+ * 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.type1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.io.IOUtils;
+
+public class PeekInputStream extends InputStream {
+	private byte[] content = new byte[0];
+	private int position = 0;
+	
+	public PeekInputStream(InputStream source) throws IOException {
+		ByteArrayOutputStream bos = new ByteArrayOutputStream();
+		try {
+			IOUtils.copyLarge(source, bos);
+			content = bos.toByteArray();
+		} finally {
+			IOUtils.closeQuietly(source);
+			IOUtils.closeQuietly(bos);
+		}
+	}
+
+	@Override
+	public int read() throws IOException {
+		if (position >= content.length) {
+			throw new IOException("No more content in this stream");
+		}
+
+		int currentByte = (content[position] & 0xFF);
+		++position;
+		return currentByte;
+	}
+
+	public int peek() throws IOException {
+		if (position >= content.length) {
+			throw new IOException("No more content in this stream");
+		}
+
+		return (content[position] & 0xFF);
+	}
+	
+	public byte[] peek(int numberOfBytes) throws IOException {
+		if ( numberOfBytes < 0 || (position + numberOfBytes) >= content.length) {
+			throw new IOException("No more content in this stream, can't return the next " + numberOfBytes + " bytes");
+		}
+
+		byte[] nextBytes = new byte[numberOfBytes];
+		System.arraycopy(this.content, this.position, nextBytes, 0, numberOfBytes);
+		return nextBytes; 
+	}
+}
\ No newline at end of file

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