001: /* ===========================================================================
002: * $RCSfile: TreeItem.java,v $
003: * ===========================================================================
004: *
005: * RetroGuard -- an obfuscation package for Java classfiles.
006: *
007: * Copyright (c) 1998-2006 Mark Welsh (markw@retrologic.com)
008: *
009: * This program can be redistributed and/or modified under the terms of the
010: * Version 2 of the GNU General Public License as published by the Free
011: * Software Foundation.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: */
019:
020: package COM.rl.obf;
021:
022: import java.io.*;
023: import java.lang.reflect.*;
024: import java.util.*;
025: import COM.rl.util.*;
026: import COM.rl.obf.classfile.*;
027:
028: /**
029: * Item that forms a tree structure and can represent a package level, a class,
030: * or a method or field.
031: *
032: * @author Mark Welsh
033: */
034: public class TreeItem {
035: // Constants -------------------------------------------------------------
036:
037: // Fields ----------------------------------------------------------------
038: protected boolean isSynthetic; // Is a method or field Synthetic?
039: protected int access; // Access level (interpret using java.lang.reflect.Modifier)
040: protected ClassTree classTree = null; // Our owner
041: protected TreeItem parent = null; // Our immediate parent
042: protected String sep = ClassFile.SEP_REGULAR; // Separator preceeding this level's name
043: private String inName = null; // Original name of this item
044: private String outName = null; // Output name of this item
045: private boolean isFixed = false; // Has the name been fixed in some way?
046: private boolean isFromScript = false; // Is this script constrained?
047: private boolean isFromScriptMap = false; // Is this script_map constrained?
048: private boolean isTrimmed = false; // Is this to be trimmed?
049: private boolean isTrimCheck = false; // Has this been checked for trimming?
050: private Vector treeItemRefs = null; // List of referenced Cl/Md/Fd placeholders
051:
052: // Class Methods ---------------------------------------------------------
053: /** Do a wildcard String match. */
054: public static boolean isMatch(String pattern, String string) {
055: // Sanity check
056: if (pattern == null || string == null) {
057: return false;
058: }
059:
060: // Not really a wildcard, then check for exact match
061: if (pattern.indexOf('*') == -1) {
062: return pattern.equals(string);
063: }
064:
065: // Check for match of head
066: int pos = -1;
067: if (pattern.charAt(0) != '*') {
068: pos = pattern.indexOf('*');
069: String head = pattern.substring(0, pos);
070: if (string.length() < head.length()) {
071: return false;
072: }
073: if (!string.substring(0, head.length()).equals(head)) {
074: return false;
075: } else {
076: pattern = pattern.substring(pos);
077: string = string.substring(pos);
078: }
079: }
080: // Check for match of tail
081: if (pattern.charAt(pattern.length() - 1) != '*') {
082: pos = pattern.lastIndexOf('*');
083: String tail = pattern.substring(pos + 1);
084: if (string.length() < tail.length()) {
085: return false;
086: }
087: if (!string.substring(string.length() - tail.length())
088: .equals(tail)) {
089: return false;
090: } else {
091: pattern = pattern.substring(0, pos + 1);
092: string = string.substring(0, string.length()
093: - tail.length());
094: }
095: }
096: // Split the pattern at the wildcard positions
097: Vector section = new Vector();
098: pos = pattern.indexOf('*');
099: int rpos = -1;
100: while ((rpos = pattern.indexOf('*', pos + 1)) != -1) {
101: if (rpos != pos + 1) {
102: section.addElement(pattern.substring(pos + 1, rpos));
103: }
104: pos = rpos;
105: }
106: // Check each section for a non-overlapping match in the string
107: for (Enumeration enm = section.elements(); enm
108: .hasMoreElements();) {
109: String chunk = (String) enm.nextElement();
110: pos = string.indexOf(chunk);
111: if (pos == -1) {
112: return false;
113: }
114: string = string.substring(pos + chunk.length());
115: }
116: return true;
117: }
118:
119: /** Do a generalized wildcard String match - handles '**' wildcard
120: * that matches across package boundaries. */
121: public static boolean isGMatch(String pattern, String string) {
122: PatternList pl, sl;
123: try {
124: pl = PatternList.create(pattern);
125: sl = PatternList.create(string);
126: if (!pl.scExists()) {
127: if (pl.length() != sl.length())
128: return false;
129: // check each string identifier against the non-** pattern
130: for (int i = 0; i < pl.length(); i++) {
131: if (!isMatch(pl.getSub(i), sl.getSub(i)))
132: return false;
133: }
134: } else {
135: if (pl.length() > sl.length())
136: return false;
137: // check the head identifiers (pre-** segment)
138: for (int i = 0; i < pl.scIndex(); i++) {
139: if (!isMatch(pl.getSub(i), sl.getSub(i)))
140: return false;
141: }
142: // check the tail identifiers (post-** segment)
143: for (int i = pl.scIndex() + 1; i < pl.length(); i++) {
144: int j = i + sl.length() - pl.length();
145: if (!isMatch(pl.getSub(i), sl.getSub(j)))
146: return false;
147: }
148: // check the merged central identifiers against the ** segment
149: int j = pl.scIndex() + sl.length() - pl.length();
150: if (!isMatch(pl.getSub(pl.scIndex()), sl.getSub(pl
151: .scIndex(), j)))
152: return false;
153: }
154: } catch (Exception e) {
155: return false;
156: }
157: return true;
158: }
159:
160: // Instance Methods ------------------------------------------------------
161: /** Ctor. */
162: public TreeItem(TreeItem parent, String name) {
163: this .parent = parent;
164: this .inName = name;
165: if (parent != null) {
166: classTree = parent.classTree;
167: }
168: }
169:
170: /** Return the modifiers. */
171: public int getModifiers() {
172: return access;
173: }
174:
175: /** Do the modifiers specified by mask equal the settings? */
176: public boolean modifiersMatchMask(int mask, int setting) {
177: return (getModifiers() & mask) == (setting & mask);
178: }
179:
180: /** Return the original name of the entry. */
181: public String getInName() {
182: return inName;
183: }
184:
185: /** Set the output name of the entry. */
186: public void setOutName(String outName) {
187: this .outName = outName;
188: isFixed = true;
189: }
190:
191: /** Return the output name of the entry, obfuscated or original. */
192: public String getOutName() {
193: return outName != null ? outName : inName;
194: }
195:
196: /** Return the obfuscated name of the entry. */
197: public String getObfName() {
198: return outName;
199: }
200:
201: /** Signal that this constraint came from a user script line. */
202: public void setFromScript() {
203: isFromScript = true;
204: }
205:
206: /** Clear the signal that this constraint came from a user script line. */
207: public void clearFromScript() {
208: if (isFromScript) {
209: isFixed = false;
210: isFromScript = false;
211: }
212: }
213:
214: /** Signal that this constraint came from a map script line. */
215: public void setFromScriptMap() {
216: isFromScriptMap = true;
217: }
218:
219: /** Has the entry been fixed already? */
220: public boolean isFixed() {
221: return isFixed;
222: }
223:
224: /** Is this constrained by a user script line? */
225: public boolean isFromScript() {
226: return isFromScript;
227: }
228:
229: /** Is this constrained by a map script line? */
230: public boolean isFromScriptMap() {
231: return isFromScriptMap;
232: }
233:
234: /** Is a method or field Synthetic? */
235: public boolean isSynthetic() {
236: return isSynthetic;
237: }
238:
239: /** Set the parent in the tree -- used when stitching in a Cl to replace a PlaceholderCl. */
240: public void setParent(TreeItem parent) {
241: this .parent = parent;
242: }
243:
244: /** Get the parent in the tree. */
245: public TreeItem getParent() {
246: return parent;
247: }
248:
249: /** Construct and return the full original name of the entry. */
250: public String getFullInName() {
251: if (parent == null) {
252: return "";
253: } else if (parent.parent == null) {
254: return getInName();
255: } else {
256: return parent.getFullInName() + sep + getInName();
257: }
258: }
259:
260: /** Construct and return the full obfuscated name of the entry. */
261: public String getFullOutName() {
262: if (parent == null) {
263: return "";
264: } else if (parent.parent == null) {
265: return getOutName();
266: } else {
267: return parent.getFullOutName() + sep + getOutName();
268: }
269: }
270:
271: /** Does this name match the wildcard pattern? (compatibility mode) */
272: public boolean isOldStyleMatch(String pattern) {
273: return isMatch(pattern, getFullInName());
274: }
275:
276: /** Does this name match the wildcard pattern? (** and * supported) */
277: public boolean isWildcardMatch(String pattern) {
278: return isGMatch(pattern, getFullInName());
279: }
280:
281: /** Set the trimming state for this. */
282: public void setTrimmed(boolean trimmed) {
283: isTrimmed = trimmed;
284: }
285:
286: /** Is this to be trimmed? */
287: public boolean isTrimmed() {
288: return isTrimmed;
289: }
290:
291: /** Set the trim-check status for this. */
292: public void setTrimCheck(boolean state) {
293: isTrimCheck = state;
294: }
295:
296: /** Has this been checked for trimming? */
297: public boolean isTrimCheck() {
298: return isTrimCheck;
299: }
300:
301: /** Add a TreeItem references. */
302: public void addRef(Object ref) {
303: if (treeItemRefs == null) {
304: treeItemRefs = new Vector();
305: }
306: treeItemRefs.addElement(ref);
307: }
308:
309: /** Push internal references from this item to the stack as TreeItems. */
310: public void pushRefs(Stack stack) throws Exception {
311: if (treeItemRefs != null) {
312: for (Enumeration enm = treeItemRefs.elements(); enm
313: .hasMoreElements();) {
314: TreeItem ti = null;
315: Object o = enm.nextElement();
316: if (o instanceof TreeItem) {
317: ti = (TreeItem) o;
318: } else if (o instanceof TreeItemRef) {
319: ti = ((TreeItemRef) o).toTreeItem(classTree);
320: }
321: stack.push(ti);
322: }
323: }
324: }
325: }
|