<commit_before>package org.verapdf.model.tools;

import org.apache.log4j.Logger;
import org.apache.pdfbox.cos.*;
import org.apache.pdfbox.util.DateConverter;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.AdobePDFSchema;
import org.apache.xmpbox.schema.DublinCoreSchema;
import org.apache.xmpbox.schema.XMPBasicSchema;
import org.apache.xmpbox.type.AbstractField;
import org.apache.xmpbox.type.ArrayProperty;
import org.apache.xmpbox.xml.DomXmpParser;
import org.apache.xmpbox.xml.XmpParsingException;

import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This class matches document information dictionary and xmp metadata by
 * comparing eight predefined fields:
 * <ol>
 * <li>Title (-> Title)</li>
 * <li>Author (-> Creators)</li>
 * <li>Producer (-> Producer)</li>
 * <li>Creator (-> CreatorTool)</li>
 * <li>Keywords (-> Keywords)</li>
 * <li>Subject (-> Description)</li>
 * <li>Creation Date (-> Create Date)</li>
 * <li>Mod Date (-> Modify Date)</li>
 * </ol>
 * Property shouldn't be defined in xmp metadata if not present in document
 * information dictionary.
 *
 * @author <NAME>
 */
public final class XMPChecker {

    private static final Logger LOGGER = Logger.getLogger(XMPChecker.class);

    private static final String TITLE = "Title";
    private static final String SUBJECT = "Subject";
    private static final String AUTHOR = "Author";
    private static final String KEYWORDS = "Keywords";
    private static final String PRODUCER = "Producer";
    private static final String CREATOR = "Creator";
    private static final String CREATION_DATE = "CreationDate";
    private static final String MODIFICATION_DATE = "ModDate";
    private static final int MAX_REQUIRED_RECORDS = 8;

    private XMPChecker() {
		// disable default constructor
    }

    /**
     * Matches properties of document information dictionary and xmp metadata.
     * 
     * @param document
     *            which will be tested
     * @return true if fields of xmp matches with fields of info dictionary
     */
    public static Boolean doesInfoMatchXMP(COSDocument document) {
        COSDictionary info = getInformationDictionary(document);
        if (info == null) {
            return Boolean.TRUE;
        }

        try {
            COSStream meta = getMetadataDictionary(document);
            if (meta != null) {
                DomXmpParser xmpParser = new DomXmpParser();
                XMPMetadata metadata = xmpParser.parse(meta
                        .getUnfilteredStream());

                Map<String, Object> properties = new HashMap<>(
                        MAX_REQUIRED_RECORDS);

                getTitleAuthorSubject(metadata, properties);

                getProducerKeywords(metadata, properties);

                getCreatorAndDates(metadata, properties);

                return checkMatch(info, properties);
            }
        } catch (IOException e) {
            LOGGER.error(
                    "Problems with document parsing or structure. "
                            + e.getMessage(), e);
        } catch (XmpParsingException e) {
            LOGGER.error("Problems with XMP parsing. " + e.getMessage(), e);
        }

        return Boolean.FALSE;
    }

    private static COSStream getMetadataDictionary(COSDocument document)
            throws IOException {
        final COSDictionary catalog = (COSDictionary) document.getCatalog()
                .getObject();
        final COSObject metaObj = (COSObject) catalog.getItem(COSName.METADATA);
        if (metaObj != null && metaObj.getObject() instanceof COSStream) {
            return (COSStream) metaObj.getObject();
        }
        return null;
    }

