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