Package org.apache.pdfbox.preflight.content

Source Code of org.apache.pdfbox.preflight.content.PreflightContentStream

/*****************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*
****************************************************************************/

package org.apache.pdfbox.preflight.content;

import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_ENCODING_ERROR;
import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_FONTS_UNKNOWN_FONT_REF;
import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_SYNTAX_CONTENT_STREAM_INVALID_ARGUMENT;
import static org.apache.pdfbox.preflight.PreflightConstants.ERROR_SYNTAX_CONTENT_STREAM_UNSUPPORTED_OP;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSFloat;
import org.apache.pdfbox.cos.COSInteger;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.graphics.pattern.PDTilingPattern;
import org.apache.pdfbox.pdmodel.graphics.state.PDTextState;
import org.apache.pdfbox.pdmodel.graphics.state.RenderingMode;
import org.apache.pdfbox.preflight.PreflightContext;
import org.apache.pdfbox.preflight.ValidationResult.ValidationError;
import org.apache.pdfbox.preflight.exception.ValidationException;
import org.apache.pdfbox.preflight.font.container.FontContainer;
import org.apache.pdfbox.preflight.font.util.GlyphException;
import org.apache.pdfbox.contentstream.operator.Operator;

public class PreflightContentStream extends PreflightStreamEngine
{
    public PreflightContentStream(PreflightContext _context, PDPage _page)
    {
        super(_context, _page);
    }

    /**
     * Process the validation of a PageContent (The page is initialized by the constructor)
     *
     * @throws ValidationException
     */
    public void validPageContentStream() throws ValidationException
    {
        try
        {
            PDStream pstream = this.processeedPage.getStream();
            if (pstream != null)
            {
                processPage(this.processeedPage);
            }
        }
        catch (ContentStreamException e)
        {
            context.addValidationError(new ValidationError(e.getErrorCode(), e.getMessage()));
        }
        catch (IOException e)
        {
            throw new ValidationException("Unable to check the ContentStream : " + e.getMessage(), e);
        }
    }

    /**
     * Process the validation of a XObject Form
     *
     * @param form the PDFormXObject to be validated.
     * @throws ValidationException
     */
    public void validXObjContentStream(PDFormXObject form) throws ValidationException
    {
        try
        {
            // workaround for preflight not finding widget annotation parent PDPage
            if (processeedPage == null)
            {
                processChildStream(form, new PDPage()); // dummy page, resource lookup may fail
            }
            else
            {
                processChildStream(form, processeedPage);
            }
        }
        catch (ContentStreamException e)
        {
            context.addValidationError(new ValidationError(e.getErrorCode(), e.getMessage()));
        }
        catch (IOException e)
        {
            throw new ValidationException("Unable to check the ContentStream : " + e.getMessage(), e);
        }
    }

    /**
     * Process the validation of a Tiling Pattern
     *
     * @param pattern the PDTilingPattern to be validated.
     * @throws ValidationException
     */
    public void validPatternContentStream(PDTilingPattern pattern) throws ValidationException
    {
        try
        {
            processChildStream(pattern, processeedPage);
        }
        catch (ContentStreamException e)
        {
            context.addValidationError(new ValidationError(e.getErrorCode(), e.getMessage()));
        }
        catch (IOException e)
        {
            throw new ValidationException("Unable to check the ContentStream : " + e.getMessage(), e);
        }
    }

    @Override
    protected void processOperator(Operator operator, List<COSBase> arguments) throws IOException
    {
        super.processOperator(operator, arguments);

        // todo: why are the checks below done here and not in OperatorProcessor classes?

        /*
         * Process Specific Validation. The Generic Processing is useless for PDF/A validation
         */
        if ("BI".equals(operator.getName()))
        {
            validImageFilter(operator);
            validImageColorSpace(operator);
        }

        checkShowTextOperators(operator, arguments);
        checkColorOperators(operator.getName());
        validRenderingIntent(operator, arguments);
        checkSetColorSpaceOperators(operator, arguments);
        validNumberOfGraphicStates(operator);
    }

    @Override
    protected void unsupportedOperator(Operator operator, List<COSBase> arguments)
    {
        registerError("The operator \"" + operator.getName() + "\" isn't supported.",
                ERROR_SYNTAX_CONTENT_STREAM_UNSUPPORTED_OP);
    }

    /**
     * Process Text Validation. According to the operator one of the both method will be called.
     * (validStringDefinition(PDFOperator operator, List<?> arguments) / validStringArray(PDFOperator operator, List<?>
     * arguments))
     *
     * @param operator
     * @param arguments
     * @throws ContentStreamException
     * @throws IOException
     */
    protected void checkShowTextOperators(Operator operator, List<?> arguments) throws ContentStreamException,
            IOException
    {
        String op = operator.getName();
        if ("Tj".equals(op) || "'".equals(op) || "\"".equals(op))
        {
            validStringDefinition(operator, arguments);
        }

        if ("TJ".equals(op))
        {
            validStringArray(operator, arguments);
        }
    }