    private static COSDictionary getInformationDictionary(COSDocument document) {
        final COSObject info = (COSObject) document.getTrailer().getItem(
				COSName.INFO);
        if (info != null) {
            if (info.getObject() instanceof COSDictionary) {
                return (COSDictionary) info.getObject();
            } else if (info.getObject() instanceof COSObject) {
                return getInformationDictionary((COSObject) info.getObject());
            }
        }
        return null;<commit_msg>fixed error in validating for classcast exception in does info match xmp check<commit_after>package org.verapdf.model.tools;

import org.apache.log4j.Logger;
import org.apache.pdfbox.cos.*;
import org.apache.pdfbox.util.DateConverter;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.AdobePDFSchema;
import org.apache.xmpbox.schema.DublinCoreSchema;
import org.apache.xmpbox.schema.XMPBasicSchema;
import org.apache.xmpbox.xml.DomXmpParser;
import org.apache.xmpbox.xml.XmpParsingException;

import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This class matches document information dictionary and xmp metadata by
 * comparing eight predefined fields:
 * <ol>
 * <li>Title (-> Title)</li>
 * <li>Author (-> Creators)</li>
 * <li>Producer (-> Producer)</li>
 * <li>Creator (-> CreatorTool)</li>
 * <li>Keywords (-> Keywords)</li>
 * <li>Subject (-> Description)</li>
 * <li>Creation Date (-> Create Date)</li>
 * <li>Mod Date (-> Modify Date)</li>
 * </ol>
 * Property shouldn't be defined in xmp metadata if not present in document
 * information dictionary.
 *
 * @author <NAME>
 */
public final class XMPChecker {

    private static final Logger LOGGER = Logger.getLogger(XMPChecker.class);

    private static final String TITLE = "Title";
    private static final String SUBJECT = "Subject";
    private static final String AUTHOR = "Author";
    private static final String KEYWORDS = "Keywords";
    private static final String PRODUCER = "Producer";
    private static final String CREATOR = "Creator";
    private static final String CREATION_DATE = "CreationDate";
    private static final String MODIFICATION_DATE = "ModDate";
    private static final int MAX_REQUIRED_RECORDS = 8;

    private XMPChecker() {
		// disable default constructor
    }

    /**
     * Matches properties of document information dictionary and xmp metadata.
     * 
     * @param document
     *            which will be tested
     * @return true if fields of xmp matches with fields of info dictionary
     */
    public static Boolean doesInfoMatchXMP(COSDocument document) {
        COSDictionary info = getInformationDictionary(document);
        if (info == null) {
            return Boolean.TRUE;
        }

        try {
            COSStream meta = getMetadataDictionary(document);
            if (meta != null) {
                DomXmpParser xmpParser = new DomXmpParser();
                XMPMetadata metadata = xmpParser.parse(meta
                        .getUnfilteredStream());

                Map<String, Object> properties = new HashMap<>(
                        MAX_REQUIRED_RECORDS);

                getTitleAuthorSubject(metadata, properties);

                getProducerKeywords(metadata, properties);

                getCreatorAndDates(metadata, properties);

                return checkMatch(info, properties);
            }
        } catch (IOException e) {
            LOGGER.error(
                    "Problems with document parsing or structure. "
                            + e.getMessage(), e);
        } catch (XmpParsingException e) {
            LOGGER.error("Problems with XMP parsing. " + e.getMessage(), e);
        } catch (ClassCastException e) {
            LOGGER.error("Problems with properties types. " + e.getMessage(), e);
        }

        return Boolean.FALSE;
    }

    private static COSStream getMetadataDictionary(COSDocument document)
            throws IOException {
        final COSDictionary catalog = (COSDictionary) document.getCatalog()
                .getObject();
        final COSObject metaObj = (COSObject) catalog.getItem(COSName.METADATA);
        if (metaObj != null && metaObj.getObject() instanceof COSStream) {
            return (COSStream) metaObj.getObject();
        }
        return null;
    }

    private static COSDictionary getInformationDictionary(COSDocument document) {
        final COSObject info = (COSObject) document.getTrailer().getItem(
				COSName.INFO);
        if (info != null) {
            if (info.getObject() instanceof COSDictionary) {
                return (COSDictionary) info.getObject();
            } else if (info.getObject() instanceof COSObject) {
                return getInformationDictionary((COSObject) info.getObject());
            }
        }
        return null;
{'fraction_non_alphanumeric': 0.0998180991359709, 'fraction_numerical': 0.00045475216007276033, 'mean_word_length': 2.651722706517227, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1465865', 'n_tokens_mistral': 2435, 'n_tokens_neox': 2360, 'n_words': 640}