• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.res.android;
2 
3 import static com.google.common.primitives.UnsignedBytes.max;
4 import static org.robolectric.res.android.Errors.BAD_INDEX;
5 import static org.robolectric.res.android.Errors.BAD_TYPE;
6 import static org.robolectric.res.android.Errors.BAD_VALUE;
7 import static org.robolectric.res.android.Errors.NO_ERROR;
8 import static org.robolectric.res.android.Errors.NO_MEMORY;
9 import static org.robolectric.res.android.Errors.UNKNOWN_ERROR;
10 import static org.robolectric.res.android.ResourceTypes.RES_STRING_POOL_TYPE;
11 import static org.robolectric.res.android.ResourceTypes.RES_TABLE_LIBRARY_TYPE;
12 import static org.robolectric.res.android.ResourceTypes.RES_TABLE_PACKAGE_TYPE;
13 import static org.robolectric.res.android.ResourceTypes.RES_TABLE_TYPE;
14 import static org.robolectric.res.android.ResourceTypes.RES_TABLE_TYPE_SPEC_TYPE;
15 import static org.robolectric.res.android.ResourceTypes.RES_TABLE_TYPE_TYPE;
16 import static org.robolectric.res.android.ResourceTypes.validate_chunk;
17 import static org.robolectric.res.android.Util.ALOGD;
18 import static org.robolectric.res.android.Util.ALOGE;
19 import static org.robolectric.res.android.Util.ALOGI;
20 import static org.robolectric.res.android.Util.ALOGV;
21 import static org.robolectric.res.android.Util.ALOGW;
22 import static org.robolectric.res.android.Util.LOG_FATAL_IF;
23 import static org.robolectric.res.android.Util.dtohl;
24 import static org.robolectric.res.android.Util.dtohs;
25 import static org.robolectric.res.android.Util.htodl;
26 import static org.robolectric.res.android.Util.htods;
27 import static org.robolectric.res.android.Util.isTruthy;
28 
29 import java.nio.ByteBuffer;
30 import java.nio.ByteOrder;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Objects;
37 import java.util.concurrent.Semaphore;
38 import org.robolectric.res.android.ResourceTypes.ResChunk_header;
39 import org.robolectric.res.android.ResourceTypes.ResTable_entry;
40 import org.robolectric.res.android.ResourceTypes.ResTable_header;
41 import org.robolectric.res.android.ResourceTypes.ResTable_map;
42 import org.robolectric.res.android.ResourceTypes.ResTable_map_entry;
43 import org.robolectric.res.android.ResourceTypes.ResTable_package;
44 import org.robolectric.res.android.ResourceTypes.ResTable_sparseTypeEntry;
45 import org.robolectric.res.android.ResourceTypes.ResTable_type;
46 import org.robolectric.res.android.ResourceTypes.ResTable_typeSpec;
47 import org.robolectric.res.android.ResourceTypes.Res_value;
48 
49 // transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ResourceTypes.cpp
50 //   and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/include/androidfw/ResourceTypes.h
51 @SuppressWarnings("NewApi")
52 public class ResTable {
53 
54   private static final int IDMAP_MAGIC             = 0x504D4449;
55   private static final int IDMAP_CURRENT_VERSION   = 0x00000001;
56 
57   static final int APP_PACKAGE_ID      = 0x7f;
58   static final int SYS_PACKAGE_ID      = 0x01;
59 
60   static final boolean kDebugStringPoolNoisy = false;
61   static final boolean kDebugXMLNoisy = false;
62   static final boolean kDebugTableNoisy = false;
63   static final boolean kDebugTableGetEntry = false;
64   static final boolean kDebugTableSuperNoisy = false;
65   static final boolean kDebugLoadTableNoisy = false;
66   static final boolean kDebugLoadTableSuperNoisy = false;
67   static final boolean kDebugTableTheme = false;
68   static final boolean kDebugResXMLTree = false;
69   static final boolean kDebugLibNoisy = false;
70 
71   private static final Object NULL = null;
72   public static final bag_set SENTINEL_BAG_SET = new bag_set(1);
73 
74   final Semaphore mLock = new Semaphore(1);
75 
76   // Mutex that controls access to the list of pre-filtered configurations
77   // to check when looking up entries.
78   // When iterating over a bag, the mLock mutex is locked. While mLock is locked,
79   // we do resource lookups.
80   // Mutex is not reentrant, so we must use a different lock than mLock.
81   final Object               mFilteredConfigLock = new Object();
82 
83   // type defined in Errors
84   int mError;
85 
86   ResTable_config mParams;
87 
88   // Array of all resource tables.
89   final List<Header>             mHeaders = new ArrayList<>();
90 
91   // Array of packages in all resource tables.
92   final Map<Integer, PackageGroup> mPackageGroups = new HashMap<>();
93 
94   // Mapping from resource package IDs to indices into the internal
95   // package array.
96   final byte[]                     mPackageMap = new byte[256];
97 
98   byte                     mNextPackageId;
99 
Res_CHECKID(int resid)100   static boolean Res_CHECKID(int resid) { return ((resid&0xFFFF0000) != 0);}
Res_GETPACKAGE(int id)101   static int Res_GETPACKAGE(int id) {
102     return ((id>>24)-1);
103   }
Res_GETTYPE(int id)104   public static int Res_GETTYPE(int id) {
105     return (((id>>16)&0xFF)-1);
106   }
Res_GETENTRY(int id)107   static int Res_GETENTRY(int id) {
108     return (id&0xFFFF);
109   }
Res_MAKEARRAY(int entry)110   static int Res_MAKEARRAY(int entry) { return (0x02000000 | (entry&0xFFFF)); }
Res_INTERNALID(int resid)111   static boolean Res_INTERNALID(int resid) { return ((resid&0xFFFF0000) != 0 && (resid&0xFF0000) == 0); }
112 
getResourcePackageIndex(int resID)113   int getResourcePackageIndex(int resID)
114   {
115     return Res_GETPACKAGE(resID) + 1;
116     //return mPackageMap[Res_GETPACKAGE(resID)+1]-1;
117   }
118 
getResourcePackageIndexFromPackage(byte packageID)119   int getResourcePackageIndexFromPackage(byte packageID) {
120     return ((int)mPackageMap[packageID])-1;
121   }
122 
123   //  Errors add(final Object data, int size, final int cookie, boolean copyData) {
124 //    return addInternal(data, size, NULL, 0, false, cookie, copyData);
125 //  }
126 //
127 //  Errors add(final Object data, int size, final Object idmapData, int idmapDataSize,
128 //        final int cookie, boolean copyData, boolean appAsLib) {
129 //    return addInternal(data, size, idmapData, idmapDataSize, appAsLib, cookie, copyData);
130 //  }
131 //
132 //  Errors add(Asset asset, final int cookie, boolean copyData) {
133 //    final Object data = asset.getBuffer(true);
134 //    if (data == NULL) {
135 //      ALOGW("Unable to get buffer of resource asset file");
136 //      return UNKNOWN_ERROR;
137 //    }
138 //
139 //    return addInternal(data, static_cast<int>(asset.getLength()), NULL, false, 0, cookie,
140 //        copyData);
141 //  }
142 
143 //  status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false,
144 //      bool appAsLib=false, bool isSystemAsset=false);
add( Asset asset, Asset idmapAsset, final int cookie, boolean copyData, boolean appAsLib, boolean isSystemAsset)145   int add(
146       Asset asset, Asset idmapAsset, final int cookie, boolean copyData,
147       boolean appAsLib, boolean isSystemAsset) {
148     final byte[] data = asset.getBuffer(true);
149     if (data == NULL) {
150       ALOGW("Unable to get buffer of resource asset file");
151       return UNKNOWN_ERROR;
152     }
153 
154     int idmapSize = 0;
155     Object idmapData = NULL;
156     if (idmapAsset != NULL) {
157       idmapData = idmapAsset.getBuffer(true);
158       if (idmapData == NULL) {
159         ALOGW("Unable to get buffer of idmap asset file");
160         return UNKNOWN_ERROR;
161       }
162       idmapSize = (int) idmapAsset.getLength();
163     }
164 
165     return addInternal(data, (int) asset.getLength(),
166         idmapData, idmapSize, appAsLib, cookie, copyData, isSystemAsset);
167   }
168 
add(ResTable src, boolean isSystemAsset)169   int add(ResTable src, boolean isSystemAsset)
170   {
171     mError = src.mError;
172 
173     for (int i=0; i < src.mHeaders.size(); i++) {
174       mHeaders.add(src.mHeaders.get(i));
175     }
176 
177     for (PackageGroup srcPg : src.mPackageGroups.values()) {
178       PackageGroup pg = new PackageGroup(this, srcPg.name, srcPg.id,
179           false /* appAsLib */, isSystemAsset || srcPg.isSystemAsset, srcPg.isDynamic);
180       for (int j=0; j<srcPg.packages.size(); j++) {
181         pg.packages.add(srcPg.packages.get(j));
182       }
183 
184       for (Integer typeId : srcPg.types.keySet()) {
185         List<Type> typeList = computeIfAbsent(pg.types, typeId, key -> new ArrayList<>());
186         typeList.addAll(srcPg.types.get(typeId));
187       }
188       pg.dynamicRefTable.addMappings(srcPg.dynamicRefTable);
189       pg.largestTypeId = max(pg.largestTypeId, srcPg.largestTypeId);
190       mPackageGroups.put(pg.id, pg);
191     }
192 
193 //    memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
194     System.arraycopy(src.mPackageMap, 0, mPackageMap, 0, mPackageMap.length);
195 
196     return mError;
197   }
198 
addEmpty(final int cookie)199   int addEmpty(final int cookie) {
200     Header header = new Header(this);
201     header.index = mHeaders.size();
202     header.cookie = cookie;
203     header.values.setToEmpty();
204     header.ownedData = new byte[ResTable_header.SIZEOF];
205 
206     ByteBuffer buf = ByteBuffer.wrap(header.ownedData).order(ByteOrder.LITTLE_ENDIAN);
207     ResChunk_header.write(buf, (short) RES_TABLE_TYPE, () -> {}, () -> {});
208 
209     ResTable_header resHeader = new ResTable_header(buf, 0);
210 //    resHeader.header.type = RES_TABLE_TYPE;
211 //    resHeader.header.headerSize = sizeof(ResTable_header);
212 //    resHeader.header.size = sizeof(ResTable_header);
213 
214     header.header = resHeader;
215     mHeaders.add(header);
216     return (mError=NO_ERROR);
217   }
218 
219 //  status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
220 //      bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false);
addInternal(byte[] data, int dataSize, final Object idmapData, int idmapDataSize, boolean appAsLib, final int cookie, boolean copyData, boolean isSystemAsset)221   int addInternal(byte[] data, int dataSize, final Object idmapData, int idmapDataSize,
222       boolean appAsLib, final int cookie, boolean copyData, boolean isSystemAsset)
223   {
224     if (!isTruthy(data)) {
225       return NO_ERROR;
226     }
227 
228     if (dataSize < ResTable_header.SIZEOF) {
229       ALOGE("Invalid data. Size(%d) is smaller than a ResTable_header(%d).",
230           (int) dataSize, (int) ResTable_header.SIZEOF);
231       return UNKNOWN_ERROR;
232     }
233 
234     Header header = new Header(this);
235     header.index = mHeaders.size();
236     header.cookie = cookie;
237     if (idmapData != NULL) {
238       header.resourceIDMap = new int[idmapDataSize / 4];
239       if (header.resourceIDMap == NULL) {
240 //        delete header;
241         return (mError = NO_MEMORY);
242       }
243 //      memcpy(header.resourceIDMap, idmapData, idmapDataSize);
244 //      header.resourceIDMapSize = idmapDataSize;
245     }
246     mHeaders.add(header);
247 
248     final boolean notDeviceEndian = htods((short) 0xf0) != 0xf0;
249 
250     if (kDebugLoadTableNoisy) {
251       ALOGV("Adding resources to ResTable: data=%s, size=0x%x, cookie=%d, copy=%d " +
252           "idmap=%s\n", data, dataSize, cookie, copyData, idmapData);
253     }
254 
255     if (copyData || notDeviceEndian) {
256       header.ownedData = data; // malloc(dataSize);
257       if (header.ownedData == NULL) {
258         return (mError=NO_MEMORY);
259       }
260 //      memcpy(header.ownedData, data, dataSize);
261       data = header.ownedData;
262     }
263 
264     ByteBuffer buf = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
265 //    header->header = (const ResTable_header*)data;
266     header.header = new ResTable_header(buf, 0);
267     header.size = dtohl(header.header.header.size);
268     if (kDebugLoadTableSuperNoisy) {
269       ALOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header.size,
270           dtohl(header.header.header.size), header.header.header.size);
271     }
272     if (kDebugLoadTableNoisy) {
273       ALOGV("Loading ResTable @%s:\n", header.header);
274     }
275     if (dtohs(header.header.header.headerSize) > header.size
276         || header.size > dataSize) {
277       ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
278           (int)dtohs(header.header.header.headerSize),
279           (int)header.size, (int)dataSize);
280       return (mError=BAD_TYPE);
281     }
282     if (((dtohs(header.header.header.headerSize)|header.size)&0x3) != 0) {
283       ALOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n",
284           (int)dtohs(header.header.header.headerSize),
285           (int)header.size);
286       return (mError=BAD_TYPE);
287     }
288 //    header->dataEnd = ((const uint8_t*)header->header) + header->size;
289     header.dataEnd = header.size;
290 
291     // Iterate through all chunks.
292     int curPackage = 0;
293 
294 //    const ResChunk_header* chunk =
295 //      (const ResChunk_header*)(((const uint8_t*)header->header)
296 //    + dtohs(header->header->header.headerSize));
297     ResChunk_header chunk =
298       new ResChunk_header(buf, dtohs(header.header.header.headerSize));
299     while (chunk != null && (chunk.myOffset()) <= (header.dataEnd -ResChunk_header.SIZEOF) &&
300       (chunk.myOffset()) <= (header.dataEnd -dtohl(chunk.size))) {
301     int err = validate_chunk(chunk, ResChunk_header.SIZEOF, header.dataEnd, "ResTable");
302     if (err != NO_ERROR) {
303       return (mError=err);
304     }
305     if (kDebugTableNoisy) {
306       ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%s\n",
307           dtohs(chunk.type), dtohs(chunk.headerSize), dtohl(chunk.size),
308           (Object)((chunk.myOffset()) - (header.header.myOffset())));
309     }
310     final int csize = dtohl(chunk.size);
311     final int ctype = dtohs(chunk.type);
312     if (ctype == RES_STRING_POOL_TYPE) {
313       if (header.values.getError() != NO_ERROR) {
314         // Only use the first string chunk; ignore any others that
315         // may appear.
316         err = header.values.setTo(chunk.myBuf(), chunk.myOffset(), csize, false);
317         if (err != NO_ERROR) {
318           return (mError=err);
319         }
320       } else {
321         ALOGW("Multiple string chunks found in resource table.");
322       }
323     } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
324       if (curPackage >= dtohl(header.header.packageCount)) {
325         ALOGW("More package chunks were found than the %d declared in the header.",
326             dtohl(header.header.packageCount));
327         return (mError=BAD_TYPE);
328       }
329 
330       if (parsePackage(
331           new ResTable_package(chunk.myBuf(), chunk.myOffset()), header, appAsLib, isSystemAsset) != NO_ERROR) {
332         return mError;
333       }
334       curPackage++;
335     } else {
336       ALOGW("Unknown chunk type 0x%x in table at 0x%x.\n",
337           ctype,
338           (chunk.myOffset()) - (header.header.myOffset()));
339     }
340     chunk = chunk.myOffset() + csize < header.dataEnd
341         ? new ResChunk_header(chunk.myBuf(), chunk.myOffset() + csize)
342         : null;
343   }
344 
345     if (curPackage < dtohl(header.header.packageCount)) {
346       ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.",
347           (int)curPackage, dtohl(header.header.packageCount));
348       return (mError=BAD_TYPE);
349     }
350     mError = header.values.getError();
351     if (mError != NO_ERROR) {
352       ALOGW("No string values found in resource table!");
353     }
354 
355     if (kDebugTableNoisy) {
356       ALOGV("Returning from add with mError=%d\n", mError);
357     }
358     return mError;
359   }
360 
361   public final int getResource(int resID, Ref<Res_value> outValue, boolean mayBeBag, int density,
362       final Ref<Integer> outSpecFlags, Ref<ResTable_config> outConfig)
363   {
364     if (mError != NO_ERROR) {
365       return mError;
366     }
367     final int p = getResourcePackageIndex(resID);
368     final int t = Res_GETTYPE(resID);
369     final int e = Res_GETENTRY(resID);
370     if (p < 0) {
371       if (Res_GETPACKAGE(resID)+1 == 0) {
372         ALOGW("No package identifier when getting value for resource number 0x%08x", resID);
373       } else {
374         ALOGW("No known package when getting value for resource number 0x%08x", resID);
375       }
376       return BAD_INDEX;
377     }
378 
379     if (t < 0) {
380       ALOGW("No type identifier when getting value for resource number 0x%08x", resID);
381       return BAD_INDEX;
382     }
383     final PackageGroup grp = mPackageGroups.get(p);
384     if (grp == NULL) {
385       ALOGW("Bad identifier when getting value for resource number 0x%08x", resID);
386       return BAD_INDEX;
387     }
388     // Allow overriding density
389     ResTable_config desiredConfig = mParams;
390     if (density > 0) {
391       desiredConfig.density = density;
392     }
393     Entry entry = new Entry();
394     int err = getEntry(grp, t, e, desiredConfig, entry);
395     if (err != NO_ERROR) {
396       // Only log the failure when we're not running on the host as
397       // part of a tool. The caller will do its own logging.
398       return err;
399     }
400 
401     if ((entry.entry.flags & ResTable_entry.FLAG_COMPLEX) != 0) {
402       if (!mayBeBag) {
403         ALOGW("Requesting resource 0x%08x failed because it is complex\n", resID);
404       }
405       return BAD_VALUE;
406     }
407 
408 //    const Res_value* value = reinterpret_cast<const Res_value*>(
409 //      reinterpret_cast<const uint8_t*>(entry.entry) + entry.entry->size);
410     Res_value value = new Res_value(entry.entry.myBuf(), entry.entry.myOffset() + entry.entry.size);
411 
412 //    outValue.size = dtohs(value.size);
413 //    outValue.res0 = value.res0;
414 //    outValue.dataType = value.dataType;
415 //    outValue.data = dtohl(value.data);
416     outValue.set(value);
417 
418     // The reference may be pointing to a resource in a shared library. These
419     // references have build-time generated package IDs. These ids may not match
420     // the actual package IDs of the corresponding packages in this ResTable.
421     // We need to fix the package ID based on a mapping.
422     if (grp.dynamicRefTable.lookupResourceValue(outValue) != NO_ERROR) {
423       ALOGW("Failed to resolve referenced package: 0x%08x", outValue.get().data);
424       return BAD_VALUE;
425     }
426 
427 //    if (kDebugTableNoisy) {
428 //      size_t len;
429 //      printf("Found value: pkg=0x%x, type=%d, str=%s, int=%d\n",
430 //          entry.package.header.index,
431 //          outValue.dataType,
432 //          outValue.dataType == Res_value::TYPE_STRING ?
433 //              String8(entry.package.header.values.stringAt(outValue.data, &len)).string() :
434 //      "",
435 //          outValue.data);
436 //    }
437 
438     if (outSpecFlags != null) {
439         outSpecFlags.set(entry.specFlags);
440     }
441     if (outConfig != null) {
442         outConfig.set(entry.config);
443     }
444     return entry._package_.header.index;
445   }
446 
447   public final int resolveReference(Ref<Res_value> value, int blockIndex,
448       final Ref<Integer> outLastRef) {
449     return resolveReference(value, blockIndex, outLastRef, null, null);
450   }
451 
452   public final int resolveReference(Ref<Res_value> value, int blockIndex,
453       final Ref<Integer> outLastRef, Ref<Integer> inoutTypeSpecFlags) {
454     return resolveReference(value, blockIndex, outLastRef, inoutTypeSpecFlags, null);
455   }
456 
457   public final int resolveReference(Ref<Res_value> value, int blockIndex,
458       final Ref<Integer> outLastRef, Ref<Integer> inoutTypeSpecFlags,
459       final Ref<ResTable_config> outConfig)
460   {
461     int count=0;
462     while (blockIndex >= 0 && value.get().dataType == DataType.REFERENCE.code()
463         && value.get().data != 0 && count < 20) {
464       if (outLastRef != null) {
465         outLastRef.set(value.get().data);
466       }
467       final Ref<Integer> newFlags = new Ref<>(0);
468       final int newIndex = getResource(value.get().data, value, true, 0,
469           newFlags, outConfig);
470       if (newIndex == BAD_INDEX) {
471         return BAD_INDEX;
472       }
473       if (kDebugTableTheme) {
474         ALOGI("Resolving reference 0x%x: newIndex=%d, type=0x%x, data=0x%x\n",
475             value.get().data, (int)newIndex, (int)value.get().dataType, value.get().data);
476       }
477       //printf("Getting reference 0x%08x: newIndex=%d\n", value.data, newIndex);
478       if (inoutTypeSpecFlags != null) {
479         inoutTypeSpecFlags.set(inoutTypeSpecFlags.get() | newFlags.get());
480       }
481       if (newIndex < 0) {
482         // This can fail if the resource being referenced is a style...
483         // in this case, just return the reference, and expect the
484         // caller to deal with.
485         return blockIndex;
486       }
487       blockIndex = newIndex;
488       count++;
489     }
490     return blockIndex;
491   }
492 
493   private interface Compare {
494     boolean compare(ResTable_sparseTypeEntry a, ResTable_sparseTypeEntry b);
495   }
496 
497   ResTable_sparseTypeEntry lower_bound(ResTable_sparseTypeEntry first, ResTable_sparseTypeEntry last,
498                                        ResTable_sparseTypeEntry value,
499                                        Compare comparator) {
500     int count = (last.myOffset() - first.myOffset()) / ResTable_sparseTypeEntry.SIZEOF;
501     int itOffset;
502     int step;
503     while (count > 0) {
504       itOffset = first.myOffset();
505       step = count / 2;
506       itOffset += step * ResTable_sparseTypeEntry.SIZEOF;
507       if (comparator.compare(new ResTable_sparseTypeEntry(first.myBuf(), itOffset), value)) {
508         itOffset += ResTable_sparseTypeEntry.SIZEOF;
509         first = new ResTable_sparseTypeEntry(first.myBuf(), itOffset);
510       } else {
511         count = step;
512       }
513     }
514     return first;
515   }
516 
517 
518   private int getEntry(
519       final PackageGroup packageGroup, int typeIndex, int entryIndex,
520       final ResTable_config config,
521       Entry outEntry)
522   {
523     final List<Type> typeList = getOrDefault(packageGroup.types, typeIndex, Collections.emptyList());
524     if (typeList.isEmpty()) {
525       ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
526       return BAD_TYPE;
527     }
528 
529     ResTable_type bestType = null;
530     int bestOffset = ResTable_type.NO_ENTRY;
531     Package bestPackage = null;
532     int specFlags = 0;
533     byte actualTypeIndex = (byte) typeIndex;
534     ResTable_config bestConfig = null;
535 //    memset(&bestConfig, 0, sizeof(bestConfig));
536 
537     // Iterate over the Types of each package.
538     final int typeCount = typeList.size();
539     for (int i = 0; i < typeCount; i++) {
540       final Type typeSpec = typeList.get(i);
541 
542       int realEntryIndex = entryIndex;
543       int realTypeIndex = typeIndex;
544       boolean currentTypeIsOverlay = false;
545 
546       // Runtime overlay packages provide a mapping of app resource
547       // ID to package resource ID.
548       if (typeSpec.idmapEntries.hasEntries()) {
549         final Ref<Short> overlayEntryIndex = new Ref<>((short) 0);
550         if (typeSpec.idmapEntries.lookup(entryIndex, overlayEntryIndex) != NO_ERROR) {
551           // No such mapping exists
552           continue;
553         }
554         realEntryIndex = overlayEntryIndex.get();
555         realTypeIndex = typeSpec.idmapEntries.overlayTypeId() - 1;
556         currentTypeIsOverlay = true;
557       }
558 
559       // Check that the entry idx is within range of the declared entry count (ResTable_typeSpec).
560       // Particular types (ResTable_type) may be encoded with sparse entries, and so their
561       // entryCount do not need to match.
562       if (((int) realEntryIndex) >= typeSpec.entryCount) {
563         ALOGW("For resource 0x%08x, entry index(%d) is beyond type entryCount(%d)",
564             Res_MAKEID(packageGroup.id - 1, typeIndex, entryIndex),
565             entryIndex, ((int) typeSpec.entryCount));
566         // We should normally abort here, but some legacy apps declare
567         // resources in the 'android' package (old bug in AAPT).
568         continue;
569       }
570 
571       // Aggregate all the flags for each package that defines this entry.
572       if (typeSpec.typeSpecFlags != null) {
573         specFlags |= dtohl(typeSpec.typeSpecFlags[realEntryIndex]);
574       } else {
575         specFlags = -1;
576       }
577 
578       List<ResTable_type> candidateConfigs = typeSpec.configs;
579 
580 //      List<ResTable_type> filteredConfigs;
581 //      if (isTruthy(config) && Objects.equals(mParams, config)) {
582 //        // Grab the lock first so we can safely get the current filtered list.
583 //        synchronized (mFilteredConfigLock) {
584 //          // This configuration is equal to the one we have previously cached for,
585 //          // so use the filtered configs.
586 //
587 //          final TypeCacheEntry cacheEntry = packageGroup.typeCacheEntries.get(typeIndex);
588 //          if (i < cacheEntry.filteredConfigs.size()) {
589 //            if (isTruthy(cacheEntry.filteredConfigs.get(i))) {
590 //              // Grab a reference to the shared_ptr so it doesn't get destroyed while
591 //              // going through this list.
592 //              filteredConfigs = cacheEntry.filteredConfigs.get(i);
593 //
594 //              // Use this filtered list.
595 //              candidateConfigs = filteredConfigs;
596 //            }
597 //          }
598 //        }
599 //      }
600 
601       final int numConfigs = candidateConfigs.size();
602       for (int c = 0; c < numConfigs; c++) {
603         final ResTable_type thisType = candidateConfigs.get(c);
604         if (thisType == NULL) {
605           continue;
606         }
607 
608         final ResTable_config thisConfig;
609 //        thisConfig.copyFromDtoH(thisType.config);
610         thisConfig = ResTable_config.fromDtoH(thisType.config);
611 
612         // Check to make sure this one is valid for the current parameters.
613         if (config != NULL && !thisConfig.match(config)) {
614           continue;
615         }
616 
617         // const uint32_t* const eindex = reinterpret_cast<const uint32_t*>(
618         // reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize));
619 
620         final int eindex = thisType.myOffset() + dtohs(thisType.header.headerSize);
621 
622         int thisOffset;
623 
624         // Check if there is the desired entry in this type.
625         if (isTruthy(thisType.flags & ResTable_type.FLAG_SPARSE)) {
626           // This is encoded as a sparse map, so perform a binary search.
627           final ByteBuffer buf = thisType.myBuf();
628           ResTable_sparseTypeEntry sparseIndices = new ResTable_sparseTypeEntry(buf, eindex);
629           ResTable_sparseTypeEntry result = lower_bound(
630               sparseIndices,
631               new ResTable_sparseTypeEntry(buf, sparseIndices.myOffset() + dtohl(thisType.entryCount)),
632               new ResTable_sparseTypeEntry(buf, realEntryIndex),
633               (a, b) -> dtohs(a.idxOrOffset) < dtohs(b.idxOrOffset));
634 //          if (result == sparseIndices + dtohl(thisType.entryCount)
635 //              || dtohs(result.idx) != realEntryIndex) {
636           if (result.myOffset() == sparseIndices.myOffset() + dtohl(thisType.entryCount)
637               || dtohs(result.idxOrOffset) != realEntryIndex) {
638             // No entry found.
639             continue;
640           }
641           // Extract the offset from the entry. Each offset must be a multiple of 4
642           // so we store it as the real offset divided by 4.
643 //          thisOffset = dtohs(result->offset) * 4u;
644           thisOffset = dtohs(result.idxOrOffset) * 4;
645         } else {
646           if (realEntryIndex >= dtohl(thisType.entryCount)) {
647             // Entry does not exist.
648             continue;
649           }
650 //          thisOffset = dtohl(eindex[realEntryIndex]);
651           thisOffset = thisType.entryOffset(realEntryIndex);
652         }
653 
654         if (thisOffset == ResTable_type.NO_ENTRY) {
655           // There is no entry for this index and configuration.
656           continue;
657         }
658 
659         if (bestType != NULL) {
660           // Check if this one is less specific than the last found.  If so,
661           // we will skip it.  We check starting with things we most care
662           // about to those we least care about.
663           if (!thisConfig.isBetterThan(bestConfig, config)) {
664             if (!currentTypeIsOverlay || thisConfig.compare(bestConfig) != 0) {
665               continue;
666             }
667           }
668         }
669 
670         bestType = thisType;
671         bestOffset = thisOffset;
672         bestConfig = thisConfig;
673         bestPackage = typeSpec._package_;
674         actualTypeIndex = (byte) realTypeIndex;
675 
676         // If no config was specified, any type will do, so skip
677         if (config == NULL) {
678           break;
679         }
680       }
681     }
682 
683     if (bestType == NULL) {
684       return BAD_INDEX;
685     }
686 
687     bestOffset += dtohl(bestType.entriesStart);
688 
689 //    if (bestOffset > (dtohl(bestType->header.size)-sizeof(ResTable_entry))) {
690     if (bestOffset > (dtohl(bestType.header.size)- ResTable_entry.SIZEOF)) {
691       ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
692           bestOffset, dtohl(bestType.header.size));
693       return BAD_TYPE;
694     }
695     if ((bestOffset & 0x3) != 0) {
696       ALOGW("ResTable_entry at 0x%x is not on an integer boundary", bestOffset);
697       return BAD_TYPE;
698     }
699 
700 //    const ResTable_entry* const entry = reinterpret_cast<const ResTable_entry*>(
701 //      reinterpret_cast<const uint8_t*>(bestType) + bestOffset);
702     final ResTable_entry entry = new ResTable_entry(bestType.myBuf(),
703         bestType.myOffset() + bestOffset);
704     if (dtohs(entry.size) < ResTable_entry.SIZEOF) {
705       ALOGW("ResTable_entry size 0x%x is too small", dtohs(entry.size));
706       return BAD_TYPE;
707     }
708 
709     if (outEntry != null) {
710       outEntry.entry = entry;
711       outEntry.config = bestConfig;
712       outEntry.type = bestType;
713       outEntry.specFlags = specFlags;
714       outEntry._package_ = bestPackage;
715       outEntry.typeStr = new StringPoolRef(bestPackage.typeStrings, actualTypeIndex - bestPackage.typeIdOffset);
716       outEntry.keyStr = new StringPoolRef(bestPackage.keyStrings, dtohl(entry.key.index));
717     }
718     return NO_ERROR;
719   }
720 
721   int parsePackage(ResTable_package pkg,
722                                 Header header, boolean appAsLib, boolean isSystemAsset)
723   {
724     int base = pkg.myOffset();
725     int err = validate_chunk(pkg.header, ResTable_package.SIZEOF - 4 /*sizeof(pkg.typeIdOffset)*/,
726       header.dataEnd, "ResTable_package");
727     if (err != NO_ERROR) {
728       return (mError=err);
729     }
730 
731     final int pkgSize = dtohl(pkg.header.size);
732 
733     if (dtohl(pkg.typeStrings) >= pkgSize) {
734       ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.",
735           dtohl(pkg.typeStrings), pkgSize);
736       return (mError=BAD_TYPE);
737     }
738     if ((dtohl(pkg.typeStrings)&0x3) != 0) {
739       ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.",
740           dtohl(pkg.typeStrings));
741       return (mError=BAD_TYPE);
742     }
743     if (dtohl(pkg.keyStrings) >= pkgSize) {
744       ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.",
745           dtohl(pkg.keyStrings), pkgSize);
746       return (mError=BAD_TYPE);
747     }
748     if ((dtohl(pkg.keyStrings)&0x3) != 0) {
749       ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.",
750           dtohl(pkg.keyStrings));
751       return (mError=BAD_TYPE);
752     }
753 
754     int id = dtohl(pkg.id);
755     final Map<Byte, IdmapEntries> idmapEntries = new HashMap<>();
756 
757     if (header.resourceIDMap != NULL) {
758 //      byte targetPackageId = 0;
759 //      int err = parseIdmap(header.resourceIDMap, header.resourceIDMapSize, &targetPackageId, &idmapEntries);
760 //      if (err != NO_ERROR) {
761 //        ALOGW("Overlay is broken");
762 //        return (mError=err);
763 //      }
764 //      id = targetPackageId;
765     }
766 
767     boolean isDynamic = false;
768     if (id >= 256) {
769 //      LOG_ALWAYS_FATAL("Package id out of range");
770       throw new IllegalStateException("Package id out of range");
771 //      return NO_ERROR;
772     } else if (id == 0 || (id == 0x7f && appAsLib) || isSystemAsset) {
773       // This is a library or a system asset, so assign an ID
774       id = mNextPackageId++;
775       isDynamic = true;
776     }
777 
778     PackageGroup group = null;
779     Package _package = new Package(this, header, pkg);
780     if (_package == NULL) {
781     return (mError=NO_MEMORY);
782   }
783 
784 //    err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
785 //      header->dataEnd-(base+dtohl(pkg->typeStrings)));
786     err = _package.typeStrings.setTo(pkg.myBuf(), base+dtohl(pkg.typeStrings),
787       header.dataEnd -(base+dtohl(pkg.typeStrings)), false);
788     if (err != NO_ERROR) {
789 //      delete group;
790 //      delete _package;
791       return (mError=err);
792     }
793 
794 //    err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
795 //      header->dataEnd-(base+dtohl(pkg->keyStrings)));
796     err = _package.keyStrings.setTo(pkg.myBuf(), base+dtohl(pkg.keyStrings),
797       header.dataEnd -(base+dtohl(pkg.keyStrings)), false);
798     if (err != NO_ERROR) {
799 //      delete group;
800 //      delete _package;
801       return (mError=err);
802     }
803 
804     int idx = mPackageMap[id];
805     if (idx == 0) {
806       idx = mPackageGroups.size() + 1;
807 
808 //      char[] tmpName = new char[pkg.name.length /*sizeof(pkg.name)/sizeof(pkg.name[0])*/];
809 //      strcpy16_dtoh(tmpName, pkg.name, sizeof(pkg.name)/sizeof(pkg.name[0]));
810       group = new PackageGroup(this, new String(pkg.name), id, appAsLib, isSystemAsset, isDynamic);
811       if (group == NULL) {
812 //        delete _package;
813         return (mError=NO_MEMORY);
814       }
815 
816       mPackageGroups.put(group.id, group);
817 //      if (err < NO_ERROR) {
818 //        return (mError=err);
819 //      }
820 
821       mPackageMap[id] = (byte) idx;
822 
823       // Find all packages that reference this package
824 //      int N = mPackageGroups.size();
825 //      for (int i = 0; i < N; i++) {
826       for (PackageGroup packageGroup : mPackageGroups.values()) {
827         packageGroup.dynamicRefTable.addMapping(
828             group.name, (byte) group.id);
829       }
830     } else {
831       group = mPackageGroups.get(idx - 1);
832       if (group == NULL) {
833         return (mError=UNKNOWN_ERROR);
834       }
835     }
836 
837     group.packages.add(_package);
838 //    if (err < NO_ERROR) {
839 //      return (mError=err);
840 //    }
841 
842     // Iterate through all chunks.
843     ResChunk_header chunk =
844       new ResChunk_header(pkg.myBuf(), pkg.myOffset() + dtohs(pkg.header.headerSize));
845 //      const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
846     final int endPos = (pkg.myOffset()) + pkg.header.size;
847 //    while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
848 //      ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
849     while (chunk != null && (chunk.myOffset()) <= (endPos-ResChunk_header.SIZEOF) &&
850       (chunk.myOffset()) <= (endPos-dtohl(chunk.size))) {
851     if (kDebugTableNoisy) {
852       ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%s\n",
853           dtohs(chunk.type), dtohs(chunk.headerSize), dtohl(chunk.size),
854           ((chunk.myOffset()) - (header.header.myOffset())));
855     }
856         final int csize = dtohl(chunk.size);
857         final short ctype = dtohs(chunk.type);
858     if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
859             final ResTable_typeSpec typeSpec = new ResTable_typeSpec(chunk.myBuf(), chunk.myOffset());
860       err = validate_chunk(typeSpec.header, ResTable_typeSpec.SIZEOF,
861       endPos, "ResTable_typeSpec");
862       if (err != NO_ERROR) {
863         return (mError=err);
864       }
865 
866             final int typeSpecSize = dtohl(typeSpec.header.size);
867             final int newEntryCount = dtohl(typeSpec.entryCount);
868 
869       if (kDebugLoadTableNoisy) {
870         ALOGI("TypeSpec off %s: type=0x%x, headerSize=0x%x, size=%s\n",
871             (base-chunk.myOffset()),
872         dtohs(typeSpec.header.type),
873             dtohs(typeSpec.header.headerSize),
874             typeSpecSize);
875       }
876       // look for block overrun or int overflow when multiplying by 4
877       if ((dtohl(typeSpec.entryCount) > (Integer.MAX_VALUE/4 /*sizeof(int)*/)
878           || dtohs(typeSpec.header.headerSize)+(4 /*sizeof(int)*/*newEntryCount)
879           > typeSpecSize)) {
880         ALOGW("ResTable_typeSpec entry index to %s extends beyond chunk end %s.",
881             (dtohs(typeSpec.header.headerSize) + (4 /*sizeof(int)*/*newEntryCount)),
882             typeSpecSize);
883         return (mError=BAD_TYPE);
884       }
885 
886       if (typeSpec.id == 0) {
887         ALOGW("ResTable_type has an id of 0.");
888         return (mError=BAD_TYPE);
889       }
890 
891       if (newEntryCount > 0) {
892         boolean addToType = true;
893         byte typeIndex = (byte) (typeSpec.id - 1);
894         IdmapEntries idmapEntry = idmapEntries.get(typeSpec.id);
895         if (idmapEntry != null) {
896           typeIndex = (byte) (idmapEntry.targetTypeId() - 1);
897         } else if (header.resourceIDMap != NULL) {
898           // This is an overlay, but the types in this overlay are not
899           // overlaying anything according to the idmap. We can skip these
900           // as they will otherwise conflict with the other resources in the package
901           // without a mapping.
902           addToType = false;
903         }
904 
905         if (addToType) {
906           List<Type> typeList = computeIfAbsent(group.types, (int) typeIndex, k -> new ArrayList<>());
907           if (!typeList.isEmpty()) {
908             final Type existingType = typeList.get(0);
909             if (existingType.entryCount != newEntryCount && idmapEntry == null) {
910               ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
911                   (int) newEntryCount, (int) existingType.entryCount);
912               // We should normally abort here, but some legacy apps declare
913               // resources in the 'android' package (old bug in AAPT).
914             }
915           }
916 
917           Type t = new Type(header, _package, newEntryCount);
918           t.typeSpec = typeSpec;
919           t.typeSpecFlags = typeSpec.getSpecFlags();
920           if (idmapEntry != null) {
921             t.idmapEntries = idmapEntry;
922           }
923           typeList.add(t);
924           group.largestTypeId = max(group.largestTypeId, typeSpec.id);
925         }
926       } else {
927         ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec.id);
928       }
929 
930     } else if (ctype == RES_TABLE_TYPE_TYPE) {
931             ResTable_type type = new ResTable_type(chunk.myBuf(), chunk.myOffset());
932       err = validate_chunk(type.header, ResTable_type.SIZEOF_WITHOUT_CONFIG/*-sizeof(ResTable_config)*/+4,
933           endPos, "ResTable_type");
934       if (err != NO_ERROR) {
935         return (mError=err);
936       }
937 
938             final int typeSize = dtohl(type.header.size);
939             final int newEntryCount = dtohl(type.entryCount);
940 
941       if (kDebugLoadTableNoisy) {
942         System.out.println(String.format("Type off 0x%x: type=0x%x, headerSize=0x%x, size=%d\n",
943             base-chunk.myOffset(),
944         dtohs(type.header.type),
945             dtohs(type.header.headerSize),
946             typeSize));
947       }
948       if (dtohs(type.header.headerSize)+(4/*sizeof(int)*/*newEntryCount) > typeSize) {
949         ALOGW("ResTable_type entry index to %s extends beyond chunk end 0x%x.",
950             (dtohs(type.header.headerSize) + (4/*sizeof(int)*/*newEntryCount)),
951             typeSize);
952         return (mError=BAD_TYPE);
953       }
954 
955       if (newEntryCount != 0
956           && dtohl(type.entriesStart) > (typeSize- ResTable_entry.SIZEOF)) {
957         ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.",
958             dtohl(type.entriesStart), typeSize);
959         return (mError=BAD_TYPE);
960       }
961 
962       if (type.id == 0) {
963         ALOGW("ResTable_type has an id of 0.");
964         return (mError=BAD_TYPE);
965       }
966 
967       if (newEntryCount > 0) {
968         boolean addToType = true;
969         byte typeIndex = (byte) (type.id - 1);
970         IdmapEntries idmapEntry = idmapEntries.get(type.id);
971         if (idmapEntry != null) {
972           typeIndex = (byte) (idmapEntry.targetTypeId() - 1);
973         } else if (header.resourceIDMap != NULL) {
974           // This is an overlay, but the types in this overlay are not
975           // overlaying anything according to the idmap. We can skip these
976           // as they will otherwise conflict with the other resources in the package
977           // without a mapping.
978           addToType = false;
979         }
980 
981         if (addToType) {
982           List<Type> typeList = getOrDefault(group.types, (int) typeIndex, Collections.emptyList());
983           if (typeList.isEmpty()) {
984             ALOGE("No TypeSpec for type %d", type.id);
985             return (mError = BAD_TYPE);
986           }
987 
988           Type t = typeList.get(typeList.size() - 1);
989           if (newEntryCount != t.entryCount) {
990             ALOGE("ResTable_type entry count inconsistent: given %d, previously %d",
991                 (int) newEntryCount, (int) t.entryCount);
992             return (mError = BAD_TYPE);
993           }
994 
995           if (t._package_ != _package) {
996             ALOGE("No TypeSpec for type %d", type.id);
997             return (mError = BAD_TYPE);
998           }
999 
1000           t.configs.add(type);
1001 
1002           if (kDebugTableGetEntry) {
1003             ResTable_config thisConfig = ResTable_config.fromDtoH(type.config);
1004             ALOGI("Adding config to type %d: %s\n", type.id,
1005                 thisConfig.toString());
1006           }
1007         }
1008       } else {
1009         ALOGV("Skipping empty ResTable_type for type %d", type.id);
1010       }
1011 
1012     } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
1013       if (group.dynamicRefTable.entries().isEmpty()) {
1014         throw new UnsupportedOperationException("libraries not supported yet");
1015 //       const ResTable_lib_header* lib = (const ResTable_lib_header*) chunk;
1016 //       status_t err = validate_chunk(&lib->header, sizeof(*lib),
1017 //       endPos, "ResTable_lib_header");
1018 //       if (err != NO_ERROR) {
1019 //         return (mError=err);
1020 //       }
1021 //
1022 //       err = group->dynamicRefTable.load(lib);
1023 //       if (err != NO_ERROR) {
1024 //          return (mError=err);
1025 //        }
1026 //
1027 //        // Fill in the reference table with the entries we already know about.
1028 //        size_t N = mPackageGroups.size();
1029 //        for (size_t i = 0; i < N; i++) {
1030 //          group.dynamicRefTable.addMapping(mPackageGroups[i].name, mPackageGroups[i].id);
1031 //        }
1032       } else {
1033         ALOGW("Found multiple library tables, ignoring...");
1034       }
1035     } else {
1036       err = validate_chunk(chunk, ResChunk_header.SIZEOF,
1037           endPos, "ResTable_package:unknown");
1038       if (err != NO_ERROR) {
1039         return (mError=err);
1040       }
1041     }
1042       chunk = chunk.myOffset() + csize < endPos ? new ResChunk_header(chunk.myBuf(), chunk.myOffset() + csize) : null;
1043   }
1044 
1045     return NO_ERROR;
1046   }
1047 
1048   public int getTableCookie(int index) {
1049     return mHeaders.get(index).cookie;
1050   }
1051 
1052   void setParameters(ResTable_config params)
1053   {
1054 //    AutoMutex _lock(mLock);
1055 //    AutoMutex _lock2(mFilteredConfigLock);
1056     synchronized (mLock) {
1057       synchronized (mFilteredConfigLock) {
1058         if (kDebugTableGetEntry) {
1059           ALOGI("Setting parameters: %s\n", params.toString());
1060         }
1061         mParams = params;
1062         for (PackageGroup packageGroup : mPackageGroups.values()) {
1063           if (kDebugTableNoisy) {
1064             ALOGI("CLEARING BAGS FOR GROUP 0x%x!", packageGroup.id);
1065           }
1066           packageGroup.clearBagCache();
1067 
1068           // Find which configurations match the set of parameters. This allows for a much
1069           // faster lookup in getEntry() if the set of values is narrowed down.
1070           //for (int t = 0; t < packageGroup.types.size(); t++) {
1071             //if (packageGroup.types.get(t).isEmpty()) {
1072             //   continue;
1073             // }
1074             //
1075             // List<Type> typeList = packageGroup.types.get(t);
1076         for (List<Type> typeList : packageGroup.types.values()) {
1077           if (typeList.isEmpty()) {
1078                continue;
1079             }
1080 
1081           // Retrieve the cache entry for this type.
1082             //TypeCacheEntry cacheEntry = packageGroup.typeCacheEntries.editItemAt(t);
1083 
1084             for (int ts = 0; ts < typeList.size(); ts++) {
1085               Type type = typeList.get(ts);
1086 
1087 //              std::shared_ptr<Vector<const ResTable_type*>> newFilteredConfigs =
1088 //                  std::make_shared<Vector<const ResTable_type*>>();
1089               List<ResTable_type> newFilteredConfigs = new ArrayList<>();
1090 
1091               for (int ti = 0; ti < type.configs.size(); ti++) {
1092                 ResTable_config config = ResTable_config.fromDtoH(type.configs.get(ti).config);
1093 
1094                 if (config.match(mParams)) {
1095                   newFilteredConfigs.add(type.configs.get(ti));
1096                 }
1097               }
1098 
1099               if (kDebugTableNoisy) {
1100                 ALOGD("Updating pkg=0x%x type=0x%x with 0x%x filtered configs",
1101                     packageGroup.id, ts, newFilteredConfigs.size());
1102               }
1103 
1104               // todo: implement cache
1105 //              cacheEntry.filteredConfigs.add(newFilteredConfigs);
1106             }
1107           }
1108         }
1109       }
1110     }
1111   }
1112 
1113   ResTable_config getParameters()
1114   {
1115 //    mLock.lock();
1116     synchronized (mLock) {
1117       return mParams;
1118     }
1119 //    mLock.unlock();
1120   }
1121 
1122   private static final Map<String, Integer> sInternalNameToIdMap = new HashMap<>();
1123   static {
1124     sInternalNameToIdMap.put("^type", ResTable_map.ATTR_TYPE);
1125     sInternalNameToIdMap.put("^l10n", ResTable_map.ATTR_L10N);
1126     sInternalNameToIdMap.put("^min" , ResTable_map.ATTR_MIN);
1127     sInternalNameToIdMap.put("^max", ResTable_map.ATTR_MAX);
1128     sInternalNameToIdMap.put("^other", ResTable_map.ATTR_OTHER);
1129     sInternalNameToIdMap.put("^zero", ResTable_map.ATTR_ZERO);
1130     sInternalNameToIdMap.put("^one", ResTable_map.ATTR_ONE);
1131     sInternalNameToIdMap.put("^two", ResTable_map.ATTR_TWO);
1132     sInternalNameToIdMap.put("^few", ResTable_map.ATTR_FEW);
1133     sInternalNameToIdMap.put("^many", ResTable_map.ATTR_MANY);
1134   }
1135 
1136   public int identifierForName(String name, String type, String packageName) {
1137     return identifierForName(name, type, packageName, null);
1138   }
1139 
1140   public int identifierForName(String nameString, String type, String packageName,
1141       final Ref<Integer> outTypeSpecFlags) {
1142 //    if (kDebugTableSuperNoisy) {
1143 //      printf("Identifier for name: error=%d\n", mError);
1144 //    }
1145 //    // Check for internal resource identifier as the very first thing, so
1146 //    // that we will always find them even when there are no resources.
1147     if (nameString.startsWith("^")) {
1148       if (sInternalNameToIdMap.containsKey(nameString)) {
1149         if (outTypeSpecFlags != null) {
1150           outTypeSpecFlags.set(ResTable_typeSpec.SPEC_PUBLIC);
1151         }
1152         return sInternalNameToIdMap.get(nameString);
1153       }
1154       if (nameString.length() > 7)
1155         if (nameString.substring(1, 6).equals("index_")) {
1156           int index = Integer.getInteger(nameString.substring(7));
1157           if (Res_CHECKID(index)) {
1158             ALOGW("Array resource index: %d is too large.",
1159                 index);
1160             return 0;
1161           }
1162           if (outTypeSpecFlags != null) {
1163             outTypeSpecFlags.set(ResTable_typeSpec.SPEC_PUBLIC);
1164           }
1165           return  Res_MAKEARRAY(index);
1166         }
1167 
1168       return 0;
1169     }
1170 
1171     if (mError != NO_ERROR) {
1172       return 0;
1173     }
1174 
1175 
1176     // Figure out the package and type we are looking in...
1177     // TODO(BC): The following code block was a best effort attempt to directly transliterate
1178     // C++ code which uses pointer artihmetic. Consider replacing with simpler logic
1179 
1180     boolean fakePublic = false;
1181     char[] name = nameString.toCharArray();
1182     int packageEnd = -1;
1183     int typeEnd = -1;
1184     int nameEnd = name.length;
1185     int pIndex = 0;
1186     while (pIndex < nameEnd) {
1187       char p = name[pIndex];
1188       if (p == ':') packageEnd = pIndex;
1189       else if (p == '/') typeEnd = pIndex;
1190       pIndex++;
1191     }
1192     int nameIndex = 0;
1193     if (name[nameIndex] == '@') {
1194       nameIndex++;
1195       if (name[nameIndex] == '*') {
1196         fakePublic = true;
1197         nameIndex++;
1198     }
1199   }
1200     if (nameIndex >= nameEnd) {
1201       return 0;
1202     }
1203     if (packageEnd != -1) {
1204         packageName = nameString.substring(nameIndex, packageEnd);
1205         nameIndex = packageEnd+1;
1206     } else if (packageName == null) {
1207       return 0;
1208     }
1209     if (typeEnd != -1) {
1210       type = nameString.substring(nameIndex, typeEnd);
1211       nameIndex = typeEnd+1;
1212     } else if (type == null) {
1213       return 0;
1214     }
1215     if (nameIndex >= nameEnd) {
1216       return 0;
1217     }
1218     nameString = nameString.substring(nameIndex, nameEnd);
1219 
1220 //    nameLen = nameEnd-name;
1221 //    if (kDebugTableNoisy) {
1222 //      printf("Looking for identifier: type=%s, name=%s, package=%s\n",
1223 //          String8(type, typeLen).string(),
1224 //          String8(name, nameLen).string(),
1225 //          String8(package, packageLen).string());
1226 //    }
1227     final String attr = "attr";
1228     final String attrPrivate = "^attr-private";
1229     for (PackageGroup group : mPackageGroups.values()) {
1230       if (!Objects.equals(packageName.trim(), group.name.trim())) {
1231         if (kDebugTableNoisy) {
1232            System.out.println(String.format("Skipping package group: %s\n", group.name));
1233         }
1234         continue;
1235       }
1236       for (Package pkg : group.packages) {
1237         String targetType = type;
1238 
1239         do {
1240           int ti = pkg.typeStrings.indexOfString(targetType);
1241           if (ti < 0) {
1242             continue;
1243           }
1244           ti += pkg.typeIdOffset;
1245           int identifier = findEntry(group, ti, nameString, outTypeSpecFlags);
1246           if (identifier != 0) {
1247             if (fakePublic && outTypeSpecFlags != null) {
1248                         outTypeSpecFlags.set(outTypeSpecFlags.get() | ResTable_typeSpec.SPEC_PUBLIC);
1249             }
1250             return identifier;
1251           }
1252         } while (attr.compareTo(targetType) == 0
1253             && ((targetType = attrPrivate) != null)
1254             );
1255       }
1256       break;
1257     }
1258     return 0;
1259   }
1260 
1261   int findEntry(PackageGroup group, int typeIndex, String name, Ref<Integer> outTypeSpecFlags) {
1262     List<Type> typeList = getOrDefault(group.types, typeIndex, Collections.emptyList());
1263     for (Type type : typeList) {
1264       int ei = type._package_.keyStrings.indexOfString(name);
1265       if (ei < 0) {
1266         continue;
1267       }
1268       for (ResTable_type resTableType : type.configs) {
1269         int entryIndex = resTableType.findEntryByResName(ei);
1270         if (entryIndex >= 0) {
1271           int resId = Res_MAKEID(group.id - 1, typeIndex, entryIndex);
1272           if (outTypeSpecFlags != null) {
1273             Entry result = new Entry();
1274             if (getEntry(group, typeIndex, entryIndex, null, result) != NO_ERROR) {
1275               ALOGW("Failed to find spec flags for 0x%08x", resId);
1276               return 0;
1277             }
1278             outTypeSpecFlags.set(result.specFlags);
1279           }
1280           return resId;
1281         }
1282       }
1283     }
1284     return 0;
1285   }
1286 
1287 //bool ResTable::expandResourceRef(const char16_t* refStr, size_t refLen,
1288 //                                 String16* outPackage,
1289 //                                 String16* outType,
1290 //                                 String16* outName,
1291 //                                 const String16* defType,
1292 //                                 const String16* defPackage,
1293 //                                 const char** outErrorMsg,
1294 //                                 bool* outPublicOnly)
1295 //{
1296 //    const char16_t* packageEnd = NULL;
1297 //    const char16_t* typeEnd = NULL;
1298 //    const char16_t* p = refStr;
1299 //    const char16_t* const end = p + refLen;
1300 //    while (p < end) {
1301 //        if (*p == ':') packageEnd = p;
1302 //        else if (*p == '/') {
1303 //            typeEnd = p;
1304 //            break;
1305 //        }
1306 //        p++;
1307 //    }
1308 //    p = refStr;
1309 //    if (*p == '@') p++;
1310 //
1311 //    if (outPublicOnly != NULL) {
1312 //        *outPublicOnly = true;
1313 //    }
1314 //    if (*p == '*') {
1315 //        p++;
1316 //        if (outPublicOnly != NULL) {
1317 //            *outPublicOnly = false;
1318 //        }
1319 //    }
1320 //
1321 //    if (packageEnd) {
1322 //        *outPackage = String16(p, packageEnd-p);
1323 //        p = packageEnd+1;
1324 //    } else {
1325 //        if (!defPackage) {
1326 //            if (outErrorMsg) {
1327 //                *outErrorMsg = "No resource package specified";
1328 //            }
1329 //            return false;
1330 //        }
1331 //        *outPackage = *defPackage;
1332 //    }
1333 //    if (typeEnd) {
1334 //        *outType = String16(p, typeEnd-p);
1335 //        p = typeEnd+1;
1336 //    } else {
1337 //        if (!defType) {
1338 //            if (outErrorMsg) {
1339 //                *outErrorMsg = "No resource type specified";
1340 //            }
1341 //            return false;
1342 //        }
1343 //        *outType = *defType;
1344 //    }
1345 //    *outName = String16(p, end-p);
1346 //    if(**outPackage == 0) {
1347 //        if(outErrorMsg) {
1348 //            *outErrorMsg = "Resource package cannot be an empty string";
1349 //        }
1350 //        return false;
1351 //    }
1352 //    if(**outType == 0) {
1353 //        if(outErrorMsg) {
1354 //            *outErrorMsg = "Resource type cannot be an empty string";
1355 //        }
1356 //        return false;
1357 //    }
1358 //    if(**outName == 0) {
1359 //        if(outErrorMsg) {
1360 //            *outErrorMsg = "Resource id cannot be an empty string";
1361 //        }
1362 //        return false;
1363 //    }
1364 //    return true;
1365 //}
1366 //
1367 //static uint32_t get_hex(char c, bool* outError)
1368 //{
1369 //    if (c >= '0' && c <= '9') {
1370 //        return c - '0';
1371 //    } else if (c >= 'a' && c <= 'f') {
1372 //        return c - 'a' + 0xa;
1373 //    } else if (c >= 'A' && c <= 'F') {
1374 //        return c - 'A' + 0xa;
1375 //    }
1376 //    *outError = true;
1377 //    return 0;
1378 //}
1379 //
1380 //struct unit_entry
1381 //{
1382 //    const char* name;
1383 //    size_t len;
1384 //    uint8_t type;
1385 //    uint32_t unit;
1386 //    float scale;
1387 //};
1388 //
1389 //static const unit_entry unitNames[] = {
1390 //    { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f },
1391 //    { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
1392 //    { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
1393 //    { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f },
1394 //    { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f },
1395 //    { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f },
1396 //    { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f },
1397 //    { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 },
1398 //    { "%s", strlen("%s"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 },
1399 //    { NULL, 0, 0, 0, 0 }
1400 //};
1401 //
1402 //static bool parse_unit(const char* str, Res_value* outValue,
1403 //                       float* outScale, const char** outEnd)
1404 //{
1405 //    const char* end = str;
1406 //    while (*end != 0 && !isspace((unsigned char)*end)) {
1407 //        end++;
1408 //    }
1409 //    const size_t len = end-str;
1410 //
1411 //    const char* realEnd = end;
1412 //    while (*realEnd != 0 && isspace((unsigned char)*realEnd)) {
1413 //        realEnd++;
1414 //    }
1415 //    if (*realEnd != 0) {
1416 //        return false;
1417 //    }
1418 //
1419 //    const unit_entry* cur = unitNames;
1420 //    while (cur->name) {
1421 //        if (len == cur->len && strncmp(cur->name, str, len) == 0) {
1422 //            outValue->dataType = cur->type;
1423 //            outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT;
1424 //            *outScale = cur->scale;
1425 //            *outEnd = end;
1426 //            //printf("Found unit %s for %s\n", cur->name, str);
1427 //            return true;
1428 //        }
1429 //        cur++;
1430 //    }
1431 //
1432 //    return false;
1433 //}
1434 //
1435 //bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue)
1436 //{
1437 //    while (len > 0 && isspace16(*s)) {
1438 //        s++;
1439 //        len--;
1440 //    }
1441 //
1442 //    if (len <= 0) {
1443 //        return false;
1444 //    }
1445 //
1446 //    size_t i = 0;
1447 //    int64_t val = 0;
1448 //    bool neg = false;
1449 //
1450 //    if (*s == '-') {
1451 //        neg = true;
1452 //        i++;
1453 //    }
1454 //
1455 //    if (s[i] < '0' || s[i] > '9') {
1456 //        return false;
1457 //    }
1458 //
1459 //    static_assert(std::is_same<uint32_t, Res_value::data_type>::value,
1460 //                  "Res_value::data_type has changed. The range checks in this "
1461 //                  "function are no longer correct.");
1462 //
1463 //    // Decimal or hex?
1464 //    bool isHex;
1465 //    if (len > 1 && s[i] == '0' && s[i+1] == 'x') {
1466 //        isHex = true;
1467 //        i += 2;
1468 //
1469 //        if (neg) {
1470 //            return false;
1471 //        }
1472 //
1473 //        if (i == len) {
1474 //            // Just u"0x"
1475 //            return false;
1476 //        }
1477 //
1478 //        bool error = false;
1479 //        while (i < len && !error) {
1480 //            val = (val*16) + get_hex(s[i], &error);
1481 //            i++;
1482 //
1483 //            if (val > std::numeric_limits<uint32_t>::max()) {
1484 //                return false;
1485 //            }
1486 //        }
1487 //        if (error) {
1488 //            return false;
1489 //        }
1490 //    } else {
1491 //        isHex = false;
1492 //        while (i < len) {
1493 //            if (s[i] < '0' || s[i] > '9') {
1494 //                return false;
1495 //            }
1496 //            val = (val*10) + s[i]-'0';
1497 //            i++;
1498 //
1499 //            if ((neg && -val < std::numeric_limits<int32_t>::min()) ||
1500 //                (!neg && val > std::numeric_limits<int32_t>::max())) {
1501 //                return false;
1502 //            }
1503 //        }
1504 //    }
1505 //
1506 //    if (neg) val = -val;
1507 //
1508 //    while (i < len && isspace16(s[i])) {
1509 //        i++;
1510 //    }
1511 //
1512 //    if (i != len) {
1513 //        return false;
1514 //    }
1515 //
1516 //    if (outValue) {
1517 //        outValue->dataType =
1518 //            isHex ? outValue->TYPE_INT_HEX : outValue->TYPE_INT_DEC;
1519 //        outValue->data = static_cast<Res_value::data_type>(val);
1520 //    }
1521 //    return true;
1522 //}
1523 //
1524 //bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
1525 //{
1526 //    return U16StringToInt(s, len, outValue);
1527 //}
1528 //
1529 //bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
1530 //{
1531 //    while (len > 0 && isspace16(*s)) {
1532 //        s++;
1533 //        len--;
1534 //    }
1535 //
1536 //    if (len <= 0) {
1537 //        return false;
1538 //    }
1539 //
1540 //    char buf[128];
1541 //    int i=0;
1542 //    while (len > 0 && *s != 0 && i < 126) {
1543 //        if (*s > 255) {
1544 //            return false;
1545 //        }
1546 //        buf[i++] = *s++;
1547 //        len--;
1548 //    }
1549 //
1550 //    if (len > 0) {
1551 //        return false;
1552 //    }
1553 //    if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') {
1554 //        return false;
1555 //    }
1556 //
1557 //    buf[i] = 0;
1558 //    const char* end;
1559 //    float f = strtof(buf, (char**)&end);
1560 //
1561 //    if (*end != 0 && !isspace((unsigned char)*end)) {
1562 //        // Might be a unit...
1563 //        float scale;
1564 //        if (parse_unit(end, outValue, &scale, &end)) {
1565 //            f *= scale;
1566 //            const bool neg = f < 0;
1567 //            if (neg) f = -f;
1568 //            uint64_t bits = (uint64_t)(f*(1<<23)+.5f);
1569 //            uint32_t radix;
1570 //            uint32_t shift;
1571 //            if ((bits&0x7fffff) == 0) {
1572 //                // Always use 23p0 if there is no fraction, just to make
1573 //                // things easier to read.
1574 //                radix = Res_value::COMPLEX_RADIX_23p0;
1575 //                shift = 23;
1576 //            } else if ((bits&0xffffffffff800000LL) == 0) {
1577 //                // Magnitude is zero -- can fit in 0 bits of precision.
1578 //                radix = Res_value::COMPLEX_RADIX_0p23;
1579 //                shift = 0;
1580 //            } else if ((bits&0xffffffff80000000LL) == 0) {
1581 //                // Magnitude can fit in 8 bits of precision.
1582 //                radix = Res_value::COMPLEX_RADIX_8p15;
1583 //                shift = 8;
1584 //            } else if ((bits&0xffffff8000000000LL) == 0) {
1585 //                // Magnitude can fit in 16 bits of precision.
1586 //                radix = Res_value::COMPLEX_RADIX_16p7;
1587 //                shift = 16;
1588 //            } else {
1589 //                // Magnitude needs entire range, so no fractional part.
1590 //                radix = Res_value::COMPLEX_RADIX_23p0;
1591 //                shift = 23;
1592 //            }
1593 //            int32_t mantissa = (int32_t)(
1594 //                (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK);
1595 //            if (neg) {
1596 //                mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK;
1597 //            }
1598 //            outValue->data |=
1599 //                (radix<<Res_value::COMPLEX_RADIX_SHIFT)
1600 //                | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT);
1601 //            //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n",
1602 //            //       f * (neg ? -1 : 1), bits, f*(1<<23),
1603 //            //       radix, shift, outValue->data);
1604 //            return true;
1605 //        }
1606 //        return false;
1607 //    }
1608 //
1609 //    while (*end != 0 && isspace((unsigned char)*end)) {
1610 //        end++;
1611 //    }
1612 //
1613 //    if (*end == 0) {
1614 //        if (outValue) {
1615 //            outValue->dataType = outValue->TYPE_FLOAT;
1616 //            *(float*)(&outValue->data) = f;
1617 //            return true;
1618 //        }
1619 //    }
1620 //
1621 //    return false;
1622 //}
1623 //
1624 //bool ResTable::stringToValue(Res_value* outValue, String16* outString,
1625 //                             const char16_t* s, size_t len,
1626 //                             bool preserveSpaces, bool coerceType,
1627 //                             uint32_t attrID,
1628 //                             const String16* defType,
1629 //                             const String16* defPackage,
1630 //                             Accessor* accessor,
1631 //                             void* accessorCookie,
1632 //                             uint32_t attrType,
1633 //                             bool enforcePrivate) const
1634 //{
1635 //    bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting();
1636 //    const char* errorMsg = NULL;
1637 //
1638 //    outValue->size = sizeof(Res_value);
1639 //    outValue->res0 = 0;
1640 //
1641 //    // First strip leading/trailing whitespace.  Do this before handling
1642 //    // escapes, so they can be used to force whitespace into the string.
1643 //    if (!preserveSpaces) {
1644 //        while (len > 0 && isspace16(*s)) {
1645 //            s++;
1646 //            len--;
1647 //        }
1648 //        while (len > 0 && isspace16(s[len-1])) {
1649 //            len--;
1650 //        }
1651 //        // If the string ends with '\', then we keep the space after it.
1652 //        if (len > 0 && s[len-1] == '\\' && s[len] != 0) {
1653 //            len++;
1654 //        }
1655 //    }
1656 //
1657 //    //printf("Value for: %s\n", String8(s, len).string());
1658 //
1659 //    uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
1660 //    uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
1661 //    bool fromAccessor = false;
1662 //    if (attrID != 0 && !Res_INTERNALID(attrID)) {
1663 //        const ssize_t p = getResourcePackageIndex(attrID);
1664 //        const bag_entry* bag;
1665 //        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
1666 //        //printf("For attr 0x%08x got bag of %d\n", attrID, cnt);
1667 //        if (cnt >= 0) {
1668 //            while (cnt > 0) {
1669 //                //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data);
1670 //                switch (bag->map.name.ident) {
1671 //                case ResTable_map::ATTR_TYPE:
1672 //                    attrType = bag->map.value.data;
1673 //                    break;
1674 //                case ResTable_map::ATTR_MIN:
1675 //                    attrMin = bag->map.value.data;
1676 //                    break;
1677 //                case ResTable_map::ATTR_MAX:
1678 //                    attrMax = bag->map.value.data;
1679 //                    break;
1680 //                case ResTable_map::ATTR_L10N:
1681 //                    l10nReq = bag->map.value.data;
1682 //                    break;
1683 //                }
1684 //                bag++;
1685 //                cnt--;
1686 //            }
1687 //            unlockBag(bag);
1688 //        } else if (accessor && accessor->getAttributeType(attrID, &attrType)) {
1689 //            fromAccessor = true;
1690 //            if (attrType == ResTable_map::TYPE_ENUM
1691 //                    || attrType == ResTable_map::TYPE_FLAGS
1692 //                    || attrType == ResTable_map::TYPE_INTEGER) {
1693 //                accessor->getAttributeMin(attrID, &attrMin);
1694 //                accessor->getAttributeMax(attrID, &attrMax);
1695 //            }
1696 //            if (localizationSetting) {
1697 //                l10nReq = accessor->getAttributeL10N(attrID);
1698 //            }
1699 //        }
1700 //    }
1701 //
1702 //    const bool canStringCoerce =
1703 //        coerceType && (attrType&ResTable_map::TYPE_STRING) != 0;
1704 //
1705 //    if (*s == '@') {
1706 //        outValue->dataType = outValue->TYPE_REFERENCE;
1707 //
1708 //        // Note: we don't check attrType here because the reference can
1709 //        // be to any other type; we just need to count on the client making
1710 //        // sure the referenced type is correct.
1711 //
1712 //        //printf("Looking up ref: %s\n", String8(s, len).string());
1713 //
1714 //        // It's a reference!
1715 //        if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
1716 //            // Special case @null as undefined. This will be converted by
1717 //            // AssetManager to TYPE_NULL with data DATA_NULL_UNDEFINED.
1718 //            outValue->data = 0;
1719 //            return true;
1720 //        } else if (len == 6 && s[1]=='e' && s[2]=='m' && s[3]=='p' && s[4]=='t' && s[5]=='y') {
1721 //            // Special case @empty as explicitly defined empty value.
1722 //            outValue->dataType = Res_value::TYPE_NULL;
1723 //            outValue->data = Res_value::DATA_NULL_EMPTY;
1724 //            return true;
1725 //        } else {
1726 //            bool createIfNotFound = false;
1727 //            const char16_t* resourceRefName;
1728 //            int resourceNameLen;
1729 //            if (len > 2 && s[1] == '+') {
1730 //                createIfNotFound = true;
1731 //                resourceRefName = s + 2;
1732 //                resourceNameLen = len - 2;
1733 //            } else if (len > 2 && s[1] == '*') {
1734 //                enforcePrivate = false;
1735 //                resourceRefName = s + 2;
1736 //                resourceNameLen = len - 2;
1737 //            } else {
1738 //                createIfNotFound = false;
1739 //                resourceRefName = s + 1;
1740 //                resourceNameLen = len - 1;
1741 //            }
1742 //            String16 package, type, name;
1743 //            if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name,
1744 //                                   defType, defPackage, &errorMsg)) {
1745 //                if (accessor != NULL) {
1746 //                    accessor->reportError(accessorCookie, errorMsg);
1747 //                }
1748 //                return false;
1749 //            }
1750 //
1751 //            uint32_t specFlags = 0;
1752 //            uint32_t rid = identifierForName(name.string(), name.size(), type.string(),
1753 //                    type.size(), package.string(), package.size(), &specFlags);
1754 //            if (rid != 0) {
1755 //                if (enforcePrivate) {
1756 //                    if (accessor == NULL || accessor->getAssetsPackage() != package) {
1757 //                        if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
1758 //                            if (accessor != NULL) {
1759 //                                accessor->reportError(accessorCookie, "Resource is not public.");
1760 //                            }
1761 //                            return false;
1762 //                        }
1763 //                    }
1764 //                }
1765 //
1766 //                if (accessor) {
1767 //                    rid = Res_MAKEID(
1768 //                        accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
1769 //                        Res_GETTYPE(rid), Res_GETENTRY(rid));
1770 //                    if (kDebugTableNoisy) {
1771 //                        ALOGI("Incl %s:%s/%s: 0x%08x\n",
1772 //                                String8(package).string(), String8(type).string(),
1773 //                                String8(name).string(), rid);
1774 //                    }
1775 //                }
1776 //
1777 //                uint32_t packageId = Res_GETPACKAGE(rid) + 1;
1778 //                if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
1779 //                    outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
1780 //                }
1781 //                outValue->data = rid;
1782 //                return true;
1783 //            }
1784 //
1785 //            if (accessor) {
1786 //                uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
1787 //                                                                       createIfNotFound);
1788 //                if (rid != 0) {
1789 //                    if (kDebugTableNoisy) {
1790 //                        ALOGI("Pckg %s:%s/%s: 0x%08x\n",
1791 //                                String8(package).string(), String8(type).string(),
1792 //                                String8(name).string(), rid);
1793 //                    }
1794 //                    uint32_t packageId = Res_GETPACKAGE(rid) + 1;
1795 //                    if (packageId == 0x00) {
1796 //                        outValue->data = rid;
1797 //                        outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
1798 //                        return true;
1799 //                    } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
1800 //                        // We accept packageId's generated as 0x01 in order to support
1801 //                        // building the android system resources
1802 //                        outValue->data = rid;
1803 //                        return true;
1804 //                    }
1805 //                }
1806 //            }
1807 //        }
1808 //
1809 //        if (accessor != NULL) {
1810 //            accessor->reportError(accessorCookie, "No resource found that matches the given name");
1811 //        }
1812 //        return false;
1813 //    }
1814 //
1815 //    // if we got to here, and localization is required and it's not a reference,
1816 //    // complain and bail.
1817 //    if (l10nReq == ResTable_map::L10N_SUGGESTED) {
1818 //        if (localizationSetting) {
1819 //            if (accessor != NULL) {
1820 //                accessor->reportError(accessorCookie, "This attribute must be localized.");
1821 //            }
1822 //        }
1823 //    }
1824 //
1825 //    if (*s == '#') {
1826 //        // It's a color!  Convert to an integer of the form 0xaarrggbb.
1827 //        uint32_t color = 0;
1828 //        bool error = false;
1829 //        if (len == 4) {
1830 //            outValue->dataType = outValue->TYPE_INT_COLOR_RGB4;
1831 //            color |= 0xFF000000;
1832 //            color |= get_hex(s[1], &error) << 20;
1833 //            color |= get_hex(s[1], &error) << 16;
1834 //            color |= get_hex(s[2], &error) << 12;
1835 //            color |= get_hex(s[2], &error) << 8;
1836 //            color |= get_hex(s[3], &error) << 4;
1837 //            color |= get_hex(s[3], &error);
1838 //        } else if (len == 5) {
1839 //            outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4;
1840 //            color |= get_hex(s[1], &error) << 28;
1841 //            color |= get_hex(s[1], &error) << 24;
1842 //            color |= get_hex(s[2], &error) << 20;
1843 //            color |= get_hex(s[2], &error) << 16;
1844 //            color |= get_hex(s[3], &error) << 12;
1845 //            color |= get_hex(s[3], &error) << 8;
1846 //            color |= get_hex(s[4], &error) << 4;
1847 //            color |= get_hex(s[4], &error);
1848 //        } else if (len == 7) {
1849 //            outValue->dataType = outValue->TYPE_INT_COLOR_RGB8;
1850 //            color |= 0xFF000000;
1851 //            color |= get_hex(s[1], &error) << 20;
1852 //            color |= get_hex(s[2], &error) << 16;
1853 //            color |= get_hex(s[3], &error) << 12;
1854 //            color |= get_hex(s[4], &error) << 8;
1855 //            color |= get_hex(s[5], &error) << 4;
1856 //            color |= get_hex(s[6], &error);
1857 //        } else if (len == 9) {
1858 //            outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8;
1859 //            color |= get_hex(s[1], &error) << 28;
1860 //            color |= get_hex(s[2], &error) << 24;
1861 //            color |= get_hex(s[3], &error) << 20;
1862 //            color |= get_hex(s[4], &error) << 16;
1863 //            color |= get_hex(s[5], &error) << 12;
1864 //            color |= get_hex(s[6], &error) << 8;
1865 //            color |= get_hex(s[7], &error) << 4;
1866 //            color |= get_hex(s[8], &error);
1867 //        } else {
1868 //            error = true;
1869 //        }
1870 //        if (!error) {
1871 //            if ((attrType&ResTable_map::TYPE_COLOR) == 0) {
1872 //                if (!canStringCoerce) {
1873 //                    if (accessor != NULL) {
1874 //                        accessor->reportError(accessorCookie,
1875 //                                "Color types not allowed");
1876 //                    }
1877 //                    return false;
1878 //                }
1879 //            } else {
1880 //                outValue->data = color;
1881 //                //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color);
1882 //                return true;
1883 //            }
1884 //        } else {
1885 //            if ((attrType&ResTable_map::TYPE_COLOR) != 0) {
1886 //                if (accessor != NULL) {
1887 //                    accessor->reportError(accessorCookie, "Color value not valid --"
1888 //                            " must be #rgb, #argb, #rrggbb, or #aarrggbb");
1889 //                }
1890 //                #if 0
1891 //                fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
1892 //                        "Resource File", //(const char*)in->getPrintableSource(),
1893 //                        String8(*curTag).string(),
1894 //                        String8(s, len).string());
1895 //                #endif
1896 //                return false;
1897 //            }
1898 //        }
1899 //    }
1900 //
1901 //    if (*s == '?') {
1902 //        outValue->dataType = outValue->TYPE_ATTRIBUTE;
1903 //
1904 //        // Note: we don't check attrType here because the reference can
1905 //        // be to any other type; we just need to count on the client making
1906 //        // sure the referenced type is correct.
1907 //
1908 //        //printf("Looking up attr: %s\n", String8(s, len).string());
1909 //
1910 //        static const String16 attr16("attr");
1911 //        String16 package, type, name;
1912 //        if (!expandResourceRef(s+1, len-1, &package, &type, &name,
1913 //                               &attr16, defPackage, &errorMsg)) {
1914 //            if (accessor != NULL) {
1915 //                accessor->reportError(accessorCookie, errorMsg);
1916 //            }
1917 //            return false;
1918 //        }
1919 //
1920 //        //printf("Pkg: %s, Type: %s, Name: %s\n",
1921 //        //       String8(package).string(), String8(type).string(),
1922 //        //       String8(name).string());
1923 //        uint32_t specFlags = 0;
1924 //        uint32_t rid =
1925 //            identifierForName(name.string(), name.size(),
1926 //                              type.string(), type.size(),
1927 //                              package.string(), package.size(), &specFlags);
1928 //        if (rid != 0) {
1929 //            if (enforcePrivate) {
1930 //                if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
1931 //                    if (accessor != NULL) {
1932 //                        accessor->reportError(accessorCookie, "Attribute is not public.");
1933 //                    }
1934 //                    return false;
1935 //                }
1936 //            }
1937 //
1938 //            if (accessor) {
1939 //                rid = Res_MAKEID(
1940 //                    accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
1941 //                    Res_GETTYPE(rid), Res_GETENTRY(rid));
1942 //            }
1943 //
1944 //            uint32_t packageId = Res_GETPACKAGE(rid) + 1;
1945 //            if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
1946 //                outValue->dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
1947 //            }
1948 //            outValue->data = rid;
1949 //            return true;
1950 //        }
1951 //
1952 //        if (accessor) {
1953 //            uint32_t rid = accessor->getCustomResource(package, type, name);
1954 //            if (rid != 0) {
1955 //                uint32_t packageId = Res_GETPACKAGE(rid) + 1;
1956 //                if (packageId == 0x00) {
1957 //                    outValue->data = rid;
1958 //                    outValue->dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
1959 //                    return true;
1960 //                } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
1961 //                    // We accept packageId's generated as 0x01 in order to support
1962 //                    // building the android system resources
1963 //                    outValue->data = rid;
1964 //                    return true;
1965 //                }
1966 //            }
1967 //        }
1968 //
1969 //        if (accessor != NULL) {
1970 //            accessor->reportError(accessorCookie, "No resource found that matches the given name");
1971 //        }
1972 //        return false;
1973 //    }
1974 //
1975 //    if (stringToInt(s, len, outValue)) {
1976 //        if ((attrType&ResTable_map::TYPE_INTEGER) == 0) {
1977 //            // If this type does not allow integers, but does allow floats,
1978 //            // fall through on this error case because the float type should
1979 //            // be able to accept any integer value.
1980 //            if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) {
1981 //                if (accessor != NULL) {
1982 //                    accessor->reportError(accessorCookie, "Integer types not allowed");
1983 //                }
1984 //                return false;
1985 //            }
1986 //        } else {
1987 //            if (((int32_t)outValue->data) < ((int32_t)attrMin)
1988 //                    || ((int32_t)outValue->data) > ((int32_t)attrMax)) {
1989 //                if (accessor != NULL) {
1990 //                    accessor->reportError(accessorCookie, "Integer value out of range");
1991 //                }
1992 //                return false;
1993 //            }
1994 //            return true;
1995 //        }
1996 //    }
1997 //
1998 //    if (stringToFloat(s, len, outValue)) {
1999 //        if (outValue->dataType == Res_value::TYPE_DIMENSION) {
2000 //            if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) {
2001 //                return true;
2002 //            }
2003 //            if (!canStringCoerce) {
2004 //                if (accessor != NULL) {
2005 //                    accessor->reportError(accessorCookie, "Dimension types not allowed");
2006 //                }
2007 //                return false;
2008 //            }
2009 //        } else if (outValue->dataType == Res_value::TYPE_FRACTION) {
2010 //            if ((attrType&ResTable_map::TYPE_FRACTION) != 0) {
2011 //                return true;
2012 //            }
2013 //            if (!canStringCoerce) {
2014 //                if (accessor != NULL) {
2015 //                    accessor->reportError(accessorCookie, "Fraction types not allowed");
2016 //                }
2017 //                return false;
2018 //            }
2019 //        } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) {
2020 //            if (!canStringCoerce) {
2021 //                if (accessor != NULL) {
2022 //                    accessor->reportError(accessorCookie, "Float types not allowed");
2023 //                }
2024 //                return false;
2025 //            }
2026 //        } else {
2027 //            return true;
2028 //        }
2029 //    }
2030 //
2031 //    if (len == 4) {
2032 //        if ((s[0] == 't' || s[0] == 'T') &&
2033 //            (s[1] == 'r' || s[1] == 'R') &&
2034 //            (s[2] == 'u' || s[2] == 'U') &&
2035 //            (s[3] == 'e' || s[3] == 'E')) {
2036 //            if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
2037 //                if (!canStringCoerce) {
2038 //                    if (accessor != NULL) {
2039 //                        accessor->reportError(accessorCookie, "Boolean types not allowed");
2040 //                    }
2041 //                    return false;
2042 //                }
2043 //            } else {
2044 //                outValue->dataType = outValue->TYPE_INT_BOOLEAN;
2045 //                outValue->data = (uint32_t)-1;
2046 //                return true;
2047 //            }
2048 //        }
2049 //    }
2050 //
2051 //    if (len == 5) {
2052 //        if ((s[0] == 'f' || s[0] == 'F') &&
2053 //            (s[1] == 'a' || s[1] == 'A') &&
2054 //            (s[2] == 'l' || s[2] == 'L') &&
2055 //            (s[3] == 's' || s[3] == 'S') &&
2056 //            (s[4] == 'e' || s[4] == 'E')) {
2057 //            if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
2058 //                if (!canStringCoerce) {
2059 //                    if (accessor != NULL) {
2060 //                        accessor->reportError(accessorCookie, "Boolean types not allowed");
2061 //                    }
2062 //                    return false;
2063 //                }
2064 //            } else {
2065 //                outValue->dataType = outValue->TYPE_INT_BOOLEAN;
2066 //                outValue->data = 0;
2067 //                return true;
2068 //            }
2069 //        }
2070 //    }
2071 //
2072 //    if ((attrType&ResTable_map::TYPE_ENUM) != 0) {
2073 //        const ssize_t p = getResourcePackageIndex(attrID);
2074 //        const bag_entry* bag;
2075 //        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
2076 //        //printf("Got %d for enum\n", cnt);
2077 //        if (cnt >= 0) {
2078 //            resource_name rname;
2079 //            while (cnt > 0) {
2080 //                if (!Res_INTERNALID(bag->map.name.ident)) {
2081 //                    //printf("Trying attr #%08x\n", bag->map.name.ident);
2082 //                    if (getResourceName(bag->map.name.ident, false, &rname)) {
2083 //                        #if 0
2084 //                        printf("Matching %s against %s (0x%08x)\n",
2085 //                               String8(s, len).string(),
2086 //                               String8(rname.name, rname.nameLen).string(),
2087 //                               bag->map.name.ident);
2088 //                        #endif
2089 //                        if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
2090 //                            outValue->dataType = bag->map.value.dataType;
2091 //                            outValue->data = bag->map.value.data;
2092 //                            unlockBag(bag);
2093 //                            return true;
2094 //                        }
2095 //                    }
2096 //
2097 //                }
2098 //                bag++;
2099 //                cnt--;
2100 //            }
2101 //            unlockBag(bag);
2102 //        }
2103 //
2104 //        if (fromAccessor) {
2105 //            if (accessor->getAttributeEnum(attrID, s, len, outValue)) {
2106 //                return true;
2107 //            }
2108 //        }
2109 //    }
2110 //
2111 //    if ((attrType&ResTable_map::TYPE_FLAGS) != 0) {
2112 //        const ssize_t p = getResourcePackageIndex(attrID);
2113 //        const bag_entry* bag;
2114 //        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
2115 //        //printf("Got %d for flags\n", cnt);
2116 //        if (cnt >= 0) {
2117 //            bool failed = false;
2118 //            resource_name rname;
2119 //            outValue->dataType = Res_value::TYPE_INT_HEX;
2120 //            outValue->data = 0;
2121 //            const char16_t* end = s + len;
2122 //            const char16_t* pos = s;
2123 //            while (pos < end && !failed) {
2124 //                const char16_t* start = pos;
2125 //                pos++;
2126 //                while (pos < end && *pos != '|') {
2127 //                    pos++;
2128 //                }
2129 //                //printf("Looking for: %s\n", String8(start, pos-start).string());
2130 //                const bag_entry* bagi = bag;
2131 //                ssize_t i;
2132 //                for (i=0; i<cnt; i++, bagi++) {
2133 //                    if (!Res_INTERNALID(bagi->map.name.ident)) {
2134 //                        //printf("Trying attr #%08x\n", bagi->map.name.ident);
2135 //                        if (getResourceName(bagi->map.name.ident, false, &rname)) {
2136 //                            #if 0
2137 //                            printf("Matching %s against %s (0x%08x)\n",
2138 //                                   String8(start,pos-start).string(),
2139 //                                   String8(rname.name, rname.nameLen).string(),
2140 //                                   bagi->map.name.ident);
2141 //                            #endif
2142 //                            if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
2143 //                                outValue->data |= bagi->map.value.data;
2144 //                                break;
2145 //                            }
2146 //                        }
2147 //                    }
2148 //                }
2149 //                if (i >= cnt) {
2150 //                    // Didn't find this flag identifier.
2151 //                    failed = true;
2152 //                }
2153 //                if (pos < end) {
2154 //                    pos++;
2155 //                }
2156 //            }
2157 //            unlockBag(bag);
2158 //            if (!failed) {
2159 //                //printf("Final flag value: 0x%lx\n", outValue->data);
2160 //                return true;
2161 //            }
2162 //        }
2163 //
2164 //
2165 //        if (fromAccessor) {
2166 //            if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
2167 //                //printf("Final flag value: 0x%lx\n", outValue->data);
2168 //                return true;
2169 //            }
2170 //        }
2171 //    }
2172 //
2173 //    if ((attrType&ResTable_map::TYPE_STRING) == 0) {
2174 //        if (accessor != NULL) {
2175 //            accessor->reportError(accessorCookie, "String types not allowed");
2176 //        }
2177 //        return false;
2178 //    }
2179 //
2180 //    // Generic string handling...
2181 //    outValue->dataType = outValue->TYPE_STRING;
2182 //    if (outString) {
2183 //        bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg);
2184 //        if (accessor != NULL) {
2185 //            accessor->reportError(accessorCookie, errorMsg);
2186 //        }
2187 //        return failed;
2188 //    }
2189 //
2190 //    return true;
2191 //}
2192 //
2193 //bool ResTable::collectString(String16* outString,
2194 //                             const char16_t* s, size_t len,
2195 //                             bool preserveSpaces,
2196 //                             const char** outErrorMsg,
2197 //                             bool append)
2198 //{
2199 //    String16 tmp;
2200 //
2201 //    char quoted = 0;
2202 //    const char16_t* p = s;
2203 //    while (p < (s+len)) {
2204 //        while (p < (s+len)) {
2205 //            const char16_t c = *p;
2206 //            if (c == '\\') {
2207 //                break;
2208 //            }
2209 //            if (!preserveSpaces) {
2210 //                if (quoted == 0 && isspace16(c)
2211 //                    && (c != ' ' || isspace16(*(p+1)))) {
2212 //                    break;
2213 //                }
2214 //                if (c == '"' && (quoted == 0 || quoted == '"')) {
2215 //                    break;
2216 //                }
2217 //                if (c == '\'' && (quoted == 0 || quoted == '\'')) {
2218 //                    /*
2219 //                     * In practice, when people write ' instead of \'
2220 //                     * in a string, they are doing it by accident
2221 //                     * instead of really meaning to use ' as a quoting
2222 //                     * character.  Warn them so they don't lose it.
2223 //                     */
2224 //                    if (outErrorMsg) {
2225 //                        *outErrorMsg = "Apostrophe not preceded by \\";
2226 //                    }
2227 //                    return false;
2228 //                }
2229 //            }
2230 //            p++;
2231 //        }
2232 //        if (p < (s+len)) {
2233 //            if (p > s) {
2234 //                tmp.append(String16(s, p-s));
2235 //            }
2236 //            if (!preserveSpaces && (*p == '"' || *p == '\'')) {
2237 //                if (quoted == 0) {
2238 //                    quoted = *p;
2239 //                } else {
2240 //                    quoted = 0;
2241 //                }
2242 //                p++;
2243 //            } else if (!preserveSpaces && isspace16(*p)) {
2244 //                // Space outside of a quote -- consume all spaces and
2245 //                // leave a single plain space char.
2246 //                tmp.append(String16(" "));
2247 //                p++;
2248 //                while (p < (s+len) && isspace16(*p)) {
2249 //                    p++;
2250 //                }
2251 //            } else if (*p == '\\') {
2252 //                p++;
2253 //                if (p < (s+len)) {
2254 //                    switch (*p) {
2255 //                    case 't':
2256 //                        tmp.append(String16("\t"));
2257 //                        break;
2258 //                    case 'n':
2259 //                        tmp.append(String16("\n"));
2260 //                        break;
2261 //                    case '#':
2262 //                        tmp.append(String16("#"));
2263 //                        break;
2264 //                    case '@':
2265 //                        tmp.append(String16("@"));
2266 //                        break;
2267 //                    case '?':
2268 //                        tmp.append(String16("?"));
2269 //                        break;
2270 //                    case '"':
2271 //                        tmp.append(String16("\""));
2272 //                        break;
2273 //                    case '\'':
2274 //                        tmp.append(String16("'"));
2275 //                        break;
2276 //                    case '\\':
2277 //                        tmp.append(String16("\\"));
2278 //                        break;
2279 //                    case 'u':
2280 //                    {
2281 //                        char16_t chr = 0;
2282 //                        int i = 0;
2283 //                        while (i < 4 && p[1] != 0) {
2284 //                            p++;
2285 //                            i++;
2286 //                            int c;
2287 //                            if (*p >= '0' && *p <= '9') {
2288 //                                c = *p - '0';
2289 //                            } else if (*p >= 'a' && *p <= 'f') {
2290 //                                c = *p - 'a' + 10;
2291 //                            } else if (*p >= 'A' && *p <= 'F') {
2292 //                                c = *p - 'A' + 10;
2293 //                            } else {
2294 //                                if (outErrorMsg) {
2295 //                                    *outErrorMsg = "Bad character in \\u unicode escape sequence";
2296 //                                }
2297 //                                return false;
2298 //                            }
2299 //                            chr = (chr<<4) | c;
2300 //                        }
2301 //                        tmp.append(String16(&chr, 1));
2302 //                    } break;
2303 //                    default:
2304 //                        // ignore unknown escape chars.
2305 //                        break;
2306 //                    }
2307 //                    p++;
2308 //                }
2309 //            }
2310 //            len -= (p-s);
2311 //            s = p;
2312 //        }
2313 //    }
2314 //
2315 //    if (tmp.size() != 0) {
2316 //        if (len > 0) {
2317 //            tmp.append(String16(s, len));
2318 //        }
2319 //        if (append) {
2320 //            outString->append(tmp);
2321 //        } else {
2322 //            outString->setTo(tmp);
2323 //        }
2324 //    } else {
2325 //        if (append) {
2326 //            outString->append(String16(s, len));
2327 //        } else {
2328 //            outString->setTo(s, len);
2329 //        }
2330 //    }
2331 //
2332 //    return true;
2333 //}
2334 
2335   public int getBasePackageCount()
2336   {
2337     if (mError != NO_ERROR) {
2338       return 0;
2339     }
2340     return mPackageGroups.size();
2341   }
2342 
2343   public String getBasePackageName(int idx)
2344   {
2345     if (mError != NO_ERROR) {
2346       return null;
2347     }
2348     LOG_FATAL_IF(idx >= mPackageGroups.size(),
2349         "Requested package index %d past package count %d",
2350         (int)idx, (int)mPackageGroups.size());
2351     return mPackageGroups.get(keyFor(idx)).name;
2352   }
2353 
2354   public int getBasePackageId(int idx)
2355   {
2356     if (mError != NO_ERROR) {
2357       return 0;
2358     }
2359     LOG_FATAL_IF(idx >= mPackageGroups.size(),
2360         "Requested package index %d past package count %d",
2361         (int)idx, (int)mPackageGroups.size());
2362     return mPackageGroups.get(keyFor(idx)).id;
2363   }
2364 
getLastTypeIdForPackage(int idx)2365   int getLastTypeIdForPackage(int idx)
2366   {
2367     if (mError != NO_ERROR) {
2368       return 0;
2369     }
2370     LOG_FATAL_IF(idx >= mPackageGroups.size(),
2371         "Requested package index %d past package count %d",
2372         (int)idx, (int)mPackageGroups.size());
2373     PackageGroup group = mPackageGroups.get(keyFor(idx));
2374     return group.largestTypeId;
2375   }
2376 
keyFor(int idx)2377   int keyFor(int idx) {
2378     ArrayList<Integer> keys = new ArrayList<>(mPackageGroups.keySet());
2379     Collections.sort(keys);
2380     return keys.get(idx);
2381   }
2382 
getTableCount()2383   public int getTableCount() {
2384     return mHeaders.size();
2385   }
2386 
getTableStringBlock(int index)2387   public ResStringPool getTableStringBlock(int index) {
2388     return mHeaders.get(index).values;
2389   }
2390 
getDynamicRefTableForCookie(int cookie)2391   public DynamicRefTable getDynamicRefTableForCookie(int cookie) {
2392     for (PackageGroup pg : mPackageGroups.values()) {
2393       int M = pg.packages.size();
2394       for (int j = 0; j < M; j++) {
2395         if (pg.packages.get(j).header.cookie == cookie) {
2396           return pg.dynamicRefTable;
2397         }
2398       }
2399     }
2400     return null;
2401   }
2402 
getResourceName(int resID, boolean allowUtf8, ResourceName outName)2403   public boolean getResourceName(int resID, boolean allowUtf8, ResourceName outName) {
2404     if (mError != NO_ERROR) {
2405       return false;
2406     }
2407 
2408     final int p = getResourcePackageIndex(resID);
2409     final int t = Res_GETTYPE(resID);
2410     final int e = Res_GETENTRY(resID);
2411 
2412     if (p < 0) {
2413       if (Res_GETPACKAGE(resID)+1 == 0) {
2414         ALOGW("No package identifier when getting name for resource number 0x%08x", resID);
2415       }
2416       return false;
2417     }
2418     if (t < 0) {
2419       ALOGW("No type identifier when getting name for resource number 0x%08x", resID);
2420       return false;
2421     }
2422 
2423     final PackageGroup grp = mPackageGroups.get(p);
2424     if (grp == NULL) {
2425       ALOGW("Bad identifier when getting name for resource number 0x%08x", resID);
2426       return false;
2427     }
2428 
2429     Entry entry = new Entry();
2430     int err = getEntry(grp, t, e, null, entry);
2431     if (err != NO_ERROR) {
2432       return false;
2433     }
2434 
2435     outName.packageName = grp.name;
2436     outName.type = entry.typeStr.string();
2437     if (outName.type == null) {
2438       return false;
2439     }
2440     outName.name = entry.keyStr.string();
2441     if (outName.name == null) {
2442       return false;
2443     }
2444 
2445     return true;
2446   }
2447 
getResourceName(int resId)2448   String getResourceName(int resId) {
2449     ResourceName outName = new ResourceName();
2450     if (getResourceName(resId, true, outName)) {
2451       return outName.toString();
2452     }
2453     throw new IllegalArgumentException("Unknown resource id " + resId);
2454   }
2455 
2456   // A group of objects describing a particular resource package.
2457   // The first in 'package' is always the root object (from the resource
2458   // table that defined the package); the ones after are skins on top of it.
2459   // from ResourceTypes.cpp struct ResTable::PackageGroup
2460   public static class PackageGroup
2461   {
PackageGroup( ResTable _owner, final String _name, int _id, boolean appAsLib, boolean _isSystemAsset, boolean _isDynamic)2462     public PackageGroup(
2463         ResTable _owner, final String _name, int _id,
2464         boolean appAsLib, boolean _isSystemAsset, boolean _isDynamic)
2465 //        : owner(_owner)
2466 //        , name(_name)
2467 //        , id(_id)
2468 //        , largestTypeId(0)
2469 //        , dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
2470 //        , isSystemAsset(_isSystemAsset)
2471     {
2472       this.owner = _owner;
2473       this.name = _name;
2474       this.id = _id;
2475       this.dynamicRefTable = new DynamicRefTable((byte) _id, appAsLib);
2476       this.isSystemAsset = _isSystemAsset;
2477       this.isDynamic = _isDynamic;
2478     }
2479 
2480 //    ~PackageGroup() {
2481 //      clearBagCache();
2482 //      final int numTypes = types.size();
2483 //      for (int i = 0; i < numTypes; i++) {
2484 //        final List<DataType> typeList = types.get(i);
2485 //        final int numInnerTypes = typeList.size();
2486 //        for (int j = 0; j < numInnerTypes; j++) {
2487 //          if (typeList.get(j)._package_.owner == owner) {
2488 //            delete typeList[j];
2489 //          }
2490 //        }
2491 //        typeList.clear();
2492 //      }
2493 //
2494 //      final int N = packages.size();
2495 //      for (int i=0; i<N; i++) {
2496 //        ResTable_package pkg = packages[i];
2497 //        if (pkg.owner == owner) {
2498 //          delete pkg;
2499 //        }
2500 //      }
2501 //    }
2502 
2503     /**
2504      * Clear all cache related data that depends on parameters/configuration.
2505      * This includes the bag caches and filtered types.
2506      */
clearBagCache()2507     void clearBagCache() {
2508 //      for (int i = 0; i < typeCacheEntries.size(); i++) {
2509 //        if (kDebugTableNoisy) {
2510 //          printf("type=0x%x\n", i);
2511 //        }
2512 //        final List<DataType> typeList = types.get(i);
2513 //        if (!typeList.isEmpty()) {
2514 //          TypeCacheEntry cacheEntry = typeCacheEntries.editItemAt(i);
2515 //
2516 //          // Reset the filtered configurations.
2517 //          cacheEntry.filteredConfigs.clear();
2518 //
2519 //          bag_set[][] typeBags = cacheEntry.cachedBags;
2520 //          if (kDebugTableNoisy) {
2521 //            printf("typeBags=%s\n", typeBags);
2522 //          }
2523 //
2524 //          if (isTruthy(typeBags)) {
2525 //            final int N = typeList.get(0).entryCount;
2526 //            if (kDebugTableNoisy) {
2527 //              printf("type.entryCount=0x%x\n", N);
2528 //            }
2529 //            for (int j = 0; j < N; j++) {
2530 //              if (typeBags[j] && typeBags[j] != (bag_set *) 0xFFFFFFFF){
2531 //                free(typeBags[j]);
2532 //              }
2533 //            }
2534 //            free(typeBags);
2535 //            cacheEntry.cachedBags = NULL;
2536 //          }
2537 //        }
2538 //      }
2539     }
2540 
printf(String message, Object... arguments)2541     private void printf(String message, Object... arguments) {
2542       System.out.print(String.format(message, arguments));
2543     }
2544 
2545 //    long findType16(final String type, int len) {
2546 //      final int N = packages.size();
2547 //      for (int i = 0; i < N; i++) {
2548 //        sint index = packages[i].typeStrings.indexOfString(type, len);
2549 //        if (index >= 0) {
2550 //          return index + packages[i].typeIdOffset;
2551 //        }
2552 //      }
2553 //      return -1;
2554 //    }
2555 
2556     final ResTable owner;
2557     final String name;
2558     final int id;
2559 
2560     // This is mainly used to keep track of the loaded packages
2561     // and to clean them up properly. Accessing resources happens from
2562     // the 'types' array.
2563     List<Package> packages = new ArrayList<>();
2564 
2565     public final Map<Integer, List<Type>> types = new HashMap<>();
2566 
2567     byte largestTypeId;
2568 
2569     // Cached objects dependent on the parameters/configuration of this ResTable.
2570     // Gets cleared whenever the parameters/configuration changes.
2571     // These are stored here in a parallel structure because the data in `types` may
2572     // be shared by other ResTable's (framework resources are shared this way).
2573     ByteBucketArray<TypeCacheEntry> typeCacheEntries =
2574         new ByteBucketArray<TypeCacheEntry>(new TypeCacheEntry()) {
2575           @Override
2576           TypeCacheEntry newInstance() {
2577             return new TypeCacheEntry();
2578           }
2579         };
2580 
2581     // The table mapping dynamic references to resolved references for
2582     // this package group.
2583     // TODO: We may be able to support dynamic references in overlays
2584     // by having these tables in a per-package scope rather than
2585     // per-package-group.
2586     DynamicRefTable dynamicRefTable;
2587 
2588     // If the package group comes from a system asset. Used in
2589     // determining non-system locales.
2590     final boolean isSystemAsset;
2591     final boolean isDynamic;
2592   }
2593 
2594   // --------------------------------------------------------------------
2595 // --------------------------------------------------------------------
2596 // --------------------------------------------------------------------
2597 
2598 //  struct ResTable::Header
2599   public static class Header
2600   {
2601 //    Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
2602 //      resourceIDMap(NULL), resourceIDMapSize(0) { }
2603 
Header(ResTable owner)2604     public Header(ResTable owner) {
2605       this.owner = owner;
2606     }
2607 
2608 //    ~Header()
2609 //    {
2610 //      free(resourceIDMap);
2611 //    }
2612 
2613     ResTable            owner;
2614     byte[]                           ownedData;
2615     ResTable_header header;
2616     int                          size;
2617     int                  dataEnd;
2618     int                          index;
2619     int                         cookie;
2620 
2621     ResStringPool                   values = new ResStringPool();
2622     int[]                       resourceIDMap;
2623     int                          resourceIDMapSize;
2624   };
2625 
2626   public static class Entry {
2627     ResTable_config config;
2628     ResTable_entry entry;
2629     ResTable_type type;
2630     int specFlags;
2631     Package _package_;
2632 
2633     StringPoolRef typeStr;
2634     StringPoolRef keyStr;
2635   }
2636 
2637   // struct ResTable::DataType
2638   public static class Type {
2639 
2640     final Header header;
2641     final Package _package_;
2642     public final int entryCount;
2643     public ResTable_typeSpec typeSpec;
2644     public int[] typeSpecFlags;
2645     public IdmapEntries idmapEntries = new IdmapEntries();
2646     public List<ResTable_type> configs;
2647 
Type(final Header _header, final Package _package, int count)2648     public Type(final Header _header, final Package _package, int count)
2649   //        : header(_header), package(_package), entryCount(count),
2650   //  typeSpec(NULL), typeSpecFlags(NULL) { }
2651     {
2652       this.header = _header;
2653       _package_ = _package;
2654       this.entryCount = count;
2655       this.typeSpec = null;
2656       this.typeSpecFlags = null;
2657       this.configs = new ArrayList<>();
2658     }
2659   }
2660 
2661 //  struct ResTable::Package
2662   public static class Package {
2663 //    Package(ResTable* _owner, final Header* _header, final ResTable_package* _package)
2664 //        : owner(_owner), header(_header), package(_package), typeIdOffset(0) {
2665 //    if (dtohs(package.header.headerSize) == sizeof(package)) {
2666 //      // The package structure is the same size as the definition.
2667 //      // This means it contains the typeIdOffset field.
2668 //      typeIdOffset = package.typeIdOffset;
2669 //    }
2670 
Package(ResTable owner, Header header, ResTable_package _package)2671     public Package(ResTable owner, Header header, ResTable_package _package) {
2672       this.owner = owner;
2673       this.header = header;
2674       this._package_ = _package;
2675     }
2676 
2677     final ResTable owner;
2678     final Header header;
2679     final ResTable_package _package_;
2680 
2681     ResStringPool typeStrings = new ResStringPool();
2682     ResStringPool keyStrings = new ResStringPool();
2683 
2684     int typeIdOffset;
2685   };
2686 
2687   public static class bag_entry {
2688     public int stringBlock;
2689     public ResTable_map map = new ResTable_map();
2690   }
2691 
lock()2692   public void lock() {
2693     try {
2694       mLock.acquire();
2695     } catch (InterruptedException e) {
2696       throw new RuntimeException(e);
2697     }
2698   }
2699 
unlock()2700   public void unlock() {
2701     mLock.release();
2702   }
2703 
lockBag(int resID, Ref<bag_entry[]> outBag)2704   public int lockBag(int resID, Ref<bag_entry[]> outBag) {
2705     lock();
2706 
2707     int err = getBagLocked(resID, outBag, null);
2708     if (err < NO_ERROR) {
2709       //printf("*** get failed!  unlocking\n");
2710       mLock.release();
2711     }
2712     return err;
2713   }
2714 
getBagLocked(int resID, Ref<bag_entry[]> outBag, Ref<Integer> outTypeSpecFlags)2715   public int getBagLocked(int resID, Ref<bag_entry[]> outBag, Ref<Integer> outTypeSpecFlags) {
2716     if (mError != NO_ERROR) {
2717       return mError;
2718     }
2719 
2720     final int p = getResourcePackageIndex(resID);
2721     final int t = Res_GETTYPE(resID);
2722     final int e = Res_GETENTRY(resID);
2723 
2724     if (p < 0) {
2725       ALOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID);
2726       return BAD_INDEX;
2727     }
2728     if (t < 0) {
2729       ALOGW("No type identifier when getting bag for resource number 0x%08x", resID);
2730       return BAD_INDEX;
2731     }
2732 
2733     //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t);
2734     PackageGroup grp = mPackageGroups.get(p);
2735     if (grp == NULL) {
2736       ALOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
2737       return BAD_INDEX;
2738     }
2739 
2740     final List<Type> typeConfigs = getOrDefault(grp.types, t, Collections.emptyList());
2741     if (typeConfigs.isEmpty()) {
2742       ALOGW("Type identifier 0x%x does not exist.", t+1);
2743       return BAD_INDEX;
2744     }
2745 
2746     final int NENTRY = typeConfigs.get(0).entryCount;
2747     if (e >= (int)NENTRY) {
2748       ALOGW("Entry identifier 0x%x is larger than entry count 0x%x",
2749           e, (int)typeConfigs.get(0).entryCount);
2750       return BAD_INDEX;
2751     }
2752 
2753     // First see if we've already computed this bag...
2754     TypeCacheEntry cacheEntry = grp.typeCacheEntries.editItemAt(t);
2755     bag_set[] typeSet = cacheEntry.cachedBags;
2756     // todo cache
2757 //    if (isTruthy(typeSet)) {
2758 //      bag_set set = typeSet[e];
2759 //      if (isTruthy(set)) {
2760 //        if (set != (bag_set) 0xFFFFFFFF){
2761 //        if (set != SENTINEL_BAG_SET){
2762 //          if (outTypeSpecFlags != NULL) {
2763 //                    outTypeSpecFlags.set(set.typeSpecFlags);
2764 //          }
2765 //          outBag.set((bag_entry *) (set + 1);
2766 //          if (kDebugTableSuperNoisy) {
2767 //            ALOGI("Found existing bag for: 0x%x\n", resID);
2768 //          }
2769 //          return set.numAttrs;
2770 //        }
2771 //        ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
2772 //            resID);
2773 //        return BAD_INDEX;
2774 //      }
2775 //    }
2776 //
2777     // Bag not found, we need to compute it!
2778     if (!isTruthy(typeSet)) {
2779       typeSet = new bag_set[NENTRY]; // (bag_set**)calloc(NENTRY, sizeof(bag_set*));
2780       //cacheEntry.cachedBags = typeSet;
2781     }
2782 //
2783 //    // Mark that we are currently working on this one.
2784 //    typeSet[e] = (bag_set*)0xFFFFFFFF;
2785 //    typeSet[e] = SENTINEL_BAG_SET;
2786 
2787     if (kDebugTableNoisy) {
2788       ALOGI("Building bag: %x\n", resID);
2789     }
2790 
2791     // Now collect all bag attributes
2792     Entry entry = new Entry();
2793     int err = getEntry(grp, t, e, mParams, entry);
2794     if (err != NO_ERROR) {
2795       return err;
2796     }
2797     final short entrySize = dtohs(entry.entry.size);
2798 //    const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
2799 //        ? dtohl(((const ResTable_map_entry*)entry.entry)->parent.ident) : 0;
2800 //    const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
2801 //        ? dtohl(((const ResTable_map_entry*)entry.entry)->count) : 0;
2802     ResTable_map_entry mapEntry = entrySize >= ResTable_map_entry.BASE_SIZEOF ?
2803         new ResTable_map_entry(entry.entry.myBuf(), entry.entry.myOffset()) : null;
2804     final int parent = mapEntry != null ? dtohl(mapEntry.parent.ident) : 0;
2805     final int count = mapEntry != null ? dtohl(mapEntry.count) : 0;
2806 
2807     int N = count;
2808 
2809     if (kDebugTableNoisy) {
2810       ALOGI("Found map: size=%x parent=%x count=%d\n", entrySize, parent, count);
2811 
2812       // If this map inherits from another, we need to start
2813       // with its parent's values.  Otherwise start out empty.
2814       ALOGI("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", entrySize, parent);
2815     }
2816 
2817     // This is what we are building.
2818     bag_set set;
2819 
2820     if (isTruthy(parent)) {
2821       final Ref<Integer> resolvedParent = new Ref<>(parent);
2822 
2823       // Bags encode a parent reference without using the standard
2824       // Res_value structure. That means we must always try to
2825       // resolve a parent reference in case it is actually a
2826       // TYPE_DYNAMIC_REFERENCE.
2827       err = grp.dynamicRefTable.lookupResourceId(resolvedParent);
2828       if (err != NO_ERROR) {
2829         ALOGE("Failed resolving bag parent id 0x%08x", parent);
2830         return UNKNOWN_ERROR;
2831       }
2832 
2833       final Ref<bag_entry[]> parentBag = new Ref<>(null);
2834       final Ref<Integer> parentTypeSpecFlags = new Ref<>(0);
2835       final int NP = getBagLocked(resolvedParent.get(), parentBag, parentTypeSpecFlags);
2836       final int NT = ((NP >= 0) ? NP : 0) + N;
2837       set = new bag_set(NT);
2838       if (NP > 0) {
2839         set.copyFrom(parentBag.get(), NP);
2840         set.numAttrs = NP;
2841         if (kDebugTableNoisy) {
2842           ALOGI("Initialized new bag with %d inherited attributes.\n", NP);
2843         }
2844       } else {
2845         if (kDebugTableNoisy) {
2846           ALOGI("Initialized new bag with no inherited attributes.\n");
2847         }
2848         set.numAttrs = 0;
2849       }
2850       set.availAttrs = NT;
2851       set.typeSpecFlags = parentTypeSpecFlags.get();
2852     } else {
2853       set = new bag_set(N);
2854       set.numAttrs = 0;
2855       set.availAttrs = N;
2856       set.typeSpecFlags = 0;
2857     }
2858 
2859     set.typeSpecFlags |= entry.specFlags;
2860 
2861     // Now merge in the new attributes...
2862 //    int curOff = (reinterpret_cast<uintptr_t>(entry.entry) - reinterpret_cast<uintptr_t>(entry.type))
2863 //        + dtohs(entry.entry.size);
2864     int curOff = entry.entry.myOffset() - entry.type.myOffset() + entry.entry.size;
2865     ResTable_map map;
2866 //    bag_entry* entries = (bag_entry*)(set+1);
2867     bag_entry[] entries = set.bag_entries;
2868     int curEntry = 0;
2869     int pos = 0;
2870     if (kDebugTableNoisy) {
2871       ALOGI("Starting with set %s, entries=%s, avail=0x%x\n", set, entries, set.availAttrs);
2872     }
2873     while (pos < count) {
2874       if (kDebugTableNoisy) {
2875 //        ALOGI("Now at %s\n", curOff);
2876         ALOGI("Now at %s\n", curEntry);
2877       }
2878 
2879       if (curOff > (dtohl(entry.type.header.size)- ResTable_map.SIZEOF)) {
2880         ALOGW("ResTable_map at %d is beyond type chunk data %d",
2881             (int)curOff, dtohl(entry.type.header.size));
2882         return BAD_TYPE;
2883       }
2884 //      map = (const ResTable_map*)(((const uint8_t*)entry.type) + curOff);
2885       map = new ResTable_map(entry.type.myBuf(), entry.type.myOffset() + curOff);
2886       N++;
2887 
2888       final Ref<Integer> newName = new Ref<>(htodl(map.name.ident));
2889       if (!Res_INTERNALID(newName.get())) {
2890         // Attributes don't have a resource id as the name. They specify
2891         // other data, which would be wrong to change via a lookup.
2892         if (grp.dynamicRefTable.lookupResourceId(newName) != NO_ERROR) {
2893           ALOGE("Failed resolving ResTable_map name at %d with ident 0x%08x",
2894               (int) curEntry, (int) newName.get());
2895           return UNKNOWN_ERROR;
2896         }
2897       }
2898 
2899       boolean isInside;
2900       int oldName = 0;
2901       while ((isInside=(curEntry < set.numAttrs))
2902           && (oldName=entries[curEntry].map.name.ident) < newName.get()) {
2903         if (kDebugTableNoisy) {
2904           ALOGI("#0x%x: Keeping existing attribute: 0x%08x\n",
2905               curEntry, entries[curEntry].map.name.ident);
2906         }
2907         curEntry++;
2908       }
2909 
2910       if ((!isInside) || oldName != newName.get()) {
2911         // This is a new attribute...  figure out what to do with it.
2912         if (set.numAttrs >= set.availAttrs) {
2913           // Need to alloc more memory...
2914                 final int newAvail = set.availAttrs+N;
2915 //          set = (bag_set[])realloc(set,
2916 //              sizeof(bag_set)
2917 //                  + sizeof(bag_entry)*newAvail);
2918           set.resizeBagEntries(newAvail);
2919           set.availAttrs = newAvail;
2920 //          entries = (bag_entry*)(set+1);
2921           entries = set.bag_entries;
2922           if (kDebugTableNoisy) {
2923             ALOGI("Reallocated set %s, entries=%s, avail=0x%x\n",
2924                 set, entries, set.availAttrs);
2925           }
2926         }
2927         if (isInside) {
2928           // Going in the middle, need to make space.
2929 //          memmove(entries+curEntry+1, entries+curEntry,
2930 //              sizeof(bag_entry)*(set.numAttrs-curEntry));
2931           System.arraycopy(entries, curEntry, entries, curEntry + 1, set.numAttrs - curEntry);
2932           entries[curEntry] = null;
2933           set.numAttrs++;
2934         }
2935         if (kDebugTableNoisy) {
2936           ALOGI("#0x%x: Inserting new attribute: 0x%08x\n", curEntry, newName.get());
2937         }
2938       } else {
2939         if (kDebugTableNoisy) {
2940           ALOGI("#0x%x: Replacing existing attribute: 0x%08x\n", curEntry, oldName);
2941         }
2942       }
2943 
2944       bag_entry cur = entries[curEntry];
2945       if (cur == null) {
2946         cur = entries[curEntry] = new bag_entry();
2947       }
2948 
2949       cur.stringBlock = entry._package_.header.index;
2950       cur.map.name.ident = newName.get();
2951 //      cur->map.value.copyFrom_dtoh(map->value);
2952       cur.map.value = map.value;
2953       final Ref<Res_value> valueRef = new Ref<>(cur.map.value);
2954       err = grp.dynamicRefTable.lookupResourceValue(valueRef);
2955       cur.map.value = map.value = valueRef.get();
2956       if (err != NO_ERROR) {
2957         ALOGE("Reference item(0x%08x) in bag could not be resolved.", cur.map.value.data);
2958         return UNKNOWN_ERROR;
2959       }
2960 
2961       if (kDebugTableNoisy) {
2962         ALOGI("Setting entry #0x%x %s: block=%d, name=0x%08d, type=%d, data=0x%08x\n",
2963             curEntry, cur, cur.stringBlock, cur.map.name.ident,
2964             cur.map.value.dataType, cur.map.value.data);
2965       }
2966 
2967       // On to the next!
2968       curEntry++;
2969       pos++;
2970       final int size = dtohs(map.value.size);
2971 //      curOff += size + sizeof(*map)-sizeof(map->value);
2972       curOff += size + ResTable_map.SIZEOF-Res_value.SIZEOF;
2973     };
2974 
2975     if (curEntry > set.numAttrs) {
2976       set.numAttrs = curEntry;
2977     }
2978 
2979     // And this is it...
2980     typeSet[e] = set;
2981     if (isTruthy(set)) {
2982       if (outTypeSpecFlags != NULL) {
2983         outTypeSpecFlags.set(set.typeSpecFlags);
2984       }
2985       outBag.set(set.bag_entries);
2986       if (kDebugTableNoisy) {
2987         ALOGI("Returning 0x%x attrs\n", set.numAttrs);
2988       }
2989       return set.numAttrs;
2990     }
2991     return BAD_INDEX;
2992   }
2993 
unlockBag(Ref<bag_entry[]> bag)2994   public void unlockBag(Ref<bag_entry[]> bag) {
2995     unlock();
2996   }
2997 
2998   static class bag_set {
2999     int numAttrs;    // number in array
3000     int availAttrs;  // total space in array
3001     int typeSpecFlags;
3002     // Followed by 'numAttr' bag_entry structures.
3003 
3004     bag_entry[] bag_entries;
3005 
bag_set(int entryCount)3006     public bag_set(int entryCount) {
3007       bag_entries = new bag_entry[entryCount];
3008     }
3009 
copyFrom(bag_entry[] parentBag, int count)3010     public void copyFrom(bag_entry[] parentBag, int count) {
3011       for (int i = 0; i < count; i++) {
3012         bag_entries[i] = parentBag[i];
3013       }
3014     }
3015 
resizeBagEntries(int newEntryCount)3016     public void resizeBagEntries(int newEntryCount) {
3017       bag_entry[] newEntries = new bag_entry[newEntryCount];
3018       System.arraycopy(bag_entries, 0, newEntries, 0, Math.min(bag_entries.length, newEntryCount));
3019       bag_entries = newEntries;
3020     }
3021   };
3022 
3023   /**
3024    * Configuration dependent cached data. This must be cleared when the configuration is
3025    * changed (setParameters).
3026    */
3027   static class TypeCacheEntry {
3028 //    TypeCacheEntry() : cachedBags(NULL) {}
3029 
3030     // Computed attribute bags for this type.
3031 //    bag_set** cachedBags;
3032     bag_set[] cachedBags;
3033 
3034     // Pre-filtered list of configurations (per asset path) that match the parameters set on this
3035     // ResTable.
3036     List<List<ResTable_type>> filteredConfigs;
3037   };
3038 
3039 
Res_MAKEID(int packageId, int typeId, int entryId)3040   private int Res_MAKEID(int packageId, int typeId, int entryId) {
3041     return (((packageId+1)<<24) | (((typeId+1)&0xFF)<<16) | (entryId&0xFFFF));
3042   }
3043 
3044   // struct resource_name
3045   public static class ResourceName {
3046     public String packageName;
3047     public String type;
3048     public String name;
3049 
3050     @Override
toString()3051     public String toString() {
3052       return packageName.trim() + '@' + type + ':' + name;
3053     }
3054   }
3055 
3056   private interface Function<K, V> {
3057     V apply(K key);
3058   }
3059 
computeIfAbsent(Map<K, V> map, K key, Function<K, V> vFunction)3060   static <K, V> V computeIfAbsent(Map<K, V> map, K key, Function<K, V> vFunction) {
3061     V v = map.get(key);
3062     if (v == null) {
3063       v = vFunction.apply(key);
3064       map.put(key, v);
3065     }
3066     return v;
3067   }
3068 
getOrDefault(Map<K, V> map, K key, V defaultValue)3069   static <K, V> V getOrDefault(Map<K, V> map, K key, V defaultValue) {
3070     V v;
3071     return (((v = map.get(key)) != null) || map.containsKey(key)) ? v : defaultValue;
3072   }
3073 }
3074