package net.vhati.modmanager.xml; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.io.StringReader; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import net.vhati.modmanager.core.ModDB; import net.vhati.modmanager.core.ModInfo; import net.vhati.modmanager.core.ModUtilities; import net.vhati.modmanager.core.ModUtilities.DecodeResult; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class JDOMModMetadataReader { private static final Logger log = LogManager.getLogger(JDOMModMetadataReader.class); public static final String METADATA_INNERPATH = "mod-appendix/metadata.xml"; /** * Reads metadata.xml from a mod file and returns a ModInfo object. * * @return the read metadata, a blank ModInfo, or null if an error occurred */ public static ModInfo parseModFile( File modFile ) { ModInfo modInfo = null; InputStream fis = null; ZipInputStream zis = null; Exception exception = null; try { fis = new FileInputStream( modFile ); zis = new ZipInputStream( new BufferedInputStream( fis ) ); ZipEntry item; while ( (item = zis.getNextEntry()) != null ) { if ( item.isDirectory() ) { zis.closeEntry(); continue; } String innerPath = item.getName(); innerPath = innerPath.replace( '\\', '/' ); // Non-standard zips. if ( innerPath.equals( METADATA_INNERPATH ) ) { String metadataText = ModUtilities.decodeText( zis, modFile.getName()+":"+METADATA_INNERPATH ).text; modInfo = parse( metadataText ); zis.closeEntry(); break; } zis.closeEntry(); } } catch ( JDOMException e ) { exception = e; } catch ( IOException e ) { exception = e; } finally { try {if ( zis != null ) zis.close();} catch ( IOException e ) {} try {if ( fis != null ) fis.close();} catch ( IOException e ) {} } if ( exception != null ) { log.error( String.format( "While processing \"%s:%s\", strict parsing failed: %s", modFile.getName(), METADATA_INNERPATH, exception.getMessage() ), exception ); return null; } if ( modInfo == null ) modInfo = new ModInfo(); return modInfo; } /** * Reads a mod's metadata.xml and returns a ModInfo object. */ public static ModInfo parse( String metadataText ) throws IOException, JDOMException { ModInfo modInfo = new ModInfo(); SAXBuilder strictParser = new SAXBuilder(); Document doc = strictParser.build( new StringReader( metadataText ) ); Element root = doc.getRootElement(); String modTitle = root.getChildTextTrim( "title" ); if ( modTitle != null && modTitle.length() > 0 ) modInfo.setTitle( modTitle ); else throw new JDOMException( "Missing title." ); String modURL = root.getChildTextTrim( "threadUrl" ); if ( modURL != null && modURL.length() > 0 ) modInfo.setURL( modURL ); else throw new JDOMException( "Missing threadUrl." ); String modAuthor = root.getChildTextTrim( "author" ); if ( modAuthor != null && modAuthor.length() > 0 ) modInfo.setAuthor( modAuthor ); else throw new JDOMException( "Missing author." ); String modVersion = root.getChildTextTrim( "version" ); if ( modVersion != null && modVersion.length() > 0 ) modInfo.setVersion( modVersion ); else throw new JDOMException( "Missing version." ); String modDesc = root.getChildTextTrim( "description" ); if ( modDesc != null && modDesc.length() > 0 ) modInfo.setDescription( modDesc ); else throw new JDOMException( "Missing description." ); return modInfo; } }