//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.apache.poi.util;

import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.validation.SchemaFactory;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;

@Internal
public final class XMLHelper {
    static final String FEATURE_LOAD_DTD_GRAMMAR = "http://apache.org/xml/features/nonvalidating/load-dtd-grammar";
    static final String FEATURE_LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
    static final String FEATURE_DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
    static final String FEATURE_PARAMETER_ENTITIES = "http://xml.org/sax/features/external-parameter-entities";
    static final String FEATURE_EXTERNAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
    static final String PROPERTY_ENTITY_EXPANSION_LIMIT = "http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit";
    static final String PROPERTY_SECURITY_MANAGER = "http://apache.org/xml/properties/security-manager";
    static final String METHOD_ENTITY_EXPANSION_XERCES = "setEntityExpansionLimit";
    static final String[] SECURITY_MANAGERS = new String[]{"org.apache.xerces.util.SecurityManager"};
    private static final Logger LOG = LogManager.getLogger(XMLHelper.class);
    private static long lastLog;
    private static final DocumentBuilderFactory documentBuilderFactory = getDocumentBuilderFactory();
    private static final SAXParserFactory saxFactory = getSaxParserFactory();

    private XMLHelper() {
    }

    public static DocumentBuilderFactory getDocumentBuilderFactory() {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        factory.setExpandEntityReferences(false);
        factory.setValidating(false);
        trySet(factory::setFeature, "http://javax.xml.XMLConstants/feature/secure-processing", true);
        trySet(factory::setAttribute, "http://javax.xml.XMLConstants/property/accessExternalSchema", "");
        trySet(factory::setAttribute, "http://javax.xml.XMLConstants/property/accessExternalDTD", "");
        trySet(factory::setFeature, "http://xml.org/sax/features/external-general-entities", false);
        trySet(factory::setFeature, "http://xml.org/sax/features/external-parameter-entities", false);
        trySet(factory::setFeature, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        trySet(factory::setFeature, "http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
        trySet(factory::setFeature, "http://apache.org/xml/features/disallow-doctype-decl", true);
        trySet((n, b) -> {
            factory.setXIncludeAware(b);
        }, "XIncludeAware", false);
        Object manager = getXercesSecurityManager();
        if (manager == null || !trySet(factory::setAttribute, "http://apache.org/xml/properties/security-manager", manager)) {
            trySet(factory::setAttribute, "http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit", 1);
        }

        return factory;
    }

    public static DocumentBuilder newDocumentBuilder() {
        try {
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            documentBuilder.setEntityResolver(XMLHelper::ignoreEntity);
            documentBuilder.setErrorHandler(new DocHelperErrorHandler());
            return documentBuilder;
        } catch (ParserConfigurationException var1) {
            throw new IllegalStateException("cannot create a DocumentBuilder", var1);
        }
    }

    public static SAXParserFactory getSaxParserFactory() {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setValidating(false);
            factory.setNamespaceAware(true);
            trySet(factory::setFeature, "http://javax.xml.XMLConstants/feature/secure-processing", true);
            trySet(factory::setFeature, "http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
            trySet(factory::setFeature, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            trySet(factory::setFeature, "http://xml.org/sax/features/external-general-entities", false);
            trySet(factory::setFeature, "http://apache.org/xml/features/disallow-doctype-decl", true);
            return factory;
        } catch (Error | RuntimeException var1) {
            logThrowable(var1, "Failed to create SAXParserFactory", "-");
            throw var1;
        } catch (Exception var2) {
            logThrowable(var2, "Failed to create SAXParserFactory", "-");
            throw new RuntimeException("Failed to create SAXParserFactory", var2);
        }
    }

    public static XMLReader newXMLReader() throws SAXException, ParserConfigurationException {
        XMLReader xmlReader = saxFactory.newSAXParser().getXMLReader();
        xmlReader.setEntityResolver(XMLHelper::ignoreEntity);
        trySet(xmlReader::setFeature, "http://javax.xml.XMLConstants/feature/secure-processing", true);
        trySet(xmlReader::setFeature, "http://xml.org/sax/features/external-general-entities", false);
        Object manager = getXercesSecurityManager();
        if (manager == null || !trySet(xmlReader::setProperty, "http://apache.org/xml/properties/security-manager", manager)) {
            trySet(xmlReader::setProperty, "http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit", 1);
        }

        return xmlReader;
    }

    public static XMLInputFactory newXMLInputFactory() {
        XMLInputFactory factory = XMLInputFactory.newInstance();
        trySet(factory::setProperty, "javax.xml.stream.isNamespaceAware", true);
        trySet(factory::setProperty, "javax.xml.stream.isValidating", false);
        trySet(factory::setProperty, "javax.xml.stream.supportDTD", false);
        trySet(factory::setProperty, "javax.xml.stream.isSupportingExternalEntities", false);
        return factory;
    }

    public static XMLOutputFactory newXMLOutputFactory() {
        XMLOutputFactory factory = XMLOutputFactory.newInstance();
        trySet(factory::setProperty, "javax.xml.stream.isRepairingNamespaces", true);
        return factory;
    }

    public static XMLEventFactory newXMLEventFactory() {
        return XMLEventFactory.newInstance();
    }

    public static TransformerFactory getTransformerFactory() {
        TransformerFactory factory = TransformerFactory.newInstance();
        trySet(factory::setFeature, "http://javax.xml.XMLConstants/feature/secure-processing", true);
        quietSet(factory::setAttribute, "http://javax.xml.XMLConstants/property/accessExternalDTD", "");
        trySet(factory::setAttribute, "http://javax.xml.XMLConstants/property/accessExternalStylesheet", "");
        quietSet(factory::setAttribute, "http://javax.xml.XMLConstants/property/accessExternalSchema", "");
        return factory;
    }

    public static Transformer newTransformer() throws TransformerConfigurationException {
        Transformer serializer = getTransformerFactory().newTransformer();
        serializer.setOutputProperty("encoding", "UTF-8");
        serializer.setOutputProperty("indent", "no");
        serializer.setOutputProperty("method", "xml");
        return serializer;
    }

    public static SchemaFactory getSchemaFactory() {
        SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
        trySet(factory::setFeature, "http://javax.xml.XMLConstants/feature/secure-processing", true);
        trySet(factory::setProperty, "http://javax.xml.XMLConstants/property/accessExternalDTD", "");
        trySet(factory::setProperty, "http://javax.xml.XMLConstants/property/accessExternalStylesheet", "");
        trySet(factory::setProperty, "http://javax.xml.XMLConstants/property/accessExternalSchema", "");
        return factory;
    }

    private static Object getXercesSecurityManager() {
        String[] var0 = SECURITY_MANAGERS;
        int var1 = var0.length;

        for(int var2 = 0; var2 < var1; ++var2) {
            String securityManagerClassName = var0[var2];

            try {
                Object mgr = Class.forName(securityManagerClassName).getDeclaredConstructor().newInstance();
                Method setLimit = mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE);
                setLimit.invoke(mgr, 1);
                return mgr;
            } catch (ClassNotFoundException var6) {
            } catch (Throwable var7) {
                logThrowable(var7, "SAX Feature unsupported", securityManagerClassName);
            }
        }

        return null;
    }

    private static boolean trySet(SecurityFeature feature, String name, boolean value) {
        try {
            feature.accept(name, value);
            return true;
        } catch (Exception var4) {
            logThrowable(var4, "SAX Feature unsupported", name);
        } catch (Error var5) {
            logThrowable(var5, "Cannot set SAX feature because outdated XML parser in classpath", name);
        }

        return false;
    }

    private static boolean trySet(SecurityProperty property, String name, Object value) {
        try {
            property.accept(name, value);
            return true;
        } catch (Exception var4) {
            logThrowable(var4, "SAX Feature unsupported", name);
        } catch (Error var5) {
            logThrowable(var5, "Cannot set SAX feature because outdated XML parser in classpath", name);
        }

        return false;
    }

    private static boolean quietSet(SecurityProperty property, String name, Object value) {
        try {
            property.accept(name, value);
            return true;
        } catch (Error | Exception var4) {
            return false;
        }
    }

    private static void logThrowable(Throwable t, String message, String name) {
        if (System.currentTimeMillis() > lastLog + TimeUnit.MINUTES.toMillis(5L)) {
            //LOG.atWarn().withThrowable(t).log("{} [log suppressed for 5 minutes]{}", message, name);
            lastLog = System.currentTimeMillis();
        }

    }

    private static InputSource ignoreEntity(String publicId, String systemId) {
        return new InputSource(new StringReader(""));
    }

    private static class DocHelperErrorHandler implements ErrorHandler {
        private DocHelperErrorHandler() {
        }

        public void warning(SAXParseException exception) {
            this.printError(Level.WARN, exception);
        }

        public void error(SAXParseException exception) {
            this.printError(Level.ERROR, exception);
        }

        public void fatalError(SAXParseException exception) throws SAXException {
            this.printError(Level.FATAL, exception);
            throw exception;
        }

        private void printError(Level type, SAXParseException ex) {
            String systemId = ex.getSystemId();
            if (systemId != null) {
                int index = systemId.lastIndexOf(47);
                if (index != -1) {
                    systemId = systemId.substring(index + 1);
                }
            }

            String message = (systemId == null ? "" : systemId) + ':' + ex.getLineNumber() + ':' + ex.getColumnNumber() + ':' + ex.getMessage();
            XMLHelper.LOG.atLevel(type).withThrowable(ex).log(message);
        }
    }

    @FunctionalInterface
    private interface SecurityProperty {
        void accept(String var1, Object var2) throws SAXException;
    }

    @FunctionalInterface
    private interface SecurityFeature {
        void accept(String var1, boolean var2) throws ParserConfigurationException, SAXException, TransformerException;
    }
}
