Add support for writing map_item

This commit is contained in:
Izzat Bahadirov 2012-12-17 15:10:34 -05:00 committed by Ben Gruver
parent e68daf22aa
commit 085cfce948
14 changed files with 328 additions and 6 deletions

View File

@ -49,6 +49,7 @@ public class AnnotationDirectoryPool {
@Nonnull private final Map<String, Integer> nonInternedAnnotationDirectoryOffsetMap = Maps.newHashMap();
@Nonnull private final List<Key> nonInternedAnnotationDirectoryItems = Lists.newArrayList();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public AnnotationDirectoryPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
@ -101,10 +102,24 @@ public class AnnotationDirectoryPool {
return offset;
}
public int getNumItems() {
return internedAnnotationDirectoryItems.size() + nonInternedAnnotationDirectoryItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
// we'll write out the interned items first
List<Key> directoryItems = Lists.newArrayList(internedAnnotationDirectoryItems.keySet());
Collections.sort(directoryItems);
writer.align();
sectionOffset = writer.getPosition();
for (Key key: directoryItems) {
writer.align();
internedAnnotationDirectoryItems.put(key, writer.getPosition());

View File

@ -49,6 +49,7 @@ import java.util.SortedSet;
public class AnnotationPool {
@Nonnull private final Map<Annotation, Integer> internedAnnotations = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public AnnotationPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
@ -73,10 +74,22 @@ public class AnnotationPool {
return offset;
}
public int getNumItems() {
return internedAnnotations.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Annotation> annotations = Lists.newArrayList(internedAnnotations.keySet());
Collections.sort(annotations);
sectionOffset = writer.getPosition();
for (Annotation annotation: annotations) {
internedAnnotations.put(annotation, writer.getPosition());
writer.writeUbyte(annotation.getVisibility());

View File

@ -47,6 +47,7 @@ import java.util.*;
public class AnnotationSetPool {
@Nonnull private final Map<Set<? extends Annotation>, Integer> internedAnnotationSetItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public AnnotationSetPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
@ -74,11 +75,24 @@ public class AnnotationSetPool {
return offset;
}
public int getNumItems() {
return internedAnnotationSetItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Set<? extends Annotation>> annotationSets =
Lists.newArrayList(internedAnnotationSetItems.keySet());
Collections.sort(annotationSets, CollectionUtils.listComparator(Ordering.natural()));
writer.align();
sectionOffset = writer.getPosition();
for (Set<? extends Annotation> annotationSet: annotationSets) {
SortedSet<? extends Annotation> sortedAnnotationSet = ImmutableSortedSet.copyOf(BaseAnnotation.BY_TYPE,
annotationSet);

View File

@ -51,6 +51,7 @@ import java.util.*;
public class AnnotationSetRefPool {
@Nonnull private final Map<Key, Integer> internedAnnotationSetRefItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public AnnotationSetRefPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
@ -75,11 +76,24 @@ public class AnnotationSetRefPool {
return offset;
}
public int getNumItems() {
return internedAnnotationSetRefItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Key> annotationSetRefs =
Lists.newArrayList(internedAnnotationSetRefItems.keySet());
Collections.sort(annotationSetRefs);
writer.align();
sectionOffset = writer.getPosition();
for (Key key: annotationSetRefs) {
writer.align();
internedAnnotationSetRefItems.put(key, writer.getPosition());
@ -127,7 +141,7 @@ public class AnnotationSetRefPool {
}
Iterator<Set<? extends Annotation>> otherAnnotationSets = getAnnotationSets().iterator();
for (Set<? extends Annotation> annotationSet: getAnnotationSets()) {
if (!annotationSet.equals(otherAnnotationSets)) {
if (!annotationSet.equals(otherAnnotationSets.next())) {
return false;
}
}

View File

@ -49,6 +49,7 @@ import java.util.Map;
public class DebugInfoPool {
@Nonnull private final Map<Method, Integer> debugInfoOffsetMap = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public DebugInfoPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
@ -96,9 +97,22 @@ public class DebugInfoPool {
return offset;
}
public int getNumItems() {
return debugInfoOffsetMap.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Method> methods = Lists.newArrayList(debugInfoOffsetMap.keySet());
Collections.sort(methods);
sectionOffset = writer.getPosition();
for (Method method: methods) {
debugInfoOffsetMap.put(method, writer.getPosition());

View File

@ -60,6 +60,7 @@ public class DexFile {
@Nonnull final DebugInfoPool debugInfoPool = new DebugInfoPool(this);
@Nonnull final CodeItemPool codeItemPool = new CodeItemPool(this);
@Nonnull final ClassDefPool classDefPool = new ClassDefPool(this);
@Nonnull final MapItem mapItem = new MapItem(this);
@Nonnull private final Set<? extends ClassDef> classes;
@ -205,6 +206,7 @@ public class DexFile {
debugInfoPool.write(offsetWriter);
codeItemPool.write(offsetWriter);
classDefPool.write(indexWriter, offsetWriter);
mapItem.write(offsetWriter);
} finally {
indexWriter.close();
offsetWriter.close();

View File

@ -55,6 +55,7 @@ import java.util.*;
public class EncodedArrayPool {
@Nonnull private final Map<Key, Integer> internedEncodedArrayItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public EncodedArrayPool(DexFile dexFile) {
this.dexFile = dexFile;
@ -84,10 +85,22 @@ public class EncodedArrayPool {
return 0;
}
public int getNumItems() {
return internedEncodedArrayItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Key> encodedArrays = Lists.newArrayList(internedEncodedArrayItems.keySet());
Collections.sort(encodedArrays);
sectionOffset = writer.getPosition();
for (Key encodedArray: encodedArrays) {
internedEncodedArrayItems.put(encodedArray, writer.getPosition());
writer.writeUleb128(encodedArray.getElementCount());

View File

@ -44,9 +44,11 @@ import java.util.List;
import java.util.Map;
public class FieldPool {
private final static int FIELD_ID_ITEM_SIZE = 8;
public final static int FIELD_ID_ITEM_SIZE = 0x08;
@Nonnull private final Map<FieldReference, Integer> internedFieldIdItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public FieldPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
@ -73,10 +75,22 @@ public class FieldPool {
return internedFieldIdItems.size() * FIELD_ID_ITEM_SIZE;
}
public int getNumItems() {
return internedFieldIdItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<FieldReference> fields = Lists.newArrayList(internedFieldIdItems.keySet());
Collections.sort(fields);
sectionOffset = writer.getPosition();
int index = 0;
for (FieldReference field: fields) {
internedFieldIdItems.put(field, index++);

View File

@ -0,0 +1,149 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
public class MapItem {
DexFile dexFile;
private int sectionOffset = -1;
public MapItem(DexFile dexFile) {
this.dexFile = dexFile;
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
writer.align();
sectionOffset = writer.getPosition();
int numItems = calcNumItems();
writer.writeInt(numItems);
// index section
writeItem(writer, DexItemType.HEADER_ITEM, 1, 0);
writeItem(writer, DexItemType.STRING_ID_ITEM, dexFile.stringPool.getNumItems(), dexFile.stringPool.getIndexSectionOffset());
writeItem(writer, DexItemType.TYPE_ID_ITEM, dexFile.typePool.getNumItems(), dexFile.typePool.getSectionOffset());
writeItem(writer, DexItemType.PROTO_ID_ITEM, dexFile.protoPool.getNumItems(), dexFile.protoPool.getSectionOffset());
writeItem(writer, DexItemType.FIELD_ID_ITEM, dexFile.fieldPool.getNumItems(), dexFile.fieldPool.getSectionOffset());
writeItem(writer, DexItemType.METHOD_ID_ITEM, dexFile.methodPool.getNumItems(), dexFile.methodPool.getSectionOffset());
writeItem(writer, DexItemType.CLASS_DEF_ITEM, dexFile.classDefPool.getNumClassDefItems(), dexFile.classDefPool.getIndexSectionOffset());
// data section
writeItem(writer, DexItemType.STRING_DATA_ITEM, dexFile.stringPool.getNumItems(), dexFile.stringPool.getDataSectionOffset());
writeItem(writer, DexItemType.TYPE_LIST, dexFile.typeListPool.getNumItems(), dexFile.typeListPool.getSectionOffset());
writeItem(writer, DexItemType.ENCODED_ARRAY_ITEM, dexFile.encodedArrayPool.getNumItems(), dexFile.encodedArrayPool.getSectionOffset());
writeItem(writer, DexItemType.ANNOTATION_ITEM, dexFile.annotationPool.getNumItems(), dexFile.annotationPool.getSectionOffset());
writeItem(writer, DexItemType.ANNOTATION_SET_ITEM, dexFile.annotationSetPool.getNumItems(), dexFile.annotationSetPool.getSectionOffset());
writeItem(writer, DexItemType.ANNOTATION_SET_REF_LIST, dexFile.annotationSetRefPool.getNumItems(), dexFile.annotationSetRefPool.getSectionOffset());
writeItem(writer, DexItemType.ANNOTATION_DIRECTORY_ITEM, dexFile.annotationDirectoryPool.getNumItems(), dexFile.annotationDirectoryPool.getSectionOffset());
writeItem(writer, DexItemType.DEBUG_INFO_ITEM, dexFile.debugInfoPool.getNumItems(), dexFile.debugInfoPool.getSectionOffset());
writeItem(writer, DexItemType.CODE_ITEM, dexFile.codeItemPool.getNumItems(), dexFile.codeItemPool.getSectionOffset());
writeItem(writer, DexItemType.CLASS_DATA_ITEM, dexFile.classDefPool.getNumClassDataItems(), dexFile.classDefPool.getDataSectionOffset());
writeItem(writer, DexItemType.MAP_LIST, numItems, sectionOffset);
}
private int calcNumItems() {
int numItems = 0;
// header item
numItems++;
if (dexFile.stringPool.getNumItems() > 0) {
numItems += 2; // index and data
}
if (dexFile.typePool.getNumItems() > 0) {
numItems++;
}
if (dexFile.protoPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.fieldPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.methodPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.typeListPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.encodedArrayPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.annotationPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.annotationSetPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.annotationSetRefPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.annotationDirectoryPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.debugInfoPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.codeItemPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.classDefPool.getNumClassDefItems() > 0) {
numItems++;
}
if (dexFile.classDefPool.getNumClassDataItems() > 0) {
numItems++;
}
// map item itself
numItems++;
return numItems;
}
private void writeItem(DexWriter writer, int type, int size, int offset) throws IOException {
if (size > 0) {
writer.writeUshort(type);
writer.writeUshort(0);
writer.writeInt(size);
writer.writeInt(offset);
}
}
}

View File

@ -43,9 +43,11 @@ import java.util.List;
import java.util.Map;
public class MethodPool {
private final static int METHOD_ID_ITEM_SIZE = 8;
public final static int METHOD_ID_ITEM_SIZE = 0x08;
@Nonnull private final Map<MethodReference, Integer> internedMethodIdItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public MethodPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
@ -72,9 +74,21 @@ public class MethodPool {
return internedMethodIdItems.size() * METHOD_ID_ITEM_SIZE;
}
public int getNumItems() {
return internedMethodIdItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<MethodReference> methods = Lists.newArrayList(internedMethodIdItems.keySet());
sectionOffset = writer.getPosition();
int index = 0;
for (MethodReference method: methods) {
internedMethodIdItems.put(method, index++);

View File

@ -47,9 +47,11 @@ import java.util.List;
import java.util.Map;
public class ProtoPool {
private final static int PROTO_ID_ITEM_SIZE = 12;
public final static int PROTO_ID_ITEM_SIZE = 0x0C;
@Nonnull private final Map<Key, Integer> internedProtoIdItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public ProtoPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
@ -80,10 +82,22 @@ public class ProtoPool {
return internedProtoIdItems.size() * PROTO_ID_ITEM_SIZE;
}
public int getNumItems() {
return internedProtoIdItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Key> prototypes = Lists.newArrayList(internedProtoIdItems.keySet());
Collections.sort(prototypes);
sectionOffset = writer.getPosition();
int index = 0;
for (Key proto: prototypes) {
internedProtoIdItems.put(proto, index++);

View File

@ -44,8 +44,11 @@ import java.util.List;
import java.util.Map;
public class StringPool {
private final static int STRING_ID_ITEM_SIZE = 4;
public final static int STRING_ID_ITEM_SIZE = 0x04;
@Nonnull private final Map<String, Integer> internedStringIdItems = Maps.newHashMap();
private int indexSectionOffset = -1;
private int dataSectionOffset = -1;
public void intern(@Nonnull CharSequence string) {
internedStringIdItems.put(string.toString(), 0);
@ -77,10 +80,25 @@ public class StringPool {
return internedStringIdItems.size() * STRING_ID_ITEM_SIZE;
}
public int getNumItems() {
return internedStringIdItems.size();
}
public int getIndexSectionOffset() {
return indexSectionOffset;
}
public int getDataSectionOffset() {
return dataSectionOffset;
}
public void write(@Nonnull DexWriter indexWriter, @Nonnull DexWriter offsetWriter) throws IOException {
List<String> strings = Lists.newArrayList(internedStringIdItems.keySet());
Collections.sort(strings);
indexSectionOffset = indexWriter.getPosition();
dataSectionOffset = offsetWriter.getPosition();
int index = 0;
for (String string: strings) {
internedStringIdItems.put(string, index++);

View File

@ -42,6 +42,7 @@ import java.util.*;
public class TypeListPool {
@Nonnull private final Map<Key, Integer> internedTypeListItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public TypeListPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
@ -66,10 +67,23 @@ public class TypeListPool {
return offset;
}
public int getNumItems() {
return internedTypeListItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Key> typeLists = Lists.newArrayList(internedTypeListItems.keySet());
Collections.sort(typeLists);
writer.align();
sectionOffset = writer.getPosition();
for (Key typeList: typeLists) {
writer.align();
internedTypeListItems.put(typeList, writer.getPosition());

View File

@ -43,9 +43,11 @@ import java.util.List;
import java.util.Map;
public class TypePool {
private final static int TYPE_ID_ITEM_SIZE = 4;
public final static int TYPE_ID_ITEM_SIZE = 0x04;
@Nonnull private final Map<String, Integer> internedTypeIdItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public TypePool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
@ -83,10 +85,22 @@ public class TypePool {
return internedTypeIdItems.size() * TYPE_ID_ITEM_SIZE;
}
public int getNumItems() {
return internedTypeIdItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<String> types = Lists.newArrayList(internedTypeIdItems.keySet());
Collections.sort(types);
sectionOffset = writer.getPosition();
int index = 0;
for (String type: types) {
internedTypeIdItems.put(type, index++);