1081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson/*
2081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Copyright (C) 2011 The Android Open Source Project
3081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson *
4081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * you may not use this file except in compliance with the License.
6081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * You may obtain a copy of the License at
7081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson *
8081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson *
10081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Unless required by applicable law or agreed to in writing, software
11081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * See the License for the specific language governing permissions and
14081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * limitations under the License.
15081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson */
16081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
17081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonpackage com.android.dx.merge;
18081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
19081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonimport com.android.dx.dex.TableOfContents;
20bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilsonimport com.android.dx.io.Annotation;
21dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilsonimport com.android.dx.io.ClassDef;
22dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilsonimport com.android.dx.io.DexBuffer;
23bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilsonimport com.android.dx.io.EncodedValue;
24bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilsonimport com.android.dx.io.EncodedValueReader;
25dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilsonimport com.android.dx.io.FieldId;
26dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilsonimport com.android.dx.io.MethodId;
27dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilsonimport com.android.dx.io.ProtoId;
28bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilsonimport com.android.dx.util.ByteArrayAnnotatedOutput;
29bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilsonimport com.android.dx.util.ByteInput;
30bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilsonimport com.android.dx.util.ByteOutput;
31bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilsonimport com.android.dx.util.Leb128Utils;
32bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilsonimport com.android.dx.util.Unsigned;
33cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilsonimport java.util.HashMap;
34081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
35081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson/**
36081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * Maps the index offsets from one dex file to those in another. For example, if
37081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * you have string #5 in the old dex file, its position in the new dex file is
38081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson * {@code strings[5]}.
39081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson */
40081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilsonpublic final class IndexMap {
41dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    private final DexBuffer target;
42081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    public final int[] stringIds;
43dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public final short[] typeIds;
44dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public final short[] protoIds;
45dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public final short[] fieldIds;
46dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public final short[] methodIds;
47d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson    private final HashMap<Integer, Integer> typeListOffsets;
48bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    private final HashMap<Integer, Integer> annotationOffsets;
49d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson    private final HashMap<Integer, Integer> annotationSetOffsets;
50d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson    private final HashMap<Integer, Integer> annotationDirectoryOffsets;
51fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson    private final HashMap<Integer, Integer> staticValuesOffsets;
52081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
53dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public IndexMap(DexBuffer target, TableOfContents tableOfContents) {
54dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        this.target = target;
55dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        this.stringIds = new int[tableOfContents.stringIds.size];
56dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        this.typeIds = new short[tableOfContents.typeIds.size];
57dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        this.protoIds = new short[tableOfContents.protoIds.size];
58dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        this.fieldIds = new short[tableOfContents.fieldIds.size];
59dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        this.methodIds = new short[tableOfContents.methodIds.size];
60cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson        this.typeListOffsets = new HashMap<Integer, Integer>();
61bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        this.annotationOffsets = new HashMap<Integer, Integer>();
6220d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson        this.annotationSetOffsets = new HashMap<Integer, Integer>();
6320d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson        this.annotationDirectoryOffsets = new HashMap<Integer, Integer>();
64fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson        this.staticValuesOffsets = new HashMap<Integer, Integer>();
65cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson
66cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson        /*
67fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson         * A type list, annotation set, annotation directory, or static value at
68fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson         * offset 0 is always empty. Always map offset 0 to 0.
69cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson         */
70cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson        this.typeListOffsets.put(0, 0);
7120d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson        this.annotationSetOffsets.put(0, 0);
7220d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson        this.annotationDirectoryOffsets.put(0, 0);
73fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson        this.staticValuesOffsets.put(0, 0);
74081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    }
75081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson
76d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson    public void putTypeListOffset(int oldOffset, int newOffset) {
77d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson        if (oldOffset <= 0 || newOffset <= 0) {
78d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson            throw new IllegalArgumentException();
79d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson        }
80d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson        typeListOffsets.put(oldOffset, newOffset);
81d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson    }
82d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson
83bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    public void putAnnotationOffset(int oldOffset, int newOffset) {
84bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        if (oldOffset <= 0 || newOffset <= 0) {
85bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            throw new IllegalArgumentException();
86bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
87bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        annotationOffsets.put(oldOffset, newOffset);
88bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    }
89bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
90d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson    public void putAnnotationSetOffset(int oldOffset, int newOffset) {
91d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson        if (oldOffset <= 0 || newOffset <= 0) {
92d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson            throw new IllegalArgumentException();
93d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson        }
94d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson        annotationSetOffsets.put(oldOffset, newOffset);
95d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson    }
96d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson
97d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson    public void putAnnotationDirectoryOffset(int oldOffset, int newOffset) {
98d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson        if (oldOffset <= 0 || newOffset <= 0) {
99d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson            throw new IllegalArgumentException();
100d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson        }
101d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson        annotationDirectoryOffsets.put(oldOffset, newOffset);
102d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson    }
103d1e1668224cde06bbe5ad8953c7fb86d1d0d40e4Jesse Wilson
104fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson    public void putStaticValuesOffset(int oldOffset, int newOffset) {
105fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson        if (oldOffset <= 0 || newOffset <= 0) {
106fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson            throw new IllegalArgumentException();
107fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson        }
108fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson        staticValuesOffsets.put(oldOffset, newOffset);
109fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson    }
110fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson
111dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public int adjustString(int stringIndex) {
112dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        return stringIndex == ClassDef.NO_INDEX ? ClassDef.NO_INDEX : stringIds[stringIndex];
113dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    }
114dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
115bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    public int adjustType(int typeIndex) {
116bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        return (typeIndex == ClassDef.NO_INDEX) ? ClassDef.NO_INDEX : (typeIds[typeIndex] & 0xffff);
117dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    }
118dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
119cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson    public TypeList adjustTypeList(TypeList typeList) {
120cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson        if (typeList == TypeList.EMPTY) {
121cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson            return typeList;
122cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson        }
123cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson        short[] types = typeList.getTypes().clone();
124cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson        for (int i = 0; i < types.length; i++) {
125bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            types[i] = (short) adjustType(types[i]);
126081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson        }
127cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson        return new TypeList(target, types);
128dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    }
129dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
130bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    public int adjustProto(int protoIndex) {
131bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        return protoIds[protoIndex] & 0xffff;
132dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    }
133dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
134bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    public int adjustField(int fieldIndex) {
135bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        return fieldIds[fieldIndex] & 0xffff;
136dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    }
137dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
138bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    public int adjustMethod(int methodIndex) {
139bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        return methodIds[methodIndex] & 0xffff;
140dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    }
141dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
142cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson    public int adjustTypeListOffset(int typeListOffset) {
143cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson        return typeListOffsets.get(typeListOffset);
144cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson    }
145cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson
146bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    public int adjustAnnotation(int annotationOffset) {
147bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        return annotationOffsets.get(annotationOffset);
148bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    }
149bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
15020d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson    public int adjustAnnotationSet(int annotationSetOffset) {
15120d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson        return annotationSetOffsets.get(annotationSetOffset);
15220d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson    }
15320d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson
15420d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson    public int adjustAnnotationDirectory(int annotationDirectoryOffset) {
15520d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson        return annotationDirectoryOffsets.get(annotationDirectoryOffset);
15620d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson    }
15720d269ea2a9e8d41b298134f3937c6d959288b53Jesse Wilson
158fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson    public int adjustStaticValues(int staticValuesOffset) {
159fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson        return staticValuesOffsets.get(staticValuesOffset);
160fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson    }
161fa3b293a068fd521a6ba6019a051ad502dfaca55Jesse Wilson
162dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public MethodId adjust(MethodId methodId) {
163dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        return new MethodId(target,
164dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson                adjustType(methodId.getDeclaringClassIndex()),
165dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson                adjustProto(methodId.getProtoIndex()),
166dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson                adjustString(methodId.getNameIndex()));
167dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    }
168dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
169dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public FieldId adjust(FieldId fieldId) {
170dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        return new FieldId(target,
171dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson                adjustType(fieldId.getDeclaringClassIndex()),
172dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson                adjustType(fieldId.getTypeIndex()),
173dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson                adjustString(fieldId.getNameIndex()));
174dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
175dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    }
176dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
177dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public ProtoId adjust(ProtoId protoId) {
178dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        return new ProtoId(target,
179dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson                adjustString(protoId.getShortyIndex()),
180dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson                adjustType(protoId.getReturnTypeIndex()),
181cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson                adjustTypeListOffset(protoId.getParametersOffset()));
182dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    }
183dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
184dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public ClassDef adjust(ClassDef classDef) {
185dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        return new ClassDef(target, classDef.getOffset(), adjustType(classDef.getTypeIndex()),
186dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson                classDef.getAccessFlags(), adjustType(classDef.getSupertypeIndex()),
187cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson                adjustTypeListOffset(classDef.getInterfacesOffset()), classDef.getSourceFileIndex(),
188cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson                classDef.getAnnotationsOffset(), classDef.getClassDataOffset(),
189cdef3ed061e2a045d956ea613556a67f9ac6e9d0Jesse Wilson                classDef.getStaticValuesOffset());
190dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    }
191dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson
192dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson    public SortableType adjust(SortableType sortableType) {
193dc8ad6cbf19b62d8c50527a0a38fe82b937370f1Jesse Wilson        return new SortableType(sortableType.getBuffer(), adjust(sortableType.getClassDef()));
194081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson    }
195bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
196bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    public EncodedValue adjustEncodedValue(EncodedValue encodedValue) {
197bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(32);
198bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        new EncodedValueTransformer(encodedValue, out).readValue();
199bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        return new EncodedValue(out.toByteArray());
200bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    }
201bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
202bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    public EncodedValue adjustEncodedArray(EncodedValue encodedArray) {
203bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(32);
204bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        new EncodedValueTransformer(encodedArray, out).readArray();
205bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        return new EncodedValue(out.toByteArray());
206bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    }
207bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
208bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    public Annotation adjust(Annotation annotation) {
209bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        int[] names = annotation.getNames().clone();
210bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        EncodedValue[] values = annotation.getValues().clone();
211bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        for (int i = 0; i < names.length; i++) {
212bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            names[i] = adjustString(names[i]);
213bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            values[i] = adjustEncodedValue(values[i]);
214bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
215bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        return new Annotation(target, annotation.getVisibility(),
216bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson                adjustType(annotation.getTypeIndex()), names, values);
217bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    }
218bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
219bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    /**
220bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson     * Adjust an encoded value or array.
221bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson     */
222bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    private final class EncodedValueTransformer extends EncodedValueReader {
223bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        private final ByteOutput out;
224bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
225bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        public EncodedValueTransformer(EncodedValue encodedValue, ByteOutput out) {
226bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            super(encodedValue);
227bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            this.out = out;
228bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
229bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
230bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitArray(int size) {
231bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            Leb128Utils.writeUnsignedLeb128(out, size);
232bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
233bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
234bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitAnnotation(int typeIndex, int size) {
235bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            Leb128Utils.writeUnsignedLeb128(out, adjustType(typeIndex));
236bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            Leb128Utils.writeUnsignedLeb128(out, size);
237bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
238bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
239bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitAnnotationName(int index) {
240bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            Leb128Utils.writeUnsignedLeb128(out, adjustString(index));
241bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
242bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
243bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitPrimitive(int argAndType, int type, int arg, int size) {
244bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            out.writeByte(argAndType);
245bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            copyBytes(in, out, size);
246bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
247bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
248bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitString(int type, int index) {
249bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            writeTypeAndSizeAndIndex(type, adjustString(index));
250bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
251bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
252bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitType(int type, int index) {
253bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            writeTypeAndSizeAndIndex(type, adjustType(index));
254bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
255bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
256bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitField(int type, int index) {
257bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            writeTypeAndSizeAndIndex(type, adjustField(index));
258bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
259bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
260bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitMethod(int type, int index) {
261bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            writeTypeAndSizeAndIndex(type, adjustMethod(index));
262bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
263bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
264bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitArrayValue(int argAndType) {
265bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            out.writeByte(argAndType);
266bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
267bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
268bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitAnnotationValue(int argAndType) {
269bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            out.writeByte(argAndType);
270bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
271bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
272bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitEncodedBoolean(int argAndType) {
273bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            out.writeByte(argAndType);
274bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
275bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
276bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        protected void visitEncodedNull(int argAndType) {
277bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            out.writeByte(argAndType);
278bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
279bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
280bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        private void writeTypeAndSizeAndIndex(int type, int index) {
281bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            int byteCount;
282bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            if (Unsigned.compare(index, 0xff) <= 0) {
283bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson                byteCount = 1;
284bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            } else if (Unsigned.compare(index, 0xffff) <= 0) {
285bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson                byteCount = 2;
286bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            } else if (Unsigned.compare(index, 0xffffff) <= 0) {
287bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson                byteCount = 3;
288bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            } else {
289bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson                byteCount = 4;
290bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            }
291bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            int argAndType = ((byteCount - 1) << 5) | type;
292bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            out.writeByte(argAndType);
293bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
294bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            for (int i = 0; i < byteCount; i++) {
295bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson                out.writeByte(index & 0xff);
296bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson                index >>>= 8;
297bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            }
298bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
299bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson
300bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        private void copyBytes(ByteInput in, ByteOutput out, int size) {
301bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            for (int i = 0; i < size; i++) {
302bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson                out.writeByte(in.readByte());
303bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson            }
304bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        }
305bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    }
306081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson}
307