package uk.org.smithfamily.utils.normaliser; import java.io.*; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Map; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; public class Normaliser { private enum Section { None, Header, Expressions, Gauges, Logs, FrontPage, Constants, PcVariables, ConstantsExtensions, Menu, TableEditor, CurveEditor, ControllerCommands, UserDefined, SettingGroups } private static final String TAB = " "; private static ECUData ecuData = new ECUData(); private static Map<String, String> classList = new TreeMap<String, String>(); private static Section currentSection; private static String className; private static File outputDirectory; /** * @param args * @throws FileNotFoundException */ public static void main(final String[] args) throws IOException { final File f = new File(args[0]); outputDirectory = new File(args[1]); outputDirectory.mkdirs(); final BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f), "Windows-1252")); String line; while ((line = br.readLine()) != null) { if (!line.startsWith("#")) { preProcess(f.getParent(), line); } } outputRegistry(f.getParentFile()); br.close(); } private static void outputRegistry(final File baseLocation) throws IOException { final File srcDirectory = new File(outputDirectory, "gen_src/uk/org/smithfamily/mslogger/ecuDef/gen"); final File or = new File(srcDirectory, "ECURegistry.java"); final PrintWriter w = new PrintWriter(new FileWriter(or)); final File template = new File(baseLocation, "ECURegistry.java"); final BufferedReader br = new BufferedReader(new FileReader(template)); String line; while ((line = br.readLine()) != null) { if (line.trim().equals("<LIST>")) { for (final String name : classList.keySet()) { final String sig = classList.get(name); w.println(String.format(" registerEcu(%s.class,%s);", name, sig)); } } else { w.println(line); } } br.close(); w.close(); } /** * Initialise our stores to start a new class definition * * @param filename * @param line * @throws IOException */ private static void preProcess(final String directory, final String filename) throws IOException { ecuData.setSignatureDeclaration(""); ecuData.setQueryCommandStr(""); ecuData.reset(); currentSection = Section.None; final File f = new File(directory, filename); if (f.isDirectory()) { return; } className = f.getName(); process(f, false); } // Modified from http://stackoverflow.com/questions/12630089/convert-windows-1252-to-utf-16-in-java private static String replaceWindowsChars(final String text_in) { String s = text_in; final Charset windowsCharset = Charset.forName("windows-1252"); final Charset utfCharset = Charset.forName("UTF-8"); final byte[] incomingBytes = s.getBytes(); final CharBuffer windowsEncoded = windowsCharset.decode(ByteBuffer.wrap(incomingBytes)); final byte[] utfEncoded = utfCharset.encode(windowsEncoded).array(); s = new String(utfEncoded); return s; } /** * Iterate over the file to read it * * @param f * @param subRead * @throws IOException */ private static void process(final File f, final boolean subRead) throws IOException { final BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f), "Windows-1252")); String line; while ((line = br.readLine()) != null) { if (line.startsWith("#include ")) { handleImport(line, f); continue; } if (line.trim().equals("[MegaTune]")) { currentSection = Section.Header; continue; } else if (line.trim().equals("[OutputChannels]")) { currentSection = Section.Expressions; continue; } else if (line.trim().equals("[Datalog]")) { currentSection = Section.Logs; continue; } else if (line.trim().equals("[GaugeConfigurations]")) { currentSection = Section.Gauges; continue; } else if (line.trim().equals("[Menu]")) { currentSection = Section.Menu; continue; } else if (line.trim().equals("[TableEditor]")) { currentSection = Section.TableEditor; continue; } else if (line.trim().equals("[CurveEditor]")) { currentSection = Section.CurveEditor; continue; } else if (line.trim().equals("[UserDefined]")) { currentSection = Section.UserDefined; continue; } else if (line.trim().equals("[FrontPage]")) { currentSection = Section.FrontPage; } else if (line.trim().equals("[Constants]")) { currentSection = Section.Constants; } else if (line.trim().equals("[PcVariables]")) { currentSection = Section.PcVariables; } else if (line.trim().equals("[ConstantsExtensions]")) { currentSection = Section.ConstantsExtensions; } else if (line.trim().equals("[SettingGroups]")) { currentSection = Section.SettingGroups; } else if (line.trim().equals("[ControllerCommands]")) { currentSection = Section.ControllerCommands; } else if (line.trim().startsWith("[")) { currentSection = Section.None; continue; } line = replaceWindowsChars(line); switch (currentSection) { case Expressions: Process.processExpr(ecuData, line); break; case Logs: Process.processLogEntry(ecuData, line); break; case Gauges: Process.processGaugeEntry(ecuData, line); break; case Header: Process.processHeader(ecuData, line); break; case FrontPage: Process.processFrontPage(ecuData, line); break; case Constants: Process.processConstants(ecuData, line); break; case PcVariables: Process.processPcVariables(ecuData, line); break; case ConstantsExtensions: Process.processConstantsExtensions(ecuData, line); break; case Menu: Process.processMenu(ecuData, line); break; case TableEditor: Process.processTableEditor(ecuData, line); break; case CurveEditor: Process.processCurveEditor(ecuData, line); break; case ControllerCommands: Process.processControllerCommands(ecuData, line); break; case UserDefined: Process.processUserDefined(ecuData, line); break; case SettingGroups: Process.processSettingGroups(ecuData, line); case None: break; default: break; } } br.close(); if (!subRead) { writeFile(className); } } /** * Process an included/imported file * * @param line * @param parentFile * @throws IOException */ private static void handleImport(final String line, final File parentFile) throws IOException { final Pattern importFile = Pattern.compile(".*\\\"(.*)\\\""); final Matcher importFileM = importFile.matcher(line); if (importFileM.matches()) { final String fileName = importFileM.group(1); final File imported = new File(parentFile.getAbsoluteFile().getParentFile(), fileName); process(imported, true); } } /** * Write all the firmware definition to a Java class * * @param className The class name to generate * @throws IOException */ private static void writeFile(String className) throws IOException { className = StringUtils.capitalize(className); className = StringUtils.remove(className, "."); className = StringUtils.remove(className, "ini"); className = StringUtils.replace(className, " ", "_"); className = StringUtils.replace(className, "-", "_"); className = StringUtils.replace(className, "&", "_"); String classFile = ""; classList.put(className, ecuData.getClassSignature()); final String directory = outputDirectory.getAbsolutePath() + File.separator + "gen_src/uk/org/smithfamily/mslogger/ecuDef/gen/"; new File(directory).mkdirs(); classFile = directory + className + ".java"; System.out.println("Writing to " + classFile); final PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(classFile), "CP1252")); final String fingerprint = getFingerprint(); System.out.println(fingerprint + " : " + className); Output.outputPackageAndIncludes(ecuData, writer); writer.println("/*"); writer.println("Fingerprint : " + fingerprint); writer.println("*/"); writer.println("@SuppressWarnings(\"unused\")"); writer.println("public class " + className + " implements MSECUInterface, DataSource\n{"); Output.outputConstructor(ecuData, writer, className); Output.outputOutputChannels(ecuData, writer); writer.println(TAB + "private Map<String,Double> fields = new HashMap<String,Double>();"); writer.println(TAB + ecuData.getQueryCommandStr()); writer.println(TAB + ecuData.getSignatureDeclaration()); writer.println(TAB + ecuData.getOchGetCommandStr()); writer.println(TAB + ecuData.getOchBlockSizeStr()); Output.outputRequiresPowerCycle(ecuData, writer); Output.outputRTCalcs(ecuData, writer); Output.outputLogInfo(ecuData, writer); Output.outputMenus(ecuData, writer); Output.outputUserDefined(ecuData, writer); Output.outputTableEditors(ecuData, writer); Output.outputCurves(ecuData, writer); Output.outputUserDefinedVisibilityFlags(ecuData, writer); Output.outputMenuVisibilityFlags(ecuData, writer); Output.outputSettingGroups(ecuData, writer); Output.outputControllerCommands(ecuData, writer); Output.outputOverrides(ecuData, writer); Output.outputGauges(ecuData, writer); Output.outputLoadConstants(ecuData, writer); Output.outputFlagsAndConstants(ecuData, writer); Output.outputGlobalVars(ecuData, writer); writer.println("\n}\n"); writer.close(); } /** * Get the finger print of a class * * @return The finger print as an MD5 */ private static String getFingerprint() { final StringBuffer b = new StringBuffer(); try { final MessageDigest md = MessageDigest.getInstance("MD5"); final byte[] array = md.digest(ecuData.getFingerprintSource().getBytes()); for (int i = 0; i < array.length; i++) { b.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); } } catch (final NoSuchAlgorithmException e) { e.printStackTrace(); } return b.toString(); } }