FileDocCategorySizeDatePackage
MixedItemSection.javaAPI DocAndroid 5.1 API10775Thu Mar 12 22:18:30 GMT 2015com.android.dexgen.dex.file

MixedItemSection

public final class MixedItemSection extends Section
A section of a {@code .dex} file which consists of a sequence of {@link OffsettedItem} objects, which may each be of a different concrete class and/or size. Note: It is invalid for an item in an instance of this class to have a larger alignment requirement than the alignment of this instance.

Fields Summary
private static final Comparator
TYPE_SORTER
{@code non-null;} sorter which sorts instances by type
private final ArrayList
items
{@code non-null;} the items in this part
private final HashMap
interns
{@code non-null;} items that have been explicitly interned
private final SortType
sort
{@code non-null;} how to sort the items
private int
writeSize
{@code >= -1;} the current size of this part, in bytes, or {@code -1} if not yet calculated
Constructors Summary
public MixedItemSection(String name, DexFile file, int alignment, SortType sort)
Constructs an instance. The file offset is initially unknown.

param
name {@code null-ok;} the name of this instance, for annotation purposes
param
file {@code non-null;} file that this instance is part of
param
alignment {@code > 0;} alignment requirement for the final output; must be a power of 2
param
sort how the items should be sorted in the final output


                                                                      
          
              
        super(name, file, alignment);

        this.items = new ArrayList<OffsettedItem>(100);
        this.interns = new HashMap<OffsettedItem, OffsettedItem>(100);
        this.sort = sort;
        this.writeSize = -1;
    
Methods Summary
public voidadd(OffsettedItem item)
Adds an item to this instance. This will in turn tell the given item that it has been added to this instance. It is invalid to add the same item to more than one instance, nor to add the same items multiple times to a single instance.

param
item {@code non-null;} the item to add

        throwIfPrepared();

        try {
            if (item.getAlignment() > getAlignment()) {
                throw new IllegalArgumentException(
                        "incompatible item alignment");
            }
        } catch (NullPointerException ex) {
            // Elucidate the exception.
            throw new NullPointerException("item == null");
        }

        items.add(item);
    
public Tget(T item)
Gets an item which was previously interned.

param
item {@code non-null;} the item to look for
return
{@code non-null;} the equivalent already-interned instance

        throwIfNotPrepared();

        OffsettedItem result = interns.get(item);

        if (result != null) {
            return (T) result;
        }

        throw new NoSuchElementException(item.toString());
    
public intgetAbsoluteItemOffset(Item item)
{@inheritDoc}

        OffsettedItem oi = (OffsettedItem) item;
        return oi.getAbsoluteOffset();
    
public Tintern(T item)
Interns an item in this instance, returning the interned instance (which may not be the one passed in). This will add the item if no equal item has been added.

param
item {@code non-null;} the item to intern
return
{@code non-null;} the equivalent interned instance

        throwIfPrepared();

        OffsettedItem result = interns.get(item);

        if (result != null) {
            return (T) result;
        }

        add(item);
        interns.put(item, item);
        return item;
    
public java.util.Collectionitems()
{@inheritDoc}

        return items;
    
public voidplaceItems()
Places all the items in this instance at particular offsets. This will call {@link OffsettedItem#place} on each item. If an item does not know its write size before the call to {@code place}, it is that call which is responsible for setting the write size. This method may only be called once per instance; subsequent calls will throw an exception.

        throwIfNotPrepared();

        switch (sort) {
            case INSTANCE: {
                Collections.sort(items);
                break;
            }
            case TYPE: {
                Collections.sort(items, TYPE_SORTER);
                break;
            }
        }

        int sz = items.size();
        int outAt = 0;
        for (int i = 0; i < sz; i++) {
            OffsettedItem one = items.get(i);
            try {
                int placedAt = one.place(this, outAt);

                if (placedAt < outAt) {
                    throw new RuntimeException("bogus place() result for " +
                            one);
                }

                outAt = placedAt + one.writeSize();
            } catch (RuntimeException ex) {
                throw ExceptionWithContext.withContext(ex,
                        "...while placing " + one);
            }
        }

        writeSize = outAt;
    
protected voidprepare0()
{@inheritDoc}

        DexFile file = getFile();

        /*
         * It's okay for new items to be added as a result of an
         * addContents() call; we just have to deal with the possibility.
         */

        int i = 0;
        for (;;) {
            int sz = items.size();
            if (i >= sz) {
                break;
            }

            for (/*i*/; i < sz; i++) {
                OffsettedItem one = items.get(i);
                one.addContents(file);
            }
        }
    
public intsize()
Gets the size of this instance, in items.

return
{@code >= 0;} the size

        return items.size();
    
public voidwriteHeaderPart(com.android.dexgen.util.AnnotatedOutput out)
Writes the portion of the file header that refers to this instance.

param
out {@code non-null;} where to write

        throwIfNotPrepared();

        if (writeSize == -1) {
            throw new RuntimeException("write size not yet set");
        }

        int sz = writeSize;
        int offset = (sz == 0) ? 0 : getFileOffset();
        String name = getName();

        if (name == null) {
            name = "<unnamed>";
        }

        int spaceCount = 15 - name.length();
        char[] spaceArr = new char[spaceCount];
        Arrays.fill(spaceArr, ' ");
        String spaces = new String(spaceArr);

        if (out.annotates()) {
            out.annotate(4, name + "_size:" + spaces + Hex.u4(sz));
            out.annotate(4, name + "_off: " + spaces + Hex.u4(offset));
        }

        out.writeInt(sz);
        out.writeInt(offset);
    
public voidwriteIndexAnnotation(com.android.dexgen.util.AnnotatedOutput out, ItemType itemType, java.lang.String intro)
Writes an index of contents of the items in this instance of the given type. If there are none, this writes nothing. If there are any, then the index is preceded by the given intro string.

param
out {@code non-null;} where to write to
param
itemType {@code non-null;} the item type of interest
param
intro {@code non-null;} the introductory string for non-empty indices

        throwIfNotPrepared();

        TreeMap<String, OffsettedItem> index =
            new TreeMap<String, OffsettedItem>();

        for (OffsettedItem item : items) {
            if (item.itemType() == itemType) {
                String label = item.toHuman();
                index.put(label, item);
            }
        }

        if (index.size() == 0) {
            return;
        }

        out.annotate(0, intro);

        for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) {
            String label = entry.getKey();
            OffsettedItem item = entry.getValue();
            out.annotate(0, item.offsetString() + ' " + label + '\n");
        }
    
public intwriteSize()
{@inheritDoc}

        throwIfNotPrepared();
        return writeSize;
    
protected voidwriteTo0(com.android.dexgen.util.AnnotatedOutput out)
{@inheritDoc}

        boolean annotates = out.annotates();
        boolean first = true;
        DexFile file = getFile();
        int at = 0;

        for (OffsettedItem one : items) {
            if (annotates) {
                if (first) {
                    first = false;
                } else {
                    out.annotate(0, "\n");
                }
            }

            int alignMask = one.getAlignment() - 1;
            int writeAt = (at + alignMask) & ~alignMask;

            if (at != writeAt) {
                out.writeZeroes(writeAt - at);
                at = writeAt;
            }

            one.writeTo(file, out);
            at += one.writeSize();
        }

        if (at != writeSize) {
            throw new RuntimeException("output size mismatch");
        }