/* * $Id$ * * Copyright (c) 2008 by Brent Easton and Joel Uckelman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License (LGPL) as published by the Free Software Foundation. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, copies are available * at http://www.opensource.org. */ package VASSAL.build.module.metadata; import java.io.BufferedInputStream; import java.io.IOException; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import VASSAL.build.GameModule; import VASSAL.tools.io.IOUtils; /** * * Class representing the metadata for a Module or an Extension. Modules * and extensions can't be differentiated until either the metadata or the * buildfile is parsed, so they share the same metadata structure. * * @author Brent Easton * @since 3.1.0 * */ public class ModuleMetaData extends AbstractMetaData { private static final Logger logger = LoggerFactory.getLogger(ModuleMetaData.class); public static final String ZIP_ENTRY_NAME = "moduledata"; public static final String DATA_VERSION = "1"; protected Attribute nameAttr; public ModuleMetaData(ZipFile zip) { read(zip); } public ModuleMetaData(GameModule module) { super(); nameAttr = new Attribute(module, GameModule.MODULE_NAME); setDescription(new Attribute(module, GameModule.DESCRIPTION)); setVersion(module.getGameVersion()); } public ModuleMetaData(String name, String version) { super(); nameAttr = new Attribute(GameModule.MODULE_NAME, name); setVersion(version); } public String getName() { return nameAttr == null ? "" : nameAttr.getValue(); } public String getLocalizedName() { return nameAttr == null ? "" : nameAttr.getLocalizedValue(); } public String getZipEntryName() { return ZIP_ENTRY_NAME; } public String getMetaDataVersion() { return DATA_VERSION; } /** * Add elements specific to a ModuleMetaData * * @param doc Document * @param root Root element */ protected void addElements(Document doc, Element root) { nameAttr.generateXML(doc, root, NAME_ELEMENT); } /** * Read and validate a Module file. * - Check it has a Zip Entry named buildfile * - If it has a metadata file, read and parse it. * * @param file Module File */ public void read(ZipFile zip) { version = ""; try { // Try to parse the metadata. Failure is not catastrophic, we can // treat it like an old-style module with no metadata and parse // the first lines of the buildFile DefaultHandler handler = null; ZipEntry data = zip.getEntry(ZIP_ENTRY_NAME); if (data == null) { data = zip.getEntry(GameModule.BUILDFILE); if (data == null) return; handler = new ModuleBuildFileXMLHandler(); } else { handler = new MetadataXMLHandler(); } BufferedInputStream in = null; try { in = new BufferedInputStream(zip.getInputStream(data)); synchronized (parser) { parser.setContentHandler(handler); parser.setDTDHandler(handler); parser.setEntityResolver(handler); parser.setErrorHandler(handler); parser.parse(new InputSource(in)); } in.close(); } finally { IOUtils.closeQuietly(in); } zip.close(); } catch (IOException e) { logger.error("", e); } catch (SAXEndException e) { // Indicates End of module/extension parsing. not an error. } catch (SAXException e) { logger.error("", e); } finally { IOUtils.closeQuietly(zip); } } /** * XML Handler for parsing a Module/Extension metadata file */ private class MetadataXMLHandler extends XMLHandler { @Override public void endElement(String uri, String localName, String qName) { // handle all of the elements which have CDATA here if (NAME_ELEMENT.equals(qName)) { if (nameAttr == null) { nameAttr = new Attribute(NAME_ELEMENT, accumulator.toString().trim()); } else { nameAttr.addTranslation(language, accumulator.toString().trim()); } } else { super.endElement(uri, localName, qName); } } } /** * XML Handle for parsing a Module buildFile. Used to read minimal data from * modules saved prior to 3.1.0. */ private class ModuleBuildFileXMLHandler extends BuildFileXMLHandler { @Override public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXEndException { super.startElement(uri, localName, qName, attrs); // handle element attributes we care about if (BUILDFILE_MODULE_ELEMENT1.equals(qName) || BUILDFILE_MODULE_ELEMENT2.equals(qName)) { nameAttr = new Attribute (NAME_ELEMENT, getAttr(attrs, NAME_ATTR)); setVersion(getAttr(attrs, VERSION_ATTR)); setVassalVersion(getAttr(attrs, VASSAL_VERSION_ATTR)); setDescription(getAttr(attrs, DESCRIPTION_ATTR)); throw new SAXEndException(); } } } }