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