Project: autopsy
/*
 * Autopsy Forensic Browser 
 * 
 * Copyright 2012 Basis Technology Corp. 
 * Contact: carrier <at> sleuthkit <dot> org 
 * 
 * Licensed 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.sleuthkit.autopsy.coreutils; 
 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.OutputStreamWriter; 
import java.io.UnsupportedEncodingException; 
import java.util.logging.Level; 
import javax.xml.XMLConstants; 
import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.transform.OutputKeys; 
import javax.xml.transform.Result; 
import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerConfigurationException; 
import javax.xml.transform.TransformerException; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.dom.DOMResult; 
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult; 
import javax.xml.validation.Schema; 
import javax.xml.validation.SchemaFactory; 
import javax.xml.validation.Validator; 
import org.w3c.dom.Document; 
import org.xml.sax.SAXException; 
 
/** 
 * XML Utilities 
 *  
 * This class provides basic utilities for working with XML files, such as 
 *  -Validating XML files against a given schema 
 *  -Saving documents to disk 
 *  -Loading documents from disk 
 *  
 */
 
 
public class XMLUtil { 
    /**
     * Utility to validate XML files against pre-defined schema files. 
     *  
     *  The schema files are extracted automatically when this function is called, the XML being validated is not. 
     *  Be sure the XML file is already extracted otherwise it will return false. 
     * @param xmlfile The XML file to validate, in DOMSource format 
     * @param type The file name of the schema to validate against, must exist as a resource in the same package as where this function is being called. 
     *  
     * For example usages, please see KeywordSearchListsXML, HashDbXML, or IngestModuleLoader. 
     *  
     */
 
    public static boolean xmlIsValid(DOMSource xmlfile, Class clazz, String schemaFile) { 
      try
        PlatformUtil.extractResourceToUserConfigDir(clazz, schemaFile); 
        File schemaLoc = new File(PlatformUtil.getUserConfigDirectory() + File.separator + schemaFile); 
        SchemaFactory schm = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
        try
        Schema schema = schm.newSchema(schemaLoc); 
        Validator validator = schema.newValidator(); 
        DOMResult result = new DOMResult(); 
        validator.validate(xmlfile, result); 
        return true
        } 
        catch(SAXException e){ 
            Logger.getLogger(clazz.getName()).log(Level.WARNING, "Unable to validate XML file.", e); 
            return false
        } 
      } 
      catch(IOException e){ 
           Logger.getLogger(clazz.getName()).log(Level.WARNING, "Unable to load XML file [" + xmlfile.toString() + "] of type ["+schemaFile+"]", e); 
            return false
        } 
    } 
     
    /**
     * Evaluates XML files against an XSD. 
     *  
     *  The schema files are extracted automatically when this function is called, the XML being validated is not. 
     *  Be sure the XML file is already extracted otherwise it will return false. 
     * @param xmlfile The XML file to validate 
     * @param type The file name of the schema to validate against, must exist as a resource in the same package as where this function is being called 
     *  
     * For example usages, please see KeywordSearchListsXML, HashDbXML, or IngestModuleLoader. 
     *  
     */
 
    public static boolean xmlIsValid(Document doc, Class clazz, String type){ 
           DOMSource dms = new DOMSource(doc); 
           return xmlIsValid(dms, clazz, type); 
    } 
     
     
     
    /** 
     * Loads XML files from disk 
     *  
     * @param clazz the class this method is invoked from 
     * @param xmlPath the full path to the file to load 
     * @param xsdPath the full path to the file to validate against 
     *  
     */
 
    public static Document loadDoc(Class clazz, String xmlPath, String xsdPath) { 
        DocumentBuilderFactory builderFactory = 
                DocumentBuilderFactory.newInstance(); 
        Document ret = null
 
        try { 
            DocumentBuilder builder = builderFactory.newDocumentBuilder(); 
            ret = builder.parse( 
                    new FileInputStream(xmlPath)); 
        } catch (ParserConfigurationException e) { 
            Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error loading XML file: can't initialize parser.", e); 
 
        } catch (SAXException e) { 
            Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error loading XML file: can't parse XML.", e); 
 
        } catch (IOException e) { 
            //error reading file 
            Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error loading XML file: can't read file.", e); 
 
        } 
        if (!XMLUtil.xmlIsValid(ret, clazz, xsdPath)) { 
            Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error loading XML file: could not validate against [" + xsdPath + "], results may not be accurate"); 
        } 
 
        return ret; 
    } 
     
    /** 
     * Saves XML files to disk 
     *  
     * @param clazz the class this method is invoked from 
     * @param xmlPath the full path to save the XML to 
     * @param encoding to encoding, such as "UTF-8", to encode the file with 
     * @param doc the document to save 
     *  
     */
 
    public static  boolean saveDoc(Class clazz, String xmlPath, String encoding, final Document doc) { 
        TransformerFactory xf = TransformerFactory.newInstance(); 
        xf.setAttribute("indent-number"new Integer(1)); 
        boolean success = false
        try { 
            Transformer xformer = xf.newTransformer(); 
            xformer.setOutputProperty(OutputKeys.METHOD, "xml"); 
            xformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
            xformer.setOutputProperty(OutputKeys.ENCODING, encoding); 
            xformer.setOutputProperty(OutputKeys.STANDALONE, "yes"); 
            xformer.setOutputProperty(OutputKeys.VERSION, "1.0"); 
            File file = new File(xmlPath); 
            FileOutputStream stream = new FileOutputStream(file); 
            Result out = new StreamResult(new OutputStreamWriter(stream, encoding)); 
            xformer.transform(new DOMSource(doc), out); 
            stream.flush(); 
            stream.close(); 
            success = true
 
        } catch (UnsupportedEncodingException e) { 
            Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Should not happen", e); 
        } catch (TransformerConfigurationException e) { 
            Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error writing XML file", e); 
        } catch (TransformerException e) { 
            Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error writing XML file", e); 
        } catch (FileNotFoundException e) { 
            Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error writing XML file: cannot write to file: " + xmlPath, e); 
        } catch (IOException e) { 
            Logger.getLogger(clazz.getName()).log(Level.SEVERE, "Error writing XML file: cannot write to file: " + xmlPath, e); 
        } 
        return success; 
    } 
     
}