• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.tonicsystems.jarjar;
18 
19 import com.tonicsystems.jarjar.util.*;
20 import java.io.*;
21 import java.util.*;
22 import org.objectweb.asm.*;
23 import org.objectweb.asm.Type;
24 import org.objectweb.asm.commons.*;
25 
26 // TODO: this can probably be refactored into JarClassVisitor, etc.
27 class KeepProcessor extends Remapper implements JarProcessor
28 {
29     private final ClassVisitor cv = new RemappingClassAdapter(new EmptyClassVisitor(), this);
30     private final List<Wildcard> wildcards;
31     private final List<String> roots = new ArrayList<String>();
32     private final Map<String, Set<String>> depend = new HashMap<String, Set<String>>();
33 
KeepProcessor(List<Keep> patterns)34     public KeepProcessor(List<Keep> patterns) {
35         wildcards = PatternElement.createWildcards(patterns);
36     }
37 
isEnabled()38     public boolean isEnabled() {
39         return !wildcards.isEmpty();
40     }
41 
getExcludes()42     public Set<String> getExcludes() {
43         Set<String> closure = new HashSet<String>();
44         closureHelper(closure, roots);
45         Set<String> removable = new HashSet<String>(depend.keySet());
46         removable.removeAll(closure);
47         return removable;
48     }
49 
closureHelper(Set<String> closure, Collection<String> process)50     private void closureHelper(Set<String> closure, Collection<String> process) {
51         if (process == null)
52             return;
53         for (String name : process) {
54             if (closure.add(name))
55                 closureHelper(closure, depend.get(name));
56         }
57     }
58 
59     private Set<String> curSet;
60     private byte[] buf = new byte[0x2000];
61 
process(EntryStruct struct)62     public boolean process(EntryStruct struct) throws IOException {
63         try {
64             if (struct.name.endsWith(".class")) {
65                 String name = struct.name.substring(0, struct.name.length() - 6);
66                 for (Wildcard wildcard : wildcards)
67                     if (wildcard.matches(name))
68                         roots.add(name);
69                 depend.put(name, curSet = new HashSet<String>());
70                 new ClassReader(new ByteArrayInputStream(struct.data)).accept(cv,
71                     ClassReader.EXPAND_FRAMES);
72                 curSet.remove(name);
73             }
74         } catch (Exception e) {
75           System.err.println("Error reading " + struct.name + ": " + e.getMessage());
76         }
77         return true;
78     }
79 
map(String key)80     public String map(String key) {
81         if (key.startsWith("java/") || key.startsWith("javax/"))
82             return null;
83         curSet.add(key);
84         return null;
85     }
86 
mapValue(Object value)87     public Object mapValue(Object value) {
88         if (value instanceof String) {
89             String s = (String)value;
90             if (PackageRemapper.isArrayForName(s)) {
91                 mapDesc(s.replace('.', '/'));
92             } else if (isForName(s)) {
93                 map(s.replace('.', '/'));
94             }
95             return value;
96         } else {
97             return super.mapValue(value);
98         }
99     }
100 
101     // TODO: use this for package remapping too?
isForName(String value)102     private static boolean isForName(String value) {
103         if (value.equals(""))
104             return false;
105         for (int i = 0, len = value.length(); i < len; i++) {
106             char c = value.charAt(i);
107             if (c != '.' && !Character.isJavaIdentifierPart(c))
108                 return false;
109         }
110         return true;
111     }
112 }
113