001    package cpw.mods.fml.common.discovery;
002    
003    import java.io.File;
004    import java.io.FileFilter;
005    import java.io.FileInputStream;
006    import java.util.Arrays;
007    import java.util.List;
008    import java.util.logging.Level;
009    import java.util.regex.Matcher;
010    
011    import com.google.common.base.Throwables;
012    import com.google.common.collect.Lists;
013    
014    import cpw.mods.fml.common.FMLLog;
015    import cpw.mods.fml.common.LoaderException;
016    import cpw.mods.fml.common.MetadataCollection;
017    import cpw.mods.fml.common.ModContainer;
018    import cpw.mods.fml.common.ModContainerFactory;
019    import cpw.mods.fml.common.discovery.asm.ASMModParser;
020    
021    public class DirectoryDiscoverer implements ITypeDiscoverer
022    {
023        private class ClassFilter implements FileFilter
024        {
025            @Override
026            public boolean accept(File file)
027            {
028                return (file.isFile() && classFile.matcher(file.getName()).find()) || file.isDirectory();
029            }
030        }
031    
032        private ASMDataTable table;
033    
034        @Override
035        public List<ModContainer> discover(ModCandidate candidate, ASMDataTable table)
036        {
037            this.table = table;
038            List<ModContainer> found = Lists.newArrayList();
039            FMLLog.fine("Examining directory %s for potential mods", candidate.getModContainer().getName());
040            exploreFileSystem("", candidate.getModContainer(), found, candidate, null);
041            for (ModContainer mc : found)
042            {
043                table.addContainer(mc);
044            }
045            return found;
046        }
047    
048        public void exploreFileSystem(String path, File modDir, List<ModContainer> harvestedMods, ModCandidate candidate, MetadataCollection mc)
049        {
050            if (path.length() == 0)
051            {
052                File metadata = new File(modDir, "mcmod.info");
053                try
054                {
055                    FileInputStream fis = new FileInputStream(metadata);
056                    mc = MetadataCollection.from(fis,modDir.getName());
057                    fis.close();
058                    FMLLog.fine("Found an mcmod.info file in directory %s", modDir.getName());
059                }
060                catch (Exception e)
061                {
062                    mc = MetadataCollection.from(null,"");
063                    FMLLog.fine("No mcmod.info file found in directory %s", modDir.getName());
064                }
065            }
066    
067            File[] content = modDir.listFiles(new ClassFilter());
068    
069            // Always sort our content
070            Arrays.sort(content);
071            for (File file : content)
072            {
073                if (file.isDirectory())
074                {
075                    FMLLog.finest("Recursing into package %s", path + file.getName());
076                    exploreFileSystem(path + file.getName() + ".", file, harvestedMods, candidate, mc);
077                    continue;
078                }
079                Matcher match = classFile.matcher(file.getName());
080    
081                if (match.matches())
082                {
083                    ASMModParser modParser = null;
084                    try
085                    {
086                        FileInputStream fis = new FileInputStream(file);
087                        modParser = new ASMModParser(fis);
088                        fis.close();
089                    }
090                    catch (LoaderException e)
091                    {
092                        FMLLog.log(Level.SEVERE, e, "There was a problem reading the file %s - probably this is a corrupt file", file.getPath());
093                        throw e;
094                    }
095                    catch (Exception e)
096                    {
097                        Throwables.propagate(e);
098                    }
099    
100                    modParser.validate();
101                    modParser.sendToTable(table, candidate);
102                    ModContainer container = ModContainerFactory.instance().build(modParser, candidate.getModContainer(), candidate);
103                    if (container!=null)
104                    {
105                        harvestedMods.add(container);
106                        container.bindMetadata(mc);
107                    }
108                }
109    
110    
111            }
112        }
113    
114    }