    /**
     * Process Text Validation for the Operands of a Tj, "'" and "\"" operator.
     *
     * If the validation fails for an unexpected reason, a IOException is thrown. If the validation fails due to
     * validation error, a ContentStreamException is thrown. (Use the ValidationError attribute to know the cause)
     *
     * @param operator
     * @param arguments
     * @throws ContentStreamException
     * @throws IOException
     */
    private void validStringDefinition(Operator operator, List<?> arguments) throws ContentStreamException,
            IOException
    {
        /*
         * For a Text operator, the arguments list should contain only one COSString object
         */
        if ("\"".equals(operator.getName()))
        {
            if (arguments.size() != 3)
            {
                registerError("Invalid argument for the operator : " + operator.getName(),
                        ERROR_SYNTAX_CONTENT_STREAM_INVALID_ARGUMENT);
                return;
            }
            Object arg0 = arguments.get(0);
            Object arg1 = arguments.get(1);
            Object arg2 = arguments.get(2);
            if (!(arg0 instanceof COSInteger || arg0 instanceof COSFloat)
                    || !(arg1 instanceof COSInteger || arg1 instanceof COSFloat))
            {
                registerError("Invalid argument for the operator : " + operator.getName(),
                        ERROR_SYNTAX_CONTENT_STREAM_INVALID_ARGUMENT);
                return;
            }

            if (arg2 instanceof COSString)
            {
                validText(((COSString) arg2).getBytes());
            }
            else
            {
                registerError("Invalid argument for the operator : " + operator.getName(),
                        ERROR_SYNTAX_CONTENT_STREAM_INVALID_ARGUMENT);
            }
        }
        else
        {
            Object objStr = arguments.get(0);
            if (objStr instanceof COSString)
            {
                validText(((COSString) objStr).getBytes());
            }
            else if (!(objStr instanceof COSInteger))
            {
                registerError("Invalid argument for the operator : " + operator.getName(),
                        ERROR_SYNTAX_CONTENT_STREAM_INVALID_ARGUMENT);
            }
        }
    }

    /**
     * Process Text Validation for the Operands of a TJ operator.
     *
     * If the validation fails for an unexpected reason, a IOException is thrown. If the validation fails due to
     * validation error, a ContentStreamException is thrown. (Use the ValidationError attribute to know the cause)
     *
     * @param operator
     * @param arguments
     * @throws ContentStreamException
     * @throws IOException
     */
    private void validStringArray(Operator operator, List<?> arguments) throws ContentStreamException, IOException
    {
        for (Object object : arguments)
        {
            if (object instanceof COSArray)
            {
                validStringArray(operator, ((COSArray) object).toList());
            }
            else if (object instanceof COSString)
            {
                validText(((COSString) object).getBytes());
            }
            else if (!(object instanceof COSInteger || object instanceof COSFloat))
            {
                registerError("Invalid argument for the operator : " + operator.getName(),
                        ERROR_SYNTAX_CONTENT_STREAM_INVALID_ARGUMENT);
                return;
            }
        }
    }

    /**
     * Process the validation of a Text operand contains in a ContentStream This validation checks that :
     * <UL>
     * <li>The font isn't missing if the Rendering Mode isn't 3
     * <li>The font metrics are consistent
     * <li>All character used in the text are defined in the font program.
     * </UL>
     *
     * @param string
     * @throws IOException
     */
    public void validText(byte[] string) throws IOException
    {
        // TextSize accessible through the TextState
        PDTextState textState = getGraphicsState().getTextState();
        final RenderingMode renderingMode = textState.getRenderingMode();
        final PDFont font = textState.getFont();
        if (font == null)
        {
            // Unable to decode the Text without Font
            registerError("Text operator can't be process without Font", ERROR_FONTS_UNKNOWN_FONT_REF);
            return;
        }

        FontContainer fontContainer = context.getFontContainer(font.getCOSObject());
        if (renderingMode == RenderingMode.NEITHER && (fontContainer == null || !fontContainer.isEmbeddedFont()))
        {
            // font not embedded and rendering mode is 3. Valid case and nothing to check
            return;
        }
        else if (fontContainer == null)
        {
            // Font Must be embedded if the RenderingMode isn't 3
            registerError(font.getName() + " is unknown wasn't found by the FontHelperValdiator",
                    ERROR_FONTS_UNKNOWN_FONT_REF);
            return;
        }
        else if (!fontContainer.isValid() && !fontContainer.errorsAleadyMerged())
        {
            context.addValidationErrors(fontContainer.getAllErrors());
            fontContainer.setErrorsAlreadyMerged(true);
            return;
        }
        if (!fontContainer.isValid() && fontContainer.errorsAleadyMerged())
        {
            // font already computed
            return;
        }

        InputStream in = new ByteArrayInputStream(string);
        while (in.available() > 0)
        {
            try
            {
                int code = font.readCode(in);
                fontContainer.checkGlyphWidth(code);
            }
            catch (IOException e)
            {
                registerError("Encoding can't interpret the character code", ERROR_FONTS_ENCODING_ERROR, e);
                return;
            }
            catch (GlyphException e)
            {
                if (renderingMode != RenderingMode.NEITHER)
                {
                    registerError(e.getMessage(), e.getErrorCode(), e);
                    return;
                }
            }
        }
    }
}
TOP

Related Classes of org.apache.pdfbox.preflight.content.PreflightContentStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.