Example usage for org.apache.pdfbox.cos COSName getPDFName

List of usage examples for org.apache.pdfbox.cos COSName getPDFName

Introduction

In this page you can find the example usage for org.apache.pdfbox.cos COSName getPDFName.

Prototype

public static COSName getPDFName(String aName) 

Source Link

Document

This will get a COSName object with that name.

Usage

From source file:org.apache.fop.render.pdf.StructureTreeMergerUtilTestCase.java

License:Apache License

@Test
public void testFindRoleMapKeyByValue() {

    COSDictionary rolemap = new COSDictionary();
    COSName key1 = COSName.getPDFName("Para");
    COSName value1 = COSName.getPDFName("P");
    COSName key2 = COSName.getPDFName("Icon");
    COSName value2 = COSName.getPDFName("Image");
    rolemap.setItem(key1, value1);//from   w w  w  . j  a v a2 s  .c  o m
    rolemap.setItem(key2, value2);
    String type = "Image";
    List<String> result = StructureTreeMergerUtil.findRoleMapKeyByValue(type, rolemap);
    String test = result.get(0);
    String expected = "Icon";
    Assert.assertEquals(test, expected);
}

From source file:org.apache.padaf.preflight.font.CompositeFontValidator.java

License:Apache License

/**
 * Standard information of a stream element will be checked by the
 * StreamHelper./*from   w ww . j  ava 2s  .  c o m*/
 * 
 * This method checks mandatory fields of the CMap stream. This method checks
 * too if the CMap stream is damaged using the CMapParser of the fontbox api.
 * 
 * @param aCMap
 * @return
 */
private boolean processCMapAsStream(COSStream aCMap) {
    COSDocument cDoc = handler.getDocument().getDocument();

    String type = aCMap.getNameAsString(COSName.getPDFName(DICTIONARY_KEY_TYPE));
    String cmapName = aCMap.getNameAsString(COSName.getPDFName(FONT_DICTIONARY_KEY_CMAP_NAME));
    COSBase sysinfo = aCMap.getItem(COSName.getPDFName(FONT_DICTIONARY_KEY_CID_SYSINFO));
    int wmode = aCMap.getInt(COSName.getPDFName(FONT_DICTIONARY_KEY_CMAP_WMODE));
    if (wmode == -1) {
        /*
         * According to the getInt javadoc, -1 is returned if there are no result.
         * In the PDF Reference v1.7 p449, we can read that Default value is 0.
         */
        wmode = FONT_DICTIONARY_DEFAULT_CMAP_WMODE;
    }
    COSBase cmapUsed = aCMap.getItem(COSName.getPDFName(FONT_DICTIONARY_KEY_CMAP_USECMAP));

    if (!FONT_DICTIONARY_VALUE_TYPE_CMAP.equals(type)) {
        // ---- CMap type is invalid
        this.fontContainer.addError(
                new ValidationError(ERROR_FONTS_CIDKEYED_CMAP_INVALID_OR_MISSING, "The CMap type is invalid"));
        return false;
    }

    // ---- check the content of the CIDSystemInfo
    if (!checkCIDSystemInfo(sysinfo, cDoc)) {
        return false;
    }

    if (cmapName == null || "".equals(cmapName) || wmode > 1) {
        this.fontContainer.addError(new ValidationError(ERROR_FONTS_CIDKEYED_CMAP_INVALID_OR_MISSING,
                "Some elements in the CMap dictionary are missing or invalid"));
        return false;
    }

    try {

        CMap fontboxCMap = new CMapParser().parse(null, aCMap.getUnfilteredStream());
        int wmValue = fontboxCMap.getWMode();
        String cmnValue = fontboxCMap.getName();

        if (wmValue != wmode) {

            this.fontContainer.addError(
                    new ValidationError(ERROR_FONTS_CIDKEYED_CMAP_INVALID_OR_MISSING, "WMode is inconsistent"));
            return false;
        }

        if (!cmnValue.equals(cmapName)) {

            this.fontContainer.addError(new ValidationError(ERROR_FONTS_CIDKEYED_CMAP_INVALID_OR_MISSING,
                    "CMapName is inconsistent"));
            return false;
        }

    } catch (IOException e) {
        this.fontContainer
                .addError(new ValidationError(ERROR_FONTS_CID_CMAP_DAMAGED, "The CMap type is damaged"));
        return false;
    }

    if (cmapUsed != null) {
        return checkCMap(cmapUsed);
    }

    return true;
}

