diff options
Diffstat (limited to 'dexgen/src/com/android/dexgen/dex/file/MapItem.java')
-rw-r--r-- | dexgen/src/com/android/dexgen/dex/file/MapItem.java | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/dexgen/src/com/android/dexgen/dex/file/MapItem.java b/dexgen/src/com/android/dexgen/dex/file/MapItem.java new file mode 100644 index 0000000..02472d4 --- /dev/null +++ b/dexgen/src/com/android/dexgen/dex/file/MapItem.java @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dexgen.dex.file; + +import com.android.dexgen.util.AnnotatedOutput; +import com.android.dexgen.util.Hex; + +import java.util.ArrayList; + +/** + * Class that represents a map item. + */ +public final class MapItem extends OffsettedItem { + /** file alignment of this class, in bytes */ + private static final int ALIGNMENT = 4; + + /** write size of this class, in bytes: three {@code uint}s */ + private static final int WRITE_SIZE = (4 * 3); + + /** {@code non-null;} item type this instance covers */ + private final ItemType type; + + /** {@code non-null;} section this instance covers */ + private final Section section; + + /** + * {@code null-ok;} first item covered or {@code null} if this is + * a self-reference + */ + private final Item firstItem; + + /** + * {@code null-ok;} last item covered or {@code null} if this is + * a self-reference + */ + private final Item lastItem; + + /** + * {@code > 0;} count of items covered; {@code 1} if this + * is a self-reference + */ + private final int itemCount; + + /** + * Constructs a list item with instances of this class representing + * the contents of the given array of sections, adding it to the + * given map section. + * + * @param sections {@code non-null;} the sections + * @param mapSection {@code non-null;} the section that the resulting map + * should be added to; it should be empty on entry to this method + */ + public static void addMap(Section[] sections, + MixedItemSection mapSection) { + if (sections == null) { + throw new NullPointerException("sections == null"); + } + + if (mapSection.items().size() != 0) { + throw new IllegalArgumentException( + "mapSection.items().size() != 0"); + } + + ArrayList<MapItem> items = new ArrayList<MapItem>(50); + + for (Section section : sections) { + ItemType currentType = null; + Item firstItem = null; + Item lastItem = null; + int count = 0; + + for (Item item : section.items()) { + ItemType type = item.itemType(); + if (type != currentType) { + if (count != 0) { + items.add(new MapItem(currentType, section, + firstItem, lastItem, count)); + } + currentType = type; + firstItem = item; + count = 0; + } + lastItem = item; + count++; + } + + if (count != 0) { + // Add a MapItem for the final items in the section. + items.add(new MapItem(currentType, section, + firstItem, lastItem, count)); + } else if (section == mapSection) { + // Add a MapItem for the self-referential section. + items.add(new MapItem(mapSection)); + } + } + + mapSection.add( + new UniformListItem<MapItem>(ItemType.TYPE_MAP_LIST, items)); + } + + /** + * Constructs an instance. + * + * @param type {@code non-null;} item type this instance covers + * @param section {@code non-null;} section this instance covers + * @param firstItem {@code non-null;} first item covered + * @param lastItem {@code non-null;} last item covered + * @param itemCount {@code > 0;} count of items covered + */ + private MapItem(ItemType type, Section section, Item firstItem, + Item lastItem, int itemCount) { + super(ALIGNMENT, WRITE_SIZE); + + if (type == null) { + throw new NullPointerException("type == null"); + } + + if (section == null) { + throw new NullPointerException("section == null"); + } + + if (firstItem == null) { + throw new NullPointerException("firstItem == null"); + } + + if (lastItem == null) { + throw new NullPointerException("lastItem == null"); + } + + if (itemCount <= 0) { + throw new IllegalArgumentException("itemCount <= 0"); + } + + this.type = type; + this.section = section; + this.firstItem = firstItem; + this.lastItem = lastItem; + this.itemCount = itemCount; + } + + /** + * Constructs a self-referential instance. This instance is meant to + * represent the section containing the {@code map_list}. + * + * @param section {@code non-null;} section this instance covers + */ + private MapItem(Section section) { + super(ALIGNMENT, WRITE_SIZE); + + if (section == null) { + throw new NullPointerException("section == null"); + } + + this.type = ItemType.TYPE_MAP_LIST; + this.section = section; + this.firstItem = null; + this.lastItem = null; + this.itemCount = 1; + } + + /** {@inheritDoc} */ + @Override + public ItemType itemType() { + return ItemType.TYPE_MAP_ITEM; + } + + /** {@inheritDoc} */ + @Override + public String toString() { + StringBuffer sb = new StringBuffer(100); + + sb.append(getClass().getName()); + sb.append('{'); + sb.append(section.toString()); + sb.append(' '); + sb.append(type.toHuman()); + sb.append('}'); + + return sb.toString(); + } + + /** {@inheritDoc} */ + @Override + public void addContents(DexFile file) { + // We have nothing to add. + } + + /** {@inheritDoc} */ + @Override + public final String toHuman() { + return toString(); + } + + /** {@inheritDoc} */ + @Override + protected void writeTo0(DexFile file, AnnotatedOutput out) { + int value = type.getMapValue(); + int offset; + + if (firstItem == null) { + offset = section.getFileOffset(); + } else { + offset = section.getAbsoluteItemOffset(firstItem); + } + + if (out.annotates()) { + out.annotate(0, offsetString() + ' ' + type.getTypeName() + + " map"); + out.annotate(2, " type: " + Hex.u2(value) + " // " + + type.toString()); + out.annotate(2, " unused: 0"); + out.annotate(4, " size: " + Hex.u4(itemCount)); + out.annotate(4, " offset: " + Hex.u4(offset)); + } + + out.writeShort(value); + out.writeShort(0); // unused + out.writeInt(itemCount); + out.writeInt(offset); + } +} |