/* * Copyright (C) 2007, 2008 IsmAvatar <IsmAvatar@gmail.com> * Copyright (C) 2006, 2007 Clam <clamisgood@gmail.com> * * This file is part of LateralGM. * LateralGM is free software and comes with ABSOLUTELY NO WARRANTY. * See LICENSE for details. */ package org.lateralgm.resources.library; import static org.lateralgm.file.GmStreamDecoder.mask; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.Map; import java.util.TreeMap; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.imageio.ImageIO; import org.lateralgm.file.GmStreamDecoder; import org.lateralgm.main.LGM; import org.lateralgm.main.Prefs; import org.lateralgm.main.Util; import org.lateralgm.messages.Messages; import org.lateralgm.resources.sub.Action; import org.lateralgm.resources.sub.Argument; public final class LibManager { private LibManager() { } public static ArrayList<Library> libs = new ArrayList<Library>(); public static LibAction codeAction; public static LibAction getLibAction(int libraryId, int libActionId) { for (Library l : libs) { if (l.id == libraryId) { LibAction act = l.getLibAction(libActionId); if (act != null) return act; } } return null; } /** * This is the usual LibManager "entry point". * Loads in all libs/lgls in locations specified by preferences. */ public static void autoLoad() { // We can't do this became EGM has no reflection capabilities in this regard. //if (!Prefs.enableDragAndDrop) { //codeAction = makeCodeAction(); //return; //} File dir = new File(Prefs.actionLibraryPath); if (!dir.exists()) { if (LGM.workDir == null) return; dir = new File(LGM.workDir,Prefs.actionLibraryPath); if (!dir.exists()) dir = LGM.workDir; } codeAction = null; autoLoad(dir); File userLibF = new File(Prefs.userLibraryPath); if (userLibF.exists()) autoLoad(userLibF); if (codeAction == null) { codeAction = makeCodeAction(); } } /** Loads in all libs/lgls in a given location (directory or zip file) */ public static void autoLoad(File loc) { Map<String,InputStream> map = getLibs(loc); if (map != null) loadLibMap(map,loc); } /** * Retrieves all libs/lgls in a given location (directory or zip file). * The files are stored in order and already opened for convenience. */ public static TreeMap<String,InputStream> getLibs(File loc) { if (loc.exists()) { try { if (loc.isDirectory()) return getDirLibs(loc); if (!passFilter(loc.getName())) return getZipLibs(new ZipFile(loc)); //loc is a lib/lgl already... TreeMap<String,InputStream> map = new TreeMap<String,InputStream>(); map.put(loc.getName(),new FileInputStream(loc)); return map; } catch (IOException e) { e.printStackTrace(); } } return null; } public static TreeMap<String,InputStream> getZipLibs(ZipFile zip) throws IOException { TreeMap<String,InputStream> map = new TreeMap<String,InputStream>(); Enumeration<? extends ZipEntry> entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry ent = entries.nextElement(); String en = ent.getName(); if (passFilter(en)) map.put(en.substring(en.lastIndexOf('/') + 1),zip.getInputStream(ent)); } return map; } public static TreeMap<String,InputStream> getDirLibs(File dir) throws IOException { TreeMap<String,InputStream> map = new TreeMap<String,InputStream>(); File[] fl = dir.listFiles(); for (File f : fl) { String en = f.getName(); if (passFilter(en)) map.put(en,new FileInputStream(f)); } return map; } public static final String[] EXTS = { ".lib",".lgl" }; //$NON-NLS-1$ //$NON-NLS-2$ private static boolean passFilter(String fn) { for (String ext : EXTS) if (fn.endsWith(ext)) return true; return false; } public static void loadLibMap(Map<String,InputStream> libs, File path) { ArrayList<String> exceptions = new ArrayList<String>(); if (libs.size() > 0) System.out.println(Messages.format("LibManager.LOADINGN",path.getPath())); StringBuilder buffer = new StringBuilder(); for (Map.Entry<String,InputStream> ent : libs.entrySet()) { String fn = ent.getKey(); try { loadFile(new GmStreamDecoder(ent.getValue()),fn); //print out filename if (buffer.length() + fn.length() > 60) { System.out.println(buffer); buffer.delete(0,buffer.length() - 1); } buffer.append(fn).append(' '); } catch (LibFormatException ex) { exceptions.add(fn + ": " + ex.getMessage()); } } System.out.println(buffer); for (String s : exceptions) System.out.println(s); } /** * Loads a library file of given fileName of either LIB or LGL format * @param filename * @return the library * @throws LibFormatException */ public static Library loadFile(String filename) throws LibFormatException { try { return loadFile(new GmStreamDecoder(filename),filename); } catch (FileNotFoundException e) { throw new LibFormatException(Messages.format("LibManager.ERROR_NOTFOUND",filename)); } } /** * Loads a library file of given fileName of either LIB or LGL format * @param in * @param filename for error reporting * @return the library * @throws LibFormatException */ public static Library loadFile(GmStreamDecoder in, String filename) throws LibFormatException { Library lib = null; try { int header = in.read3(); if (header == (('L' << 16) | ('G' << 8) | 'L')) lib = loadLgl(in); else if (header == 500 || header == 520) lib = loadLib(in); else throw new LibFormatException(Messages.format("LibManager.ERROR_INVALIDFILE",filename)); libs.add(lib); } catch (IOException ex) { throw new LibFormatException(Messages.format("LibManager.ERROR_READING",filename, //$NON-NLS-1$ ex.getMessage())); } catch (LibFormatException ex) { throw new LibFormatException(String.format(ex.getMessage(),filename)); } finally { try { if (in != null) in.close(); } catch (IOException ex) { String msg = Messages.getString("LibManager.ERROR_CLOSEFAILED"); //$NON-NLS-1$ throw new LibFormatException(msg); } } return lib; } /** * Workhorse for constructing a library out of given StreamDecoder of LIB format * @param in * @return the library (not yet added to the libs list) * @throws LibFormatException * @throws IOException */ public static Library loadLib(GmStreamDecoder in) throws LibFormatException,IOException { if (in.read() != 0) throw new LibFormatException(Messages.format("LibManager.ERROR_INVALIDFILE","%s")); Library lib = new Library(); lib.tabCaption = in.readStr(); lib.id = in.read4(); in.skip(in.read4()); in.skip(4); in.skip(8); in.skip(in.read4()); in.skip(in.read4()); lib.advanced = in.readBool(); in.skip(4); // no of actions/official lib identifier thingy int acts = in.read4(); for (int j = 0; j < acts; j++) { int ver = in.read4(); if (ver != 500 && ver != 520) { throw new LibFormatException(Messages.format("LibManager.ERROR_INVALIDACTION",j,"%s",ver)); } LibAction act = lib.addLibAction(); act.parent = lib; act.name = in.readStr(); act.id = in.read4(); byte[] data = new byte[in.read4()]; in.read(data); act.actImage = Util.getTransparentImage( ImageIO.read(new ByteArrayInputStream(data))).getSubimage(0,0,24,24); act.hidden = in.readBool(); act.advanced = in.readBool(); if (ver == 520) act.registeredOnly = in.readBool(); act.description = in.readStr(); act.listText = in.readStr(); act.hintText = in.readStr(); act.actionKind = (byte) in.read4(); act.interfaceKind = (byte) in.read4(); act.question = in.readBool(); act.canApplyTo = in.readBool(); act.allowRelative = in.readBool(); act.libArguments = new LibArgument[in.read4()]; int args = in.read4(); for (int k = 0; k < args; k++) { if (k < act.libArguments.length) { LibArgument arg = new LibArgument(); arg.caption = in.readStr(); arg.kind = (byte) in.read4(); arg.defaultVal = in.readStr(); arg.menu = in.readStr(); act.libArguments[k] = arg; } else { in.skip(in.read4()); in.skip(4); in.skip(in.read4()); in.skip(in.read4()); } } act.execType = (byte) in.read4(); if (act.execType == Action.EXEC_FUNCTION) act.execInfo = in.readStr(); else in.skip(in.read4()); if (act.execType == Action.EXEC_CODE) act.execInfo = in.readStr(); else in.skip(in.read4()); } return lib; } /** * Workhorse for constructing a library out of given StreamDecoder of LGL format * @param in * @return the library (not yet added to the libs list) * @throws LibFormatException * @throws IOException */ public static Library loadLgl(GmStreamDecoder in) throws LibFormatException,IOException { if (in.read2() != 160) { String invalidFile = Messages.getString("LibManager.ERROR_INVALIDFILE"); //$NON-NLS-1$ throw new LibFormatException(invalidFile); } Library lib = new Library(); lib.id = in.read3(); lib.tabCaption = in.readStr1(); in.skip(in.read()); in.skip(4); in.skip(8); in.skip(in.read4()); in.skip(in.read4()); int acts = in.read(); lib.advanced = mask(acts,128); acts &= 127; for (int j = 0; j < acts; j++) { if (in.read2() != 160) throw new LibFormatException(Messages.format("LibManager.ERROR_INVALIDACTION",j,"%s",160)); LibAction act = lib.addLibAction(); act.parent = lib; act.id = in.read2(); act.name = in.readStr1(); act.description = in.readStr1(); act.listText = in.readStr1(); act.hintText = in.readStr1(); int tags = in.read(); act.hidden = mask(tags,128); act.advanced = mask(tags,64); act.registeredOnly = mask(tags,32); act.question = mask(tags,16); act.canApplyTo = mask(tags,8); act.allowRelative = mask(tags,4); act.execType = (byte) (tags & 3); act.execInfo = in.readStr(); tags = in.read(); act.actionKind = (byte) (tags >> 4); act.interfaceKind = (byte) (tags & 15); act.libArguments = new LibArgument[in.read()]; for (int k = 0; k < act.libArguments.length; k++) { LibArgument arg = new LibArgument(); arg.caption = in.readStr1(); arg.kind = (byte) in.read(); arg.defaultVal = in.readStr1(); arg.menu = in.readStr1(); act.libArguments[k] = arg; } if (act.actionKind == Action.ACT_CODE && act.execType == Action.EXEC_CODE && act.interfaceKind == LibAction.INTERFACE_CODE) codeAction = act; } BufferedImage icons = ImageIO.read(in.getInputStream()); int i = 0; int cc = icons.getWidth() / 24; for (LibAction a : lib.libActions) { if (a.actionKind < 8) { a.actImage = icons.getSubimage(24 * (i % cc),24 * (i / cc),24,24); i++; } } return lib; } private static LibAction makeCodeAction() { LibAction act = new LibAction(); act.name = "Code"; act.description = "Execute a piece of code"; act.listText = "Execute a piece of code"; act.hintText = "Execute code:##@0"; act.canApplyTo = true; act.execType = Action.EXEC_CODE; act.actionKind = Action.ACT_CODE; act.interfaceKind = LibAction.INTERFACE_CODE; act.libArguments = new LibArgument[1]; act.libArguments[0] = new LibArgument(); act.libArguments[0].kind = Argument.ARG_STRING; return act; } }