From source file:org.apache.padaf.preflight.font.TrueTypeFontValidator.java

License:Apache License

/**
 * This methods validates the Font Stream. If the font is damaged or missing
 * the FontContainer is updated and false is returned. Moreover, this method
 * checks the Encoding property of the FontDescriptor dictionary.
 * //from w w w .ja v a  2  s  .c o m
 * @return
 */
protected boolean checkFontFileElement() throws ValidationException {
    PDStream ff1 = pFontDesc.getFontFile();
    PDStream ff2 = pFontDesc.getFontFile2();
    PDStream ff3 = pFontDesc.getFontFile3();
    boolean onlyOne = (ff1 != null && ff2 == null && ff3 == null) || (ff1 == null && ff2 != null && ff3 == null)
            || (ff1 == null && ff2 == null && ff3 != null);

    if (ff2 == null || !onlyOne) {
        this.fontContainer.addError(new ValidationResult.ValidationError(
                ValidationConstants.ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile2 is invalid"));
        return false;
    }

    // ---- Stream validation should be done by the StreamValidateHelper.
    // ---- Process font specific check
    COSStream stream = ff2.getStream();
    if (stream == null) {
        this.fontContainer.addError(new ValidationResult.ValidationError(
                ValidationConstants.ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is missing"));
        this.fontContainer.setFontProgramEmbedded(false);
        return false;
    }

    boolean hasLength1 = stream.getInt(COSName.getPDFName(FONT_DICTIONARY_KEY_LENGTH1)) > 0;
    if (!hasLength1) {
        this.fontContainer.addError(new ValidationResult.ValidationError(
                ValidationConstants.ERROR_FONTS_FONT_FILEX_INVALID, "The FontFile is invalid"));
        return false;
    }

    // ---- check the encoding part.
    if (pFontDesc.isNonSymbolic()) {
        // ---- only MacRomanEncoding or WinAnsiEncoding are allowed for a non
        // symbolic font
        Encoding encodingValue = this.pFont.getFontEncoding();
        if (encodingValue == null
                || !(encodingValue instanceof MacRomanEncoding || encodingValue instanceof WinAnsiEncoding)) {
            this.fontContainer
                    .addError(new ValidationResult.ValidationError(ValidationConstants.ERROR_FONTS_ENCODING,
                            "The Encoding is invalid for the NonSymbolic TTF"));
            return false;
        }
    } else if (pFontDesc.isSymbolic()) {
        // ---- For symbolic font, no encoding entry is allowed and only one
        // encoding entry is expected into the FontFile CMap
        if (((COSDictionary) this.fDictionary.getCOSObject())
                .getItem(COSName.getPDFName(FONT_DICTIONARY_KEY_ENCODING)) != null) {
            this.fontContainer
                    .addError(new ValidationResult.ValidationError(ValidationConstants.ERROR_FONTS_ENCODING,
                            "The Encoding should be missing for the Symbolic TTF"));
            return false;
        } // else check the content of the Font CMap (see below)

    } else {
        // ----- should never happen
        return true;
    }

    /*
     * ---- try to load the font using the TTFParser object. If the font is
     * invalid, an exception will be thrown. Because of it is a Embedded Font
     * Program, some tables are required and other are optional see PDF
     * Reference (5.8)
     */
    ByteArrayInputStream bis = null;
    try {
        bis = new ByteArrayInputStream(ff2.getByteArray());
        TrueTypeFont ttf = new TTFParser(true).parseTTF(bis);
        if (pFontDesc.isSymbolic() && ttf.getCMAP().getCmaps().length != 1) {
            this.fontContainer
                    .addError(new ValidationResult.ValidationError(ValidationConstants.ERROR_FONTS_ENCODING,
                            "The Encoding should be missing for the Symbolic TTF"));
            return false;
        }

        ((TrueTypeFontContainer) this.fontContainer).setFontObjectAndInitializeInnerFields(ttf);
        ((TrueTypeFontContainer) this.fontContainer).setCMap(getCMapOfFontProgram(ttf));

        return checkFontFileMetaData(pFontDesc, ff2);
    } catch (IOException e) {
        this.fontContainer.addError(new ValidationResult.ValidationError(
                ValidationConstants.ERROR_FONTS_TRUETYPE_DAMAGED, "The FontFile can't be read"));
        return false;
    } finally {
        if (bis != null) {
            IOUtils.closeQuietly(bis);
        }
    }
}

From source file:org.apache.padaf.preflight.font.Type1FontValidator.java

License:Apache License

/**
 * This method checks the metric consistency and adds the FontContainer in the
 * DocumentHandler./*from   www.j  av  a 2  s  .  c  om*/
 * 
 * @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);

        return true;
    } catch (IOException e) {
        throw new ValidationException("Unable to check Type1 metrics due to : " + e.getMessage(), e);
    }
}

From source file:org.apache.padaf.preflight.font.Type3FontValidator.java

License:Apache License

/**
 * 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.
 * //  w  w  w .  ja  v  a 2  s  . c  o  m
 * 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) {
                /* 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 {
                    // --- 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;
}

From source file:org.apache.padaf.preflight.font.Type3FontValidator.java

License:Apache License

/**
 * 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.//from w  w w . j a  v a 2 s.  c o m
 * 
 * @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) {
        // ---- 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);
}

From source file:org.apache.padaf.preflight.graphics.ShadingPattern.java

License:Apache License

/**
 * Because of a Shading Pattern can be used as an Indirect Object or Directly
 * define in an other dictionary, there are two ways to obtain the Shading
 * Pattern dictionary according to the pattern attribute. This method returns
 * the Shading pattern dictionary represented by the pattern attribute or
 * contained in it.//from   w w  w  .j a  v  a 2s  .c o  m
 * 
 * This is the first method called by the validate method.
 * 
 * @param errors
 *          the list of error to update if there are no Shading pattern in the
 *          pattern COSDictionary.
 * @return the ShadingPattern dictionary
 */
protected COSDictionary getShadingDictionary(List<ValidationError> errors) {
    if (pattern.getItem(COSName.getPDFName(PATTERN_KEY_SHADING_TYPE)) == null
            && !"Shading".equals(pattern.getNameAsString(COSName.getPDFName(DICTIONARY_KEY_TYPE)))) {
        COSBase shading = pattern.getItem(COSName.getPDFName(PATTERN_KEY_SHADING));
        if (shading == null) {
            errors.add(new ValidationError(ERROR_GRAPHIC_INVALID_PATTERN_DEFINITION));
            return null;
        }
        return COSUtils.getAsDictionary(shading, cosDoc);
    } else {
        return pattern;
    }
}

From source file:org.apache.padaf.preflight.helpers.BookmarkValidationHelper.java

License:Apache License

/**
 * return true if Count entry > 0/*from   w  ww. j av a  2  s.  c o  m*/
 * @param outline
 * @param doc
 * @return
 */
private boolean isCountEntryPositive(COSDictionary outline, COSDocument doc) {
    COSBase countBase = outline.getItem(COSName.getPDFName("Count"));
    return COSUtils.isInteger(countBase, doc) && (COSUtils.getAsInteger(countBase, doc) > 0);
}

From source file:org.apache.padaf.preflight.helpers.CatalogValidationHelper.java

License:Apache License

/**
 * This method checks the content of each OutputIntent. The S entry must
 * contain GTS_PDFA1. The DestOuputProfile must contain a valid ICC Profile
 * Stream.// w  w  w . j  a  va2  s. com
 * 
 * If there are more than one OutputIntent, they have to use the same ICC
 * Profile.
 * 
 * This method returns a list of ValidationError. It is empty if no errors
 * have been found.
 * 
 * @param handler
 * @return
 * @throws ValidationException
 */
public List<ValidationError> validateOutputIntent(DocumentHandler handler) throws ValidationException {
    List<ValidationError> result = new ArrayList<ValidationError>(0);
    PDDocument pdDocument = handler.getDocument();
    PDDocumentCatalog catalog = pdDocument.getDocumentCatalog();
    COSDocument cDoc = pdDocument.getDocument();

    COSBase cBase = catalog.getCOSDictionary()
            .getItem(COSName.getPDFName(DOCUMENT_DICTIONARY_KEY_OUTPUT_INTENTS));
    COSArray outputIntents = COSUtils.getAsArray(cBase, cDoc);

    Map<COSObjectKey, Boolean> tmpDestOutputProfile = new HashMap<COSObjectKey, Boolean>();

    for (int i = 0; outputIntents != null && i < outputIntents.size(); ++i) {
        COSDictionary dictionary = COSUtils.getAsDictionary(outputIntents.get(i), cDoc);

        if (dictionary == null) {

            result.add(new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY,
                    "OutputIntent object is null or isn't a dictionary"));

        } else {
            // ---- S entry is mandatory and must be equals to GTS_PDFA1
            String sValue = dictionary.getNameAsString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_S));
            if (!OUTPUT_INTENT_DICTIONARY_VALUE_GTS_PDFA1.equals(sValue)) {
                result.add(new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_S_VALUE_INVALID,
                        "The S entry of the OutputIntent isn't GTS_PDFA1"));
                continue;
            }

            // ---- OutputConditionIdentifier is a mandatory field
            String outputConditionIdentifier = dictionary
                    .getString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_OUTPUT_CONDITION_IDENTIFIER));
            if (outputConditionIdentifier == null) {// empty string is autorized (it may be an application specific value)
                result.add(new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY,
                        "The OutputIntentCondition is missing"));
                continue;
            }

            // ---- If OutputConditionIdentifier is "Custom" or a non Standard ICC Characterization :
            // ---- DestOutputProfile and Info are mandatory
            // ---- DestOutputProfile must be a ICC Profile

            // ---- Because of PDF/A conforming file needs to specify the color characteristics, the DestOutputProfile
            // ---- is checked even if the OutputConditionIdentifier isn't "Custom"
            COSBase dop = dictionary
                    .getItem(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_DEST_OUTPUT_PROFILE));
            ValidationError valer = validateICCProfile(dop, cDoc, tmpDestOutputProfile, handler);
            if (valer != null) {
                result.add(valer);
                continue;
            }

            // TODO [LAZY] When Lazy mode will be added, this block should be uncommented to set result as warning.
            //            if (!isStandardICCCharacterization(outputConditionIdentifier)) {
            //               String info = dictionary.getString(COSName.getPDFName(OUTPUT_INTENT_DICTIONARY_KEY_INFO));
            //               if (info == null || "".equals(info)) {
            //                  result.add(new ValidationError(ERROR_GRAPHIC_OUTPUT_INTENT_INVALID_ENTRY,
            //                        "The Info entry of a OutputIntent dictionary is missing"));
            //                  continue;
            //               }
            //            }
        }
    }
    return result;
}

