• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
addMap(Section[] sections, MixedItemSection mapSection)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      */
MapItem(ItemType type, Section section, Item firstItem, Item lastItem, int itemCount)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      */
MapItem(Section section)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
itemType()177     public ItemType itemType() {
178         return ItemType.TYPE_MAP_ITEM;
179     }
180 
181     /** {@inheritDoc} */
182     @Override
toString()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
addContents(DexFile file)198     public void addContents(DexFile file) {
199         // We have nothing to add.
200     }
201 
202     /** {@inheritDoc} */
203     @Override
toHuman()204     public final String toHuman() {
205         return toString();
206     }
207 
208     /** {@inheritDoc} */
209     @Override
writeTo0(DexFile file, AnnotatedOutput out)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