001/*
002 * Forge Mod Loader
003 * Copyright (c) 2012-2013 cpw.
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser Public License v2.1
006 * which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
008 * 
009 * Contributors:
010 *     cpw - implementation
011 */
012
013package cpw.mods.fml.common.discovery;
014
015import java.util.Collections;
016import java.util.List;
017import java.util.logging.Level;
018import java.util.regex.Matcher;
019import java.util.zip.ZipEntry;
020import java.util.zip.ZipFile;
021
022import com.google.common.collect.Lists;
023
024import cpw.mods.fml.common.FMLLog;
025import cpw.mods.fml.common.LoaderException;
026import cpw.mods.fml.common.MetadataCollection;
027import cpw.mods.fml.common.ModContainer;
028import cpw.mods.fml.common.ModContainerFactory;
029import cpw.mods.fml.common.discovery.asm.ASMModParser;
030
031public class JarDiscoverer implements ITypeDiscoverer
032{
033    @Override
034    public List<ModContainer> discover(ModCandidate candidate, ASMDataTable table)
035    {
036        List<ModContainer> foundMods = Lists.newArrayList();
037        FMLLog.fine("Examining file %s for potential mods", candidate.getModContainer().getName());
038        ZipFile jar = null;
039        try
040        {
041            jar = new ZipFile(candidate.getModContainer());
042
043            ZipEntry modInfo = jar.getEntry("mcmod.info");
044            MetadataCollection mc = null;
045            if (modInfo != null)
046            {
047                FMLLog.finer("Located mcmod.info file in file %s", candidate.getModContainer().getName());
048                mc = MetadataCollection.from(jar.getInputStream(modInfo), candidate.getModContainer().getName());
049            }
050            else
051            {
052                FMLLog.fine("The mod container %s appears to be missing an mcmod.info file", candidate.getModContainer().getName());
053                mc = MetadataCollection.from(null, "");
054            }
055            for (ZipEntry ze : Collections.list(jar.entries()))
056            {
057                if (ze.getName()!=null && ze.getName().startsWith("__MACOSX"))
058                {
059                    continue;
060                }
061                Matcher match = classFile.matcher(ze.getName());
062                if (match.matches())
063                {
064                    ASMModParser modParser;
065                    try
066                    {
067                        modParser = new ASMModParser(jar.getInputStream(ze));
068                    }
069                    catch (LoaderException e)
070                    {
071                        FMLLog.log(Level.SEVERE, e, "There was a problem reading the entry %s in the jar %s - probably a corrupt zip", ze.getName(), candidate.getModContainer().getPath());
072                        jar.close();
073                        throw e;
074                    }
075                    modParser.validate();
076                    modParser.sendToTable(table, candidate);
077                    ModContainer container = ModContainerFactory.instance().build(modParser, candidate.getModContainer(), candidate);
078                    if (container!=null)
079                    {
080                        table.addContainer(container);
081                        foundMods.add(container);
082                        container.bindMetadata(mc);
083                    }
084                }
085            }
086        }
087        catch (Exception e)
088        {
089            FMLLog.log(Level.WARNING, e, "Zip file %s failed to read properly, it will be ignored", candidate.getModContainer().getName());
090        }
091        finally
092        {
093            if (jar != null)
094            {
095                try
096                {
097                    jar.close();
098                }
099                catch (Exception e)
100                {
101                }
102            }
103        }
104        return foundMods;
105    }
106
107}