From source file:org.apache.padaf.preflight.helpers.StreamValidationHelper.java

License:Apache License

protected void checkStreamLength(DocumentHandler handler, COSObject cObj, List<ValidationError> result)
        throws ValidationException {
    COSStream streamObj = (COSStream) cObj.getObject();
    int length = streamObj.getInt(COSName.getPDFName(STREAM_DICTIONARY_KEY_LENGHT));
    InputStream ra = null;/*w  w w  .ja  v a  2 s. c o  m*/
    try {
        ra = handler.getSource().getInputStream();
        Long offset = handler.getDocument().getDocument().getXrefTable().get(new COSObjectKey(cObj));

        // ---- go to the beginning of the object
        long skipped = 0;
        if (offset != null) {
            while (skipped != offset) {
                long curSkip = ra.skip(offset - skipped);
                if (curSkip < 0) {
                    throw new ValidationException("Unable to skip bytes in the PDFFile to check stream length");
                }
                skipped += curSkip;
            }

            // ---- go to the stream key word
            if (readUntilStream(ra)) {
                int c = ra.read();
                if (c == '\r') {
                    ra.read();
                } // else c is '\n' no more character to read

                // ---- Here is the true beginning of the Stream Content.
                // ---- Read the given length of bytes and check the 10 next bytes
                // ---- to see if there are endstream.
                byte[] buffer = new byte[1024];
                int nbBytesToRead = length;

                do {
                    int cr = 0;
                    if (nbBytesToRead > 1024) {
                        cr = ra.read(buffer, 0, 1024);
                    } else {
                        cr = ra.read(buffer, 0, nbBytesToRead);
                    }
                    if (cr == -1) {
                        result.add(new ValidationResult.ValidationError(
                                ValidationConstants.ERROR_SYNTAX_STREAM_LENGTH_INVALID,
                                "Stream length is invalide"));
                        return;
                    } else {
                        nbBytesToRead = nbBytesToRead - cr;
                    }
                } while (nbBytesToRead > 0);

                int len = "endstream".length() + 2;
                byte[] buffer2 = new byte[len];
                for (int i = 0; i < len; ++i) {
                    buffer2[i] = (byte) ra.read();
                }

                // ---- check the content of 10 last characters
                String endStream = new String(buffer2);
                if (buffer2[0] == '\r' && buffer2[1] == '\n') {
                    if (!endStream.contains("endstream")) {
                        result.add(new ValidationResult.ValidationError(
                                ValidationConstants.ERROR_SYNTAX_STREAM_LENGTH_INVALID,
                                "Stream length is invalide"));
                    }
                } else if (buffer2[0] == '\r' && buffer2[1] == 'e') {
                    if (!endStream.contains("endstream")) {
                        result.add(new ValidationResult.ValidationError(
                                ValidationConstants.ERROR_SYNTAX_STREAM_LENGTH_INVALID,
                                "Stream length is invalide"));
                    }
                } else if (buffer2[0] == '\n' && buffer2[1] == 'e') {
                    if (!endStream.contains("endstream")) {
                        result.add(new ValidationResult.ValidationError(
                                ValidationConstants.ERROR_SYNTAX_STREAM_LENGTH_INVALID,
                                "Stream length is invalide"));
                    }
                } else {
                    result.add(new ValidationResult.ValidationError(
                            ValidationConstants.ERROR_SYNTAX_STREAM_LENGTH_INVALID,
                            "Stream length is invalide"));
                }

            } else {
                result.add(new ValidationResult.ValidationError(
                        ValidationConstants.ERROR_SYNTAX_STREAM_LENGTH_INVALID, "Stream length is invalide"));
            }
        } else {
            /*
             * 
             * Offset is null. The stream isn't used, check is useless.
             * 
             * TODO : Is it the truth? 
             */
        }
    } catch (IOException e) {
        throw new ValidationException("Unable to read a stream to validate it due to : " + e.getMessage(), e);
    } finally {
        if (ra != null) {
            IOUtils.closeQuietly(ra);
        }
    }
}