package modmanager.utility; import modmanager.business.modactions.ActionEditFileFindAll; import modmanager.business.ManagerOptions; import modmanager.business.Mod; import modmanager.business.ModList; import modmanager.utility.xml.ShirkitDriver; import modmanager.business.statistics.Statistics; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.StreamException; import com.thoughtworks.xstream.mapper.CannotResolveClassException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import modmanager.business.modactions.Action; import modmanager.business.modactions.ActionApplyAfter; import modmanager.business.modactions.ActionApplyBefore; import modmanager.business.modactions.ActionCopyFile; import modmanager.business.modactions.ActionEditFile; import modmanager.business.modactions.ActionEditFileDelete; import modmanager.business.modactions.ActionEditFileFind; import modmanager.business.modactions.ActionEditFileFindUp; import modmanager.business.modactions.ActionEditFileInsert; import modmanager.business.modactions.ActionEditFileReplace; import modmanager.business.modactions.ActionIncompatibility; import modmanager.business.modactions.ActionRequirement; /** * * @author Shirkit */ public class XML { public static ShirkitDriver getDriver() { return new ShirkitDriver("UTF-8"); } public static ShirkitDriver getAlternativeDriver() { return new ShirkitDriver("UTF-16"); } /** * Save the XML in the passed parameter of the passed Mod. * @param what Mod to be saved. * @param where path to the File that the Mod's content will be saved. * @throws FileNotFoundException if the passed param 'where' was not found. * @throws UnsupportedEncodingException * @throws IOException random I/O exception. */ public static void modToXml(Mod what, File where) throws FileNotFoundException, UnsupportedEncodingException, IOException { XStream xstream = new XStream(getDriver()); updateAlias(xstream); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Writer writer = new OutputStreamWriter(outputStream, "UTF-8"); xstream.toXML(what, writer); String temp = outputStream.toString("UTF-8"); temp = replaceInvalidHtmlChars(temp); temp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + temp; FileOutputStream fos = new FileOutputStream(where); fos.write(temp.getBytes("UTF-8")); } public static String replaceInvalidHtmlChars(String input) { // this part is to solve the HTML characters printing bug. I didn't found out any other ways to do it String temp = input; temp = temp.replaceAll("<", "<"); temp = temp.replaceAll(">", ">"); temp = temp.replaceAll(""", "\""); temp = temp.replaceAll("'", "\'"); temp = temp.replaceAll("&", "\'"); return temp; } private static Mod removeRequiredMods(Mod m) { Iterator<Action> actions = m.getActions().iterator(); ActionRequirement movableframe = null; ActionRequirement modoptionsframework = null; while (actions.hasNext()) { Action action = actions.next(); if (action.getClass().equals(ActionRequirement.class)) { ActionRequirement require = (ActionRequirement) action; if (require.getName().contains("Mod Options Framework")) { movableframe = require; } else if (require.getName().contains("Movable Frames")) { modoptionsframework = require; } } } if (modoptionsframework != null) { m.getActions().remove(modoptionsframework); } if (movableframe != null) { m.getActions().remove(movableframe); } return m; } /** * Loads the content of a XML file into a Mod. * @param is - InputStream to be read. * @return the Mod with all fields already filled up. */ private static Mod xmlToMod(InputStream is, ShirkitDriver driver) throws StreamException { XStream xstream = new XStream(driver); updateAlias(xstream); Mod m = (Mod) xstream.fromXML(is); return removeRequiredMods(m); } /** * Loads the content of a XML String into a Mod. This method should be called to read Strings that contains a file already read in it. * @param fileString to be read. * @return the Mod with all fields already filled up. */ public static Mod xmlToMod(String fileString) throws StreamException { InputStream is = null; try { is = new ByteArrayInputStream(fileString.getBytes("UTF-8")); } catch (UnsupportedEncodingException ex) { } Mod m = null; try { // UTF-8 m = xmlToMod(is, getDriver()); } catch (StreamException e1) { try { // UTF-16 m = xmlToMod(is, getAlternativeDriver()); } catch (StreamException e2) { try { // Remove the BOM is = new ByteArrayInputStream(fileString.substring(1).getBytes("UTF-8")); try { // UTF-8 m = xmlToMod(is, getDriver()); } catch (StreamException e3) { // UTF-16 m = xmlToMod(is, getAlternativeDriver()); } } catch (UnsupportedEncodingException ex) { } } } return m; } /** * Loads the content of a XML file into the ManagerOptions. * @param file to be read. * @return the Mod with all fields already filled up. * @throws FileNotFoundException */ public static ManagerOptions xmlToManagerOptions(File path) throws FileNotFoundException { XStream xstream = new XStream(getDriver()); xstream = updateAlias(xstream); Set<Mod> applied = new HashSet<Mod>(); try { ObjectInputStream in = xstream.createObjectInputStream(new FileInputStream(path)); while (true) { try { Object o = in.readObject(); if (o.getClass().equals(Mod.class)) { applied.add((Mod) o); } } catch (CannotResolveClassException e) { } catch (ClassNotFoundException e) { } } } catch (IOException ex) { // Logger.getLogger(XML.class.getName()).log(Level.SEVERE, null, ex); } ManagerOptions temp = (ManagerOptions) xstream.fromXML(new FileInputStream(path)); temp.setAppliedMods(applied); return temp; } /** * Save the XML in the passed parameter of the ManagerOptions. * @param where path to the File that the ManagerOptions's content will be saved. * @throws FileNotFoundException if the passed param 'where' was not found. * @throws IOException random I/O exception. */ public static void managerOptionsToXml(File where) throws IOException { XStream xstream = new XStream(getDriver()); updateAlias(xstream); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Writer writer = new OutputStreamWriter(outputStream, "UTF-8"); xstream.toXML(ManagerOptions.getInstance(), writer); String temp = outputStream.toString("UTF-8"); temp = replaceInvalidHtmlChars(temp); temp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + temp; FileOutputStream fos = new FileOutputStream(where, false); fos.write(temp.getBytes("UTF-8")); fos.flush(); fos.close(); } public static void statsToXml(Statistics stats, File where) throws IOException { XStream xstream = new XStream(getDriver()); updateAlias(xstream); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Writer writer = new OutputStreamWriter(outputStream, "UTF-8"); xstream.toXML(stats, writer); String temp = outputStream.toString("UTF-8"); temp = replaceInvalidHtmlChars(temp); temp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + temp; FileOutputStream fos = new FileOutputStream(where, false); fos.write(temp.getBytes("UTF-8")); fos.flush(); fos.close(); } public static void modListToXml(File destination, ModList modlist) throws IOException { XStream xstream = new XStream(getDriver()); updateAlias(xstream); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Writer writer = new OutputStreamWriter(outputStream, "UTF-8"); xstream.toXML(modlist, writer); String temp = outputStream.toString("UTF-8"); temp = replaceInvalidHtmlChars(temp); temp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + temp; FileOutputStream fos = new FileOutputStream(destination, false); fos.write(temp.getBytes("UTF-8")); fos.flush(); fos.close(); } public static ModList xmlToModList(byte[] byteFile) throws FileNotFoundException { XStream xstream = new XStream(getDriver()); xstream = updateAlias(xstream); return (ModList) xstream.fromXML(new ByteArrayInputStream(byteFile)); } public static ModList xmlToModList(File file) throws FileNotFoundException { XStream xstream = new XStream(getDriver()); xstream = updateAlias(xstream); return (ModList) xstream.fromXML(new FileInputStream(file)); } /** * This method is to help the XStream to find all the alias in the Classes and to input the synoms of the operations. * @param xstream * @return */ public static XStream updateAlias(XStream xstream) { xstream.processAnnotations(Mod.class); xstream.processAnnotations(Action.class); xstream.processAnnotations(ActionApplyAfter.class); xstream.processAnnotations(ActionApplyBefore.class); xstream.processAnnotations(ActionCopyFile.class); xstream.processAnnotations(ActionEditFile.class); xstream.processAnnotations(ActionEditFileDelete.class); xstream.processAnnotations(ActionEditFileFind.class); xstream.processAnnotations(ActionEditFileFindAll.class); xstream.processAnnotations(ActionEditFileFindUp.class); xstream.processAnnotations(ActionEditFileInsert.class); xstream.processAnnotations(ActionEditFileReplace.class); xstream.processAnnotations(ActionIncompatibility.class); xstream.processAnnotations(ActionRequirement.class); xstream.processAnnotations(ManagerOptions.class); xstream.processAnnotations(ModList.class); xstream.processAnnotations(Statistics.class); xstream.aliasField("find", ActionEditFileFind.class, "seek"); xstream.aliasField("find", ActionEditFileFind.class, "search"); xstream.aliasField("findup", ActionEditFileFind.class, "seekup"); xstream.aliasField("findup", ActionEditFileFind.class, "searchup"); xstream.aliasField("insert", ActionEditFileFind.class, "add"); return xstream; } }