1818import com .reandroid .dex .key .Key ;
1919import com .reandroid .dex .key .KeyPair ;
2020import com .reandroid .dex .model .DexClassRepository ;
21+ import com .reandroid .dex .smali .SmaliDirective ;
22+ import com .reandroid .dex .smali .SmaliFormat ;
23+ import com .reandroid .dex .smali .SmaliParseException ;
24+ import com .reandroid .dex .smali .SmaliParser ;
25+ import com .reandroid .dex .smali .SmaliReader ;
26+ import com .reandroid .dex .smali .SmaliWriter ;
2127import com .reandroid .utils .CompareUtil ;
2228import com .reandroid .utils .ObjectsUtil ;
23- import com .reandroid .utils .StringsUtil ;
2429import com .reandroid .utils .collection .ArrayCollection ;
30+ import com .reandroid .utils .collection .CollectionUtil ;
2531
26- import java .util .*;
32+ import java .io .File ;
33+ import java .io .IOException ;
34+ import java .util .Collection ;
35+ import java .util .Comparator ;
36+ import java .util .HashMap ;
37+ import java .util .HashSet ;
38+ import java .util .Iterator ;
39+ import java .util .List ;
40+ import java .util .Map ;
41+ import java .util .Set ;
2742
28- public abstract class Rename <T extends Key , R extends Key > {
43+ public abstract class Rename <T extends Key , R extends Key >
44+ implements SmaliFormat , SmaliParser {
2945
3046 private final Map <KeyPair <?, ?>, KeyPair <T , R >> keyPairMap ;
3147 private final Map <KeyPair <?, ?>, KeyPair <T , R >> flippedKeyMap ;
@@ -39,20 +55,35 @@ public Rename() {
3955 this .lockedFlippedKeys = new HashSet <>();
4056 }
4157
58+ public abstract void add (DexClassRepository classRepository , KeyPair <T , R > keyPair );
59+
60+ public void add (DexClassRepository classRepository , T search , R replace ) {
61+ add (classRepository , new KeyPair <>(search , replace ));
62+ }
4263 public void add (T search , R replace ) {
4364 add (new KeyPair <>(search , replace ));
4465 }
45- public void add (KeyPair <T , R > keyPair ){
66+ public void add (KeyPair <T , R > keyPair ) {
4667 addToSet (keyPair );
4768 }
48- public void addAll (Collection <KeyPair <T , R >> keyPairs ){
69+ public void addAll (Collection <KeyPair <T , R >> keyPairs ) {
4970 this .addAll (keyPairs .iterator ());
5071 }
51- public void addAll (Iterator <KeyPair <T , R >> iterator ){
52- while (iterator .hasNext ()){
72+ public void addAll (Iterator <KeyPair <T , R >> iterator ) {
73+ while (iterator .hasNext ()) {
5374 add (iterator .next ());
5475 }
5576 }
77+ public void addAll (DexClassRepository classRepository , Collection <KeyPair <T , R >> keyPairs ) {
78+ if (keyPairs != null ) {
79+ addAll (classRepository , keyPairs .iterator ());
80+ }
81+ }
82+ public void addAll (DexClassRepository classRepository , Iterator <KeyPair <T , R >> iterator ) {
83+ while (iterator .hasNext ()) {
84+ add (classRepository , iterator .next ());
85+ }
86+ }
5687 private void addToSet (KeyPair <T , R > keyPair ) {
5788 if (keyPair == null || !keyPair .isValid ()) {
5889 return ;
@@ -108,9 +139,9 @@ private void lockKey(KeyPair<T, R> keyPair, KeyPair<R, T> flip) {
108139 lockKey (p2 , p2 .flip ());
109140 }
110141 }
111- public boolean isLocked (KeyPair <T , R > keyPair ) {
142+ public boolean isLocked (KeyPair <?, ? > keyPair ) {
112143 if (keyPair != null ) {
113- KeyPair <R , T > flip = keyPair .flip ();
144+ KeyPair <?, ? > flip = keyPair .flip ();
114145 return lockedKeys .contains (keyPair ) ||
115146 lockedFlippedKeys .contains (keyPair ) ||
116147 lockedKeys .contains (flip ) ||
@@ -148,10 +179,27 @@ public void close() {
148179 lockedFlippedKeys .clear ();
149180 }
150181
182+ public boolean isEmpty () {
183+ return size () == 0 && lockedSize () == 0 ;
184+ }
151185 public int size () {
152186 return keyPairMap .size ();
153187 }
188+ public int lockedSize () {
189+ return lockedKeys .size ();
190+ }
154191
192+ public boolean contains (KeyPair <?, ?> keyPair ) {
193+ if (keyPair != null ) {
194+ return contains (keyPair .getFirst ()) ||
195+ contains (keyPair .getSecond ()) ||
196+ isLocked (keyPair );
197+ }
198+ return false ;
199+ }
200+ public boolean contains (Key key ) {
201+ return get (key ) != null || getFlipped (key ) != null ;
202+ }
155203 public KeyPair <T , R > get (Key search ) {
156204 return keyPairMap .get (new KeyPair <>(search , null ));
157205 }
@@ -211,13 +259,164 @@ protected boolean containsDeclaration(DexClassRepository classRepository, R repl
211259 }
212260
213261 public abstract int apply (DexClassRepository classRepository );
262+ public int apply (Rename <?, ?> rename ) {
263+ if (this .isEmpty () || rename .isEmpty ()) {
264+ return 0 ;
265+ }
266+ List <? extends KeyPair <?, ?>> list = rename .toList ();
267+ int result = 0 ;
268+ for (KeyPair <?, ?> keyPair : list ) {
269+ KeyPair <?, ?> renamedPair = apply (keyPair );
270+ if (renamedPair != keyPair ) {
271+ rename .replace (keyPair , renamedPair );
272+ result ++;
273+ }
274+ }
275+ return result ;
276+ }
277+ public KeyPair <?, ?> apply (KeyPair <?, ?> keyPair ) {
278+ Key first = keyPair .getFirst ();
279+ Key first2 = this .renameKey (first );
280+ Key second = keyPair .getSecond ();
281+ Key second2 = this .renameKey (second );
282+ if (first != first2 || second != second2 ) {
283+ keyPair = new KeyPair <>(first2 , second2 );
284+ }
285+ return keyPair ;
286+ }
287+ private void replace (KeyPair <?, ?> keyPair , KeyPair <?, ?> replace ) {
288+ if (keyPairMap .remove (keyPair ) != null ) {
289+ flippedKeyMap .remove (keyPair .flip ());
290+ add (ObjectsUtil .cast (replace ));
291+ }
292+ }
293+ protected Key renameKey (Key key ) {
294+ Iterator <? extends Key > iterator = CollectionUtil .uniqueOf (key .mentionedKeys ());
295+ while (iterator .hasNext ()) {
296+ Key mentioned = iterator .next ();
297+ Key replace = getReplace (mentioned );
298+ if (replace != null ) {
299+ key = key .replaceKey (mentioned , replace );
300+ }
301+ }
302+ return key ;
303+ }
304+ public KeyPair <T , R > mergeRename (KeyPair <T , R > lower ) {
305+ KeyPair <T , R > renamed = get (lower .getSecond ());
306+ if (renamed != null && !renamed .equalsBoth (lower )) {
307+ return new KeyPair <>(lower .getFirst (), renamed .getSecond ());
308+ }
309+ return lower ;
310+ }
214311
215312 public Set <KeyPair <T , R >> getKeyPairSet () {
216313 return ObjectsUtil .cast (keyPairMap .keySet ());
217314 }
218315
316+ public abstract SmaliDirective getSmaliDirective ();
317+
318+ @ Override
319+ public void append (SmaliWriter writer ) throws IOException {
320+ SmaliDirective directive = getSmaliDirective ();
321+ directive .append (writer );
322+ writer .appendComment ("size = " + size ());
323+ int locked = lockedSize ();
324+ if (locked != 0 ) {
325+ writer .appendComment ("locked = " + locked , false );
326+ }
327+ writer .indentPlus ();
328+ List <KeyPair <T , R >> keyPairList = toList ();
329+ for (KeyPair <T , R > keyPair : keyPairList ) {
330+ writer .newLine ();
331+ keyPair .append (writer );
332+ }
333+ List <KeyPair <T , R >> lockedKeyPairList = listLocked ();
334+ for (KeyPair <T , R > keyPair : lockedKeyPairList ) {
335+ writer .newLine ();
336+ writer .appendComment (keyPair .toString ());
337+ }
338+ writer .indentMinus ();
339+ directive .appendEnd (writer );
340+ writer .newLine ();
341+ }
342+
343+ @ Override
344+ public void parse (SmaliReader reader ) throws IOException {
345+ parse (null , reader );
346+ }
347+ public void parse (DexClassRepository classRepository , SmaliReader reader ) throws IOException {
348+ reader .skipWhitespacesOrComment ();
349+ if (reader .finished ()) {
350+ return ;
351+ }
352+ SmaliDirective directive = getSmaliDirective ();
353+ if (directive .isEnd (reader )) {
354+ directive .skipEnd (reader );
355+ return ;
356+ }
357+ SmaliParseException .expect (reader , directive );
358+ reader .skipWhitespacesOrComment ();
359+ while (!directive .isEnd (reader )) {
360+ KeyPair <T , R > keyPair = KeyPair .read (directive , reader );
361+ if (classRepository == null ) {
362+ add (keyPair );
363+ } else {
364+ add (classRepository , keyPair );
365+ }
366+ reader .skipWhitespacesOrComment ();
367+ }
368+ SmaliParseException .expect (reader , directive , true );
369+ }
370+
371+ public void writeSmali (File file ) throws IOException {
372+ SmaliWriter writer = new SmaliWriter ();
373+ writer .setWriter (file );
374+ append (writer );
375+ writer .close ();
376+ }
377+
378+ public String toSmaliString () {
379+ return SmaliWriter .toStringSafe (this );
380+ }
219381 @ Override
220382 public String toString () {
221- return StringsUtil .join (toList (), '\n' );
383+ return size () + "/" + lockedSize ();
384+ }
385+
386+ public static Rename <?, ?> read (SmaliReader reader ) throws IOException {
387+ return read (null , null , reader );
388+ }
389+ public static Rename <?, ?> read (RenameFactory renameFactory , DexClassRepository classRepository , SmaliReader reader ) throws IOException {
390+ if (renameFactory == null ) {
391+ renameFactory = RenameFactory .DEFAULT_FACTORY ;
392+ }
393+ reader .skipWhitespacesOrComment ();
394+ SmaliDirective directive = SmaliDirective .parse (reader , false );
395+ if (directive == null ) {
396+ throw new SmaliParseException (
397+ "Expecting rename directives (.class, .field, .method ...)" , reader );
398+ }
399+ if (directive .isEnd (reader )) {
400+ throw new SmaliParseException ("Unexpected end" , reader );
401+ }
402+ Rename <?, ?> rename = renameFactory .createRename (directive );
403+ if (rename == null ) {
404+ throw new SmaliParseException ("Unknown rename directive" , reader );
405+ }
406+ rename .parse (classRepository , reader );
407+ return rename ;
408+ }
409+
410+ public static Rename <?, ?> createRenameFor (SmaliDirective directive ) {
411+ if (directive == SmaliDirective .CLASS ) {
412+ return new RenameTypes ();
413+ }
414+ if (directive == SmaliDirective .FIELD ) {
415+ return new RenameFields ();
416+ }
417+ if (directive == SmaliDirective .METHOD ) {
418+ return new RenameMethods ();
419+ }
420+ return null ;
222421 }
223422}
0 commit comments