1 19 20 package soot.util.cfgcmd; 21 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.util.List ; 25 import java.util.LinkedList ; 26 import java.util.Map ; 27 import java.util.HashMap ; 28 import java.util.StringTokenizer ; 29 import java.util.Iterator ; 30 import java.lang.reflect.*; 31 import soot.Singletons; 32 import soot.G; 33 34 44 public class AltClassLoader extends ClassLoader { 45 46 private final static boolean DEBUG = false; 47 48 private String [] locations; private Map alreadyFound = new HashMap (); 54 private Map nameToMangledName = new HashMap (); 60 private Map mangledNameToName = new HashMap (); 64 65 66 73 public AltClassLoader(Singletons.Global g) {} 74 75 76 83 public static AltClassLoader v() { 84 return G.v().soot_util_cfgcmd_AltClassLoader(); 85 } 86 87 88 95 public void setAltClassPath(String altClassPath) { 96 List locationList = new LinkedList (); 97 for (StringTokenizer tokens = 98 new StringTokenizer (altClassPath, File.pathSeparator, false); 99 tokens.hasMoreTokens() ; ) { 100 String location = tokens.nextToken(); 101 locationList.add(location); 102 } 103 locations = new String [locationList.size()]; 104 locations = (String []) locationList.toArray(locations); 105 } 106 107 108 116 public void setAltClasses(String [] classNames) { 117 nameToMangledName.clear(); 118 for (int i = 0; i < classNames.length; i++) { 119 String origName = classNames[i]; 120 String mangledName = mangleName(origName); 121 nameToMangledName.put(origName, mangledName); 122 mangledNameToName.put(mangledName, origName); 123 } 124 } 125 126 142 private static String mangleName(String origName) 143 throws IllegalArgumentException { 144 final char dot = '.'; 145 final char dotReplacement = '_'; 146 StringBuffer mangledName = new StringBuffer (origName); 147 int replacements = 0; 148 int lastDot = origName.lastIndexOf(dot); 149 for (int nextDot = lastDot; 150 (nextDot = origName.lastIndexOf(dot, nextDot - 1)) >= 0; ) { 151 mangledName.setCharAt(nextDot, dotReplacement); 152 replacements++; 153 } 154 if (replacements <= 0) { 155 throw new IllegalArgumentException ("AltClassLoader.mangleName()'s crude classname mangling cannot deal with " + origName); 156 } 157 return mangledName.toString(); 158 } 159 160 161 180 protected Class findClass(String maybeMangledName) 181 throws ClassNotFoundException { 182 if (DEBUG) { 183 G.v().out.println("AltClassLoader.findClass(" + maybeMangledName + ')'); 184 } 185 186 Class result = (Class ) alreadyFound.get(maybeMangledName); 187 if (result != null) { 188 return result; 189 } 190 191 String name = (String ) mangledNameToName.get(maybeMangledName); 192 if (name == null) { 193 name = maybeMangledName; 194 } 195 String pathTail = "/" + name.replace('.', File.separatorChar) + ".class"; 196 197 for (int i = 0; i < locations.length; i++) { 198 String path = locations[i] + pathTail; 199 try { 200 FileInputStream stream = new FileInputStream (path); 201 byte[] classBytes = new byte[stream.available()]; 202 stream.read(classBytes); 203 replaceAltClassNames(classBytes); 204 result = defineClass(maybeMangledName, classBytes, 0, classBytes.length); 205 alreadyFound.put(maybeMangledName, result); 206 return result; 207 } catch (java.io.IOException e) { 208 } catch (ClassFormatError e) { 210 if (DEBUG) { 211 e.printStackTrace(G.v().out); 212 } 213 } 215 } 216 throw new ClassNotFoundException ("Unable to find class" + name + 217 " in alternate classpath"); 218 } 219 220 221 233 public Class loadClass(String name) 234 throws ClassNotFoundException { 235 if (DEBUG) { 236 G.v().out.println("AltClassLoader.loadClass(" + name + ")"); 237 } 238 239 String nameForParent = (String ) nameToMangledName.get(name); 240 if (nameForParent == null) { 241 nameForParent = name; 243 } 244 245 if (DEBUG) { 246 G.v().out.println("AltClassLoader.loadClass asking parent for " + 247 nameForParent); 248 } 249 return super.loadClass(nameForParent, false); 250 } 251 252 253 262 private void replaceAltClassNames(byte[] classBytes) { 263 for (Iterator it = nameToMangledName.entrySet().iterator(); 264 it.hasNext(); ) { 265 Map.Entry entry = (Map.Entry ) it.next(); 266 String origName = (String ) entry.getKey(); 267 origName = origName.replace('.', '/'); 268 String mangledName = (String ) entry.getValue(); 269 mangledName = mangledName.replace('.', '/'); 270 findAndReplace(classBytes, stringToUtf8Pattern(origName), 271 stringToUtf8Pattern(mangledName)); 272 findAndReplace(classBytes, stringToTypeStringPattern(origName), 273 stringToTypeStringPattern(mangledName)); 274 } 275 } 276 277 282 private static byte[] stringToUtf8Pattern(String s) { 283 byte[] origBytes = s.getBytes(); 284 int length = origBytes.length; 285 final byte CONSTANT_Utf8 = 1; 286 byte[] result = new byte[length + 3]; 287 result[0] = CONSTANT_Utf8; 288 result[1] = (byte) (length & 0xff00); 289 result[2] = (byte) (length & 0x00ff); 290 for (int i = 0; i < length; i++) { 291 result[i+3] = origBytes[i]; 292 } 293 return result; 294 } 295 296 300 private static byte[] stringToTypeStringPattern(String s) { 301 byte[] origBytes = s.getBytes(); 302 int length = origBytes.length; 303 byte[] result = new byte[length + 2]; 304 result[0] = (byte) 'L'; 305 for (int i = 0; i < length; i++) { 306 result[i+1] = origBytes[i]; 307 } 308 result[length+1] = (byte) ';'; 309 return result; 310 } 311 312 313 319 private static void findAndReplace(byte[] text, byte[] pattern, 320 byte[] replacement) 321 throws IllegalArgumentException { 322 int patternLength = pattern.length; 323 if (patternLength != replacement.length) { 324 throw new IllegalArgumentException ("findAndReplace(): The lengths of the pattern and replacement must match."); 325 } 326 int match = 0; 327 while ((match = findMatch(text, pattern, match)) >= 0) { 328 replace(text, replacement, match); 329 match += patternLength; 330 } 331 } 332 333 334 346 private static int findMatch(byte[] text, byte[] pattern, int start) { 347 int textLength = text.length; 348 int patternLength = pattern.length; 349 nextBase: 350 for (int base = start; base < textLength; base++) { 351 for (int t = base, p = 0; p < patternLength; t++, p++) { 352 if (text[t] != pattern[p]) { 353 continue nextBase; 354 } 355 } 356 return base; 357 } 358 return -1; 359 } 360 361 367 private static void replace(byte[] text, byte[] replacement, int start) { 368 for (int t=start, p = 0; p < replacement.length; t++, p++) { 369 text[t] = replacement[p]; 370 } 371 } 372 373 378 public static void main(String [] argv) throws ClassNotFoundException { 379 AltClassLoader.v().setAltClassPath(argv[0]); 380 for (int i = 1; i < argv.length; i++) { 381 AltClassLoader.v().setAltClasses(new String [] { 382 argv[i] 383 }); 384 G.v().out.println("main() loadClass(" + argv[i] + ")"); 385 AltClassLoader.v().loadClass(argv[i]); 386 } 387 } 388 389 } 390 | Popular Tags |