/* * * Copyright 2012 lexergen. * This file is part of lexergen. * * lexergen is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * lexergen is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with lexergen. If not, see <http://www.gnu.org/licenses/>. * * lexergen: * A tool to chunk source code into tokens for further processing in a compiler chain. * * Projectgroup: bi, bii * * Authors: Maximilian Schröder, Daniel Rotar, Johannes Dahlke * * Module: Softwareprojekt Übersetzerbau 2012 * * Created: Apr. 2012 * Version: 1.0 * */ package de.fuberlin.bii.dfaprovider; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import de.fuberlin.bii.regextodfaconverter.MinimalDfa; import de.fuberlin.bii.tokenmatcher.StatePayload; import de.fuberlin.bii.utils.Notification; /** * Stellt einen minimalen DFA-Provider dar, der minimale DFA's, auf Basis (von * mindestens) einer regulären Definitionsdatei und einem * {@link MinimalDfaBuilder}, erzeugt. * * Dabei können zusätlich folgende optionale Parameter angegeben - DFA-Laden - * DFA-Speichern - Speicherpfad der Serialisierung * * @author Maximilian Schröder * @author Daniel Rotar * */ public class MinimalDfaProvider { /** * Gibt einen minimalen DFA aus, der auf Basis der regulären * Definitionsdatei und dem minimalen DFA-Builder erzeugt wurde. * * @param rdFile * reguläre Definitionsdatei die dem minimalen DFA-Builder zur * DFA-Erzeugung übergeben wird * @param builder * minimaler DFA-Builder der, mittels der übergebenen regulären * Definitionsdatei, einen minimalen DFA erzeugt * @return minimaler DFA der auf Basis der regulären Definitionsdatei und * des minimalen DFA-Builders erzeugt und gegebenenfalls * deserialisiert und/oder abgespeichert wurde * @throws MinimalDfaProviderException * Wenn ein Fehler beim Erstellen des DFA's auftritt. */ public static MinimalDfa<Character, StatePayload> getMinimalDfa( File rdFile, MinimalDfaBuilder builder) throws MinimalDfaProviderException { return getMinimalDfa(rdFile, builder, false); } /** * Gibt einen minimalen DFA aus, der auf Basis der regulären * Definitionsdatei und dem minimalen DFA-Builder erzeugt wurde. * * @param rdFile * reguläre Definitionsdatei die dem minimalen DFA-Builder zur * DFA-Erzeugung übergeben wird * @param builder * minimaler DFA-Builder der, mittels der übergebenen regulären * Definitionsdatei, einen minimalen DFA erzeugt * @param skipDeserialization * Angabe, ob das Laden des minimalen DFA übersprungen werden * soll oder nicht * @return minimaler DFA der auf Basis der regulären Definitionsdatei und * des minimalen DFA-Builders erzeugt und gegebenenfalls * deserialisiert und/oder abgespeichert wurde * @throws MinimalDfaProviderException * Wenn ein Fehler beim Erstellen des DFA's auftritt. */ public static MinimalDfa<Character, StatePayload> getMinimalDfa( File rdFile, MinimalDfaBuilder builder, boolean skipDeserialization) throws MinimalDfaProviderException { return getMinimalDfa(rdFile, builder, skipDeserialization, false); } /** * Gibt einen minimalen DFA aus, der auf Basis der regulären * Definitionsdatei und dem minimalen DFA-Builder erzeugt wurde. * * @param rdFile * reguläre Definitionsdatei die dem minimalen DFA-Builder zur * DFA-Erzeugung übergeben wird * @param builder * minimaler DFA-Builder der, mittels der übergebenen regulären * Definitionsdatei, einen minimalen DFA erzeugt * @param skipDeserialization * Angabe, ob das Laden des minimalen DFA übersprungen werden * soll oder nicht * @param skipSerialization * Angabe, ob das Speichern des minimalen DFA übersprungen werden * soll oder nicht * @return minimaler DFA der auf Basis der regulären Definitionsdatei und * des minimalen DFA-Builders erzeugt und gegebenenfalls * deserialisiert und/oder abgespeichert wurde * @throws MinimalDfaProviderException * Wenn ein Fehler beim Erstellen des DFA's auftritt. */ public static MinimalDfa<Character, StatePayload> getMinimalDfa( File rdFile, MinimalDfaBuilder builder, boolean skipDeserialization, boolean skipSerialization) throws MinimalDfaProviderException { File dfaFile = new File(rdFile.getAbsolutePath() + ".dfa"); return getMinimalDfa(rdFile, builder, skipDeserialization, skipSerialization, dfaFile); } /** * Gibt einen minimalen DFA aus, der auf Basis der regulären * Definitionsdatei und dem minimalen DFA-Builder erzeugt wurde. * * @param rdFile * reguläre Definitionsdatei die dem minimalen DFA-Builder zur * DFA-Erzeugung übergeben wird * @param builder * minimaler DFA-Builder der, mittels der übergebenen regulären * Definitionsdatei, einen minimalen DFA erzeugt * @param skipDeserialization * Angabe, ob das Laden des minimalen DFA übersprungen werden * soll oder nicht * @param skipSerialization * Angabe, ob das Speichern des minimalen DFA übersprungen werden * soll oder nicht * @param dfaFile * Pfad zum Ort, an dem der minimale DFA * abgespeichert/serialisiert werden soll * @return minimaler DFA der auf Basis der regulären Definitionsdatei und * des minimalen DFA-Builders erzeugt und gegebenenfalls * deserialisiert und/oder abgespeichert wurde * @throws MinimalDfaProviderException * Wenn ein Fehler beim Zurückgeben des DFA's auftritt. */ public static MinimalDfa<Character, StatePayload> getMinimalDfa( File rdFile, MinimalDfaBuilder builder, boolean skipDeserialization, boolean skipSerialization, File dfaFile) throws MinimalDfaProviderException { /** Auf Fehleingaben überprüfen */ if (builder == null) { throw new MinimalDfaProviderException( "Der Parameter builder darf nicht null sein!"); } if (!rdFile.exists()) { throw new MinimalDfaProviderException("Die angegebene Datei '" + rdFile.getAbsolutePath() + "' existiert nicht!"); } if (!rdFile.isFile()) { throw new MinimalDfaProviderException("Der angegebene Pfad '" + rdFile.getAbsolutePath() + "' verweist nicht auf eine Datei (mit regulären Definitionen)!"); } // // if (!dfaFile.isFile()) { // throw new MinimalDfaProviderException("Der angegebene Pfad '" + dfaFile.getAbsolutePath() // + "' verweist nicht auf eine Datei (mit serialisiertem DFA)!"); // } /** Logik */ String version = getVersion(); String rdFileHash; try { rdFileHash = getFilehashAsString(rdFile); } catch (IOException e) { throw new MinimalDfaProviderException("Die angegebene Datei '" + rdFile.getAbsolutePath() + "' konnte nicht verarbeitet werden: " + e.getMessage()); } MinimalDfa<Character, StatePayload> mDfa = null; if (!skipDeserialization) { MinimalDfaCharacterStatePayloadWrapper wrapper; try { wrapper = MinimalDfaCharacterStatePayloadWrapper.load(dfaFile); if ((version.equals(wrapper.getVersion())) && (rdFileHash.equals(wrapper.getRdFileHash()))) { mDfa = wrapper.getMDfa(); } } catch (Exception e) { Notification.printErrorMessage("Error: Fehler beim Deserialisieren des minimalen DFA: " + e.getMessage()); } } if (mDfa == null) { try { mDfa = builder.buildMinimalDfa(rdFile); } catch (MinimalDfaBuilderException e) { throw new MinimalDfaProviderException( "Fehler beim Erzeugen des minimalen Dfa: " + e.getMessage()); } } if (!skipSerialization) { MinimalDfaCharacterStatePayloadWrapper wrapper = new MinimalDfaCharacterStatePayloadWrapper( version, rdFileHash, mDfa); try { wrapper.save(dfaFile); } catch (IOException e) { Notification.printErrorMessage("Error: Fehler beim Serialisieren des minimalen DFA: " + e.getMessage()); } } return mDfa; } /** * Erzeugt den SHA-Hash einer Datei, formt diesen in Hexadezimalformat um * und erzeugt davon den String. * * @param file * Datei, von der der SHA-Hash erzeugt werden soll. * @return Hash-String in Hexadezimalformat zur übergebenen Datei * @throws IOException * Leseproblem bzgl. der Eingabe-Datei */ private static String getFilehashAsString(File file) throws IOException { MessageDigest md = null; try { // Algo festlegen und Datei lesen md = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException e) { // Dieser Fall kann niemals eintreten, da seit Java 1.5 der // SHA-Algorithmus bekannt ist e.printStackTrace(); } FileInputStream fis = new FileInputStream(file.getAbsolutePath()); byte[] fileBytes = new byte[5120]; int readbytes = 0; while ((readbytes = fis.read(fileBytes)) != -1) { md.update(fileBytes, 0, readbytes); } byte[] digest = md.digest(); // Umwandlung von Byte in Hexadezimalformat StringBuffer sb = new StringBuffer(""); for (int i = 0; i < digest.length; i++) { sb.append(Integer.toString((digest[i] & 0xff) + 0x100, 16) .substring(1)); } return (sb.toString()); } /** * Liest die aktuelle Version aus und gibt diese zurück. * @return Die aktuelle Version. */ private static String getVersion() { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = null; try { db = dbf.newDocumentBuilder(); } catch (ParserConfigurationException e) { return "unknown"; } Document dom; try { dom = db.parse("pom.xml"); } catch (Exception e) { return "unknown"; } Element docEle = dom.getDocumentElement(); NodeList nl = docEle.getElementsByTagName("version"); return nl.item(0).getFirstChild().getNodeValue(); } }