Home | History | Annotate | Download | only in file
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dx.dex.file;
     18 
     19 import com.android.dx.util.AnnotatedOutput;
     20 import com.android.dx.util.Hex;
     21 
     22 import java.util.ArrayList;
     23 
     24 /**
     25  * Class that represents a map item.
     26  */
     27 public final class MapItem extends OffsettedItem {
     28     /** file alignment of this class, in bytes */
     29     private static final int ALIGNMENT = 4;
     30 
     31     /** write size of this class, in bytes: three {@code uint}s */
     32     private static final int WRITE_SIZE = (4 * 3);
     33 
     34     /** {@code non-null;} item type this instance covers */
     35     private final ItemType type;
     36 
     37     /** {@code non-null;} section this instance covers */
     38     private final Section section;
     39 
     40     /**
     41      * {@code null-ok;} first item covered or {@code null} if this is
     42      * a self-reference
     43      */
     44     private final Item firstItem;
     45 
     46     /**
     47      * {@code null-ok;} last item covered or {@code null} if this is
     48      * a self-reference
     49      */
     50     private final Item lastItem;
     51 
     52     /**
     53      * {@code > 0;} count of items covered; {@code 1} if this
     54      * is a self-reference
     55      */
     56     private final int itemCount;
     57 
     58     /**
     59      * Constructs a list item with instances of this class representing
     60      * the contents of the given array of sections, adding it to the
     61      * given map section.
     62      *
     63      * @param sections {@code non-null;} the sections
     64      * @param mapSection {@code non-null;} the section that the resulting map
     65      * should be added to; it should be empty on entry to this method
     66      */
     67     public static void addMap(Section[] sections,
     68             MixedItemSection mapSection) {
     69         if (sections == null) {
     70             throw new NullPointerException("sections == null");
     71         }
     72 
     73         if (mapSection.items().size() != 0) {
     74             throw new IllegalArgumentException(
     75                     "mapSection.items().size() != 0");
     76         }
     77 
     78         ArrayList<MapItem> items = new ArrayList<MapItem>(50);
     79 
     80         for (Section section : sections) {
     81             ItemType currentType = null;
     82             Item firstItem = null;
     83             Item lastItem = null;
     84             int count = 0;
     85 
     86             for (Item item : section.items()) {
     87                 ItemType type = item.itemType();
     88                 if (type != currentType) {
     89                     if (count != 0) {
     90                         items.add(new MapItem(currentType, section,
     91                                         firstItem, lastItem, count));
     92                     }
     93                     currentType = type;
     94                     firstItem = item;
     95                     count = 0;
     96                 }
     97                 lastItem = item;
     98                 count++;
     99             }
    100 
    101             if (count != 0) {
    102                 // Add a MapItem for the final items in the section.
    103                 items.add(new MapItem(currentType, section,
    104                                 firstItem, lastItem, count));
    105             } else if (section == mapSection) {
    106                 // Add a MapItem for the self-referential section.
    107                 items.add(new MapItem(mapSection));
    108             }
    109         }
    110 
    111         mapSection.add(
    112                 new UniformListItem<MapItem>(ItemType.TYPE_MAP_LIST, items));
    113     }
    114 
    115     /**
    116      * Constructs an instance.
    117      *
    118      * @param type {@code non-null;} item type this instance covers
    119      * @param section {@code non-null;} section this instance covers
    120      * @param firstItem {@code non-null;} first item covered
    121      * @param lastItem {@code non-null;} last item covered
    122      * @param itemCount {@code > 0;} count of items covered
    123      */
    124     private MapItem(ItemType type, Section section, Item firstItem,
    125             Item lastItem, int itemCount) {
    126         super(ALIGNMENT, WRITE_SIZE);
    127 
    128         if (type == null) {
    129             throw new NullPointerException("type == null");
    130         }
    131 
    132         if (section == null) {
    133             throw new NullPointerException("section == null");
    134         }
    135 
    136         if (firstItem == null) {
    137             throw new NullPointerException("firstItem == null");
    138         }
    139 
    140         if (lastItem == null) {
    141             throw new NullPointerException("lastItem == null");
    142         }
    143 
    144         if (itemCount <= 0) {
    145             throw new IllegalArgumentException("itemCount <= 0");
    146         }
    147 
    148         this.type = type;
    149         this.section = section;
    150         this.firstItem = firstItem;
    151         this.lastItem = lastItem;
    152         this.itemCount = itemCount;
    153     }
    154 
    155     /**
    156      * Constructs a self-referential instance. This instance is meant to
    157      * represent the section containing the {@code map_list}.
    158      *
    159      * @param section {@code non-null;} section this instance covers
    160      */
    161     private MapItem(Section section) {
    162         super(ALIGNMENT, WRITE_SIZE);
    163 
    164         if (section == null) {
    165             throw new NullPointerException("section == null");
    166         }
    167 
    168         this.type = ItemType.TYPE_MAP_LIST;
    169         this.section = section;
    170         this.firstItem = null;
    171         this.lastItem = null;
    172         this.itemCount = 1;
    173     }
    174 
    175     /** {@inheritDoc} */
    176     @Override
    177     public ItemType itemType() {
    178         return ItemType.TYPE_MAP_ITEM;
    179     }
    180 
    181     /** {@inheritDoc} */
    182     @Override
    183     public String toString() {
    184         StringBuffer sb = new StringBuffer(100);
    185 
    186         sb.append(getClass().getName());
    187         sb.append('{');
    188         sb.append(section.toString());
    189         sb.append(' ');
    190         sb.append(type.toHuman());
    191         sb.append('}');
    192 
    193         return sb.toString();
    194     }
    195 
    196     /** {@inheritDoc} */
    197     @Override
    198     public void addContents(DexFile file) {
    199         // We have nothing to add.
    200     }
    201 
    202     /** {@inheritDoc} */
    203     @Override
    204     public final String toHuman() {
    205         return toString();
    206     }
    207 
    208     /** {@inheritDoc} */
    209     @Override
    210     protected void writeTo0(DexFile file, AnnotatedOutput out) {
    211         int value = type.getMapValue();
    212         int offset;
    213 
    214         if (firstItem == null) {
    215             offset = section.getFileOffset();
    216         } else {
    217             offset = section.getAbsoluteItemOffset(firstItem);
    218         }
    219 
    220         if (out.annotates()) {
    221             out.annotate(0, offsetString() + ' ' + type.getTypeName() +
    222                     " map");
    223             out.annotate(2, "  type:   " + Hex.u2(value) + " // " +
    224                     type.toString());
    225             out.annotate(2, "  unused: 0");
    226             out.annotate(4, "  size:   " + Hex.u4(itemCount));
    227             out.annotate(4, "  offset: " + Hex.u4(offset));
    228         }
    229 
    230         out.writeShort(value);
    231         out.writeShort(0); // unused
    232         out.writeInt(itemCount);
    233         out.writeInt(offset);
    234     }
    235 }
    236