Search in sources :

Example 26 with Res_value

use of org.robolectric.res.android.ResourceTypes.Res_value in project robolectric by robolectric.

the class DynamicRefTable method lookupResourceValue.

// 
int lookupResourceValue(Ref<Res_value> value) {
    byte resolvedType = DataType.REFERENCE.code();
    Res_value inValue = value.get();
    switch(DataType.fromCode(inValue.dataType)) {
        case ATTRIBUTE:
            resolvedType = DataType.ATTRIBUTE.code();
        // fallthrough
        case REFERENCE:
            if (!mAppAsLib) {
                return NO_ERROR;
            }
            // also need to be fixed.
            break;
        case DYNAMIC_ATTRIBUTE:
            resolvedType = DataType.ATTRIBUTE.code();
        // fallthrough
        case DYNAMIC_REFERENCE:
            break;
        default:
            return NO_ERROR;
    }
    final Ref<Integer> resIdRef = new Ref<>(inValue.data);
    int err = lookupResourceId(resIdRef);
    value.set(inValue.withData(resIdRef.get()));
    if (err != NO_ERROR) {
        return err;
    }
    value.set(new Res_value(resolvedType, resIdRef.get()));
    return NO_ERROR;
}
Also used : Res_value(org.robolectric.res.android.ResourceTypes.Res_value)

Example 27 with Res_value

use of org.robolectric.res.android.ResourceTypes.Res_value in project robolectric by robolectric.

the class ResTable method getResource.

public final int getResource(int resID, Ref<Res_value> outValue, boolean mayBeBag, int density, final Ref<Integer> outSpecFlags, Ref<ResTable_config> outConfig) {
    if (mError != NO_ERROR) {
        return mError;
    }
    final int p = getResourcePackageIndex(resID);
    final int t = Res_GETTYPE(resID);
    final int e = Res_GETENTRY(resID);
    if (p < 0) {
        if (Res_GETPACKAGE(resID) + 1 == 0) {
            ALOGW("No package identifier when getting value for resource number 0x%08x", resID);
        } else {
            ALOGW("No known package when getting value for resource number 0x%08x", resID);
        }
        return BAD_INDEX;
    }
    if (t < 0) {
        ALOGW("No type identifier when getting value for resource number 0x%08x", resID);
        return BAD_INDEX;
    }
    final PackageGroup grp = mPackageGroups.get(p);
    if (grp == NULL) {
        ALOGW("Bad identifier when getting value for resource number 0x%08x", resID);
        return BAD_INDEX;
    }
    // Allow overriding density
    ResTable_config desiredConfig = mParams;
    if (density > 0) {
        desiredConfig.density = density;
    }
    Entry entry = new Entry();
    int err = getEntry(grp, t, e, desiredConfig, entry);
    if (err != NO_ERROR) {
        // part of a tool. The caller will do its own logging.
        return err;
    }
    if ((entry.entry.flags & ResTable_entry.FLAG_COMPLEX) != 0) {
        if (!mayBeBag) {
            ALOGW("Requesting resource 0x%08x failed because it is complex\n", resID);
        }
        return BAD_VALUE;
    }
    // const Res_value* value = reinterpret_cast<const Res_value*>(
    // reinterpret_cast<const uint8_t*>(entry.entry) + entry.entry->size);
    Res_value value = new Res_value(entry.entry.myBuf(), entry.entry.myOffset() + entry.entry.size);
    // outValue.size = dtohs(value.size);
    // outValue.res0 = value.res0;
    // outValue.dataType = value.dataType;
    // outValue.data = dtohl(value.data);
    outValue.set(value);
    // We need to fix the package ID based on a mapping.
    if (grp.dynamicRefTable.lookupResourceValue(outValue) != NO_ERROR) {
        ALOGW("Failed to resolve referenced package: 0x%08x", outValue.get().data);
        return BAD_VALUE;
    }
    if (outSpecFlags != null) {
        outSpecFlags.set(entry.specFlags);
    }
    if (outConfig != null) {
        outConfig.set(entry.config);
    }
    return entry._package_.header.index;
}
Also used : ResTable_sparseTypeEntry(org.robolectric.res.android.ResourceTypes.ResTable_sparseTypeEntry) Res_value(org.robolectric.res.android.ResourceTypes.Res_value)

Example 28 with Res_value

use of org.robolectric.res.android.ResourceTypes.Res_value in project robolectric by robolectric.

the class ResTable method getBagLocked.

public int getBagLocked(int resID, Ref<bag_entry[]> outBag, Ref<Integer> outTypeSpecFlags) {
    if (mError != NO_ERROR) {
        return mError;
    }
    final int p = getResourcePackageIndex(resID);
    final int t = Res_GETTYPE(resID);
    final int e = Res_GETENTRY(resID);
    if (p < 0) {
        ALOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID);
        return BAD_INDEX;
    }
    if (t < 0) {
        ALOGW("No type identifier when getting bag for resource number 0x%08x", resID);
        return BAD_INDEX;
    }
    // printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t);
    PackageGroup grp = mPackageGroups.get(p);
    if (grp == NULL) {
        ALOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
        return BAD_INDEX;
    }
    final List<Type> typeConfigs = getOrDefault(grp.types, t, Collections.emptyList());
    if (typeConfigs.isEmpty()) {
        ALOGW("Type identifier 0x%x does not exist.", t + 1);
        return BAD_INDEX;
    }
    final int NENTRY = typeConfigs.get(0).entryCount;
    if (e >= (int) NENTRY) {
        ALOGW("Entry identifier 0x%x is larger than entry count 0x%x", e, (int) typeConfigs.get(0).entryCount);
        return BAD_INDEX;
    }
    // First see if we've already computed this bag...
    TypeCacheEntry cacheEntry = grp.typeCacheEntries.editItemAt(t);
    bag_set[] typeSet = cacheEntry.cachedBags;
    // Bag not found, we need to compute it!
    if (!isTruthy(typeSet)) {
        // (bag_set**)calloc(NENTRY, sizeof(bag_set*));
        typeSet = new bag_set[NENTRY];
    // cacheEntry.cachedBags = typeSet;
    }
    if (kDebugTableNoisy) {
        ALOGI("Building bag: %x\n", resID);
    }
    // Now collect all bag attributes
    Entry entry = new Entry();
    int err = getEntry(grp, t, e, mParams, entry);
    if (err != NO_ERROR) {
        return err;
    }
    final short entrySize = dtohs(entry.entry.size);
    // const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
    // ? dtohl(((const ResTable_map_entry*)entry.entry)->parent.ident) : 0;
    // const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
    // ? dtohl(((const ResTable_map_entry*)entry.entry)->count) : 0;
    ResTable_map_entry mapEntry = entrySize >= ResTable_map_entry.BASE_SIZEOF ? new ResTable_map_entry(entry.entry.myBuf(), entry.entry.myOffset()) : null;
    final int parent = mapEntry != null ? dtohl(mapEntry.parent.ident) : 0;
    final int count = mapEntry != null ? dtohl(mapEntry.count) : 0;
    int N = count;
    if (kDebugTableNoisy) {
        ALOGI("Found map: size=%x parent=%x count=%d\n", entrySize, parent, count);
        // If this map inherits from another, we need to start
        // with its parent's values.  Otherwise start out empty.
        ALOGI("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", entrySize, parent);
    }
    // This is what we are building.
    bag_set set;
    if (isTruthy(parent)) {
        final Ref<Integer> resolvedParent = new Ref<>(parent);
        // Bags encode a parent reference without using the standard
        // Res_value structure. That means we must always try to
        // resolve a parent reference in case it is actually a
        // TYPE_DYNAMIC_REFERENCE.
        err = grp.dynamicRefTable.lookupResourceId(resolvedParent);
        if (err != NO_ERROR) {
            ALOGE("Failed resolving bag parent id 0x%08x", parent);
            return UNKNOWN_ERROR;
        }
        final Ref<bag_entry[]> parentBag = new Ref<>(null);
        final Ref<Integer> parentTypeSpecFlags = new Ref<>(0);
        final int NP = getBagLocked(resolvedParent.get(), parentBag, parentTypeSpecFlags);
        final int NT = ((NP >= 0) ? NP : 0) + N;
        set = new bag_set(NT);
        if (NP > 0) {
            set.copyFrom(parentBag.get(), NP);
            set.numAttrs = NP;
            if (kDebugTableNoisy) {
                ALOGI("Initialized new bag with %d inherited attributes.\n", NP);
            }
        } else {
            if (kDebugTableNoisy) {
                ALOGI("Initialized new bag with no inherited attributes.\n");
            }
            set.numAttrs = 0;
        }
        set.availAttrs = NT;
        set.typeSpecFlags = parentTypeSpecFlags.get();
    } else {
        set = new bag_set(N);
        set.numAttrs = 0;
        set.availAttrs = N;
        set.typeSpecFlags = 0;
    }
    set.typeSpecFlags |= entry.specFlags;
    // Now merge in the new attributes...
    // int curOff = (reinterpret_cast<uintptr_t>(entry.entry) - reinterpret_cast<uintptr_t>(entry.type))
    // + dtohs(entry.entry.size);
    int curOff = entry.entry.myOffset() - entry.type.myOffset() + entry.entry.size;
    ResTable_map map;
    // bag_entry* entries = (bag_entry*)(set+1);
    bag_entry[] entries = set.bag_entries;
    int curEntry = 0;
    int pos = 0;
    if (kDebugTableNoisy) {
        ALOGI("Starting with set %s, entries=%s, avail=0x%x\n", set, entries, set.availAttrs);
    }
    while (pos < count) {
        if (kDebugTableNoisy) {
            // ALOGI("Now at %s\n", curOff);
            ALOGI("Now at %s\n", curEntry);
        }
        if (curOff > (dtohl(entry.type.header.size) - ResTable_map.SIZEOF)) {
            ALOGW("ResTable_map at %d is beyond type chunk data %d", (int) curOff, dtohl(entry.type.header.size));
            return BAD_TYPE;
        }
        // map = (const ResTable_map*)(((const uint8_t*)entry.type) + curOff);
        map = new ResTable_map(entry.type.myBuf(), entry.type.myOffset() + curOff);
        N++;
        final Ref<Integer> newName = new Ref<>(htodl(map.name.ident));
        if (!Res_INTERNALID(newName.get())) {
            // other data, which would be wrong to change via a lookup.
            if (grp.dynamicRefTable.lookupResourceId(newName) != NO_ERROR) {
                ALOGE("Failed resolving ResTable_map name at %d with ident 0x%08x", (int) curEntry, (int) newName.get());
                return UNKNOWN_ERROR;
            }
        }
        boolean isInside;
        int oldName = 0;
        while ((isInside = (curEntry < set.numAttrs)) && (oldName = entries[curEntry].map.name.ident) < newName.get()) {
            if (kDebugTableNoisy) {
                ALOGI("#0x%x: Keeping existing attribute: 0x%08x\n", curEntry, entries[curEntry].map.name.ident);
            }
            curEntry++;
        }
        if ((!isInside) || oldName != newName.get()) {
            // This is a new attribute...  figure out what to do with it.
            if (set.numAttrs >= set.availAttrs) {
                // Need to alloc more memory...
                final int newAvail = set.availAttrs + N;
                // set = (bag_set[])realloc(set,
                // sizeof(bag_set)
                // + sizeof(bag_entry)*newAvail);
                set.resizeBagEntries(newAvail);
                set.availAttrs = newAvail;
                // entries = (bag_entry*)(set+1);
                entries = set.bag_entries;
                if (kDebugTableNoisy) {
                    ALOGI("Reallocated set %s, entries=%s, avail=0x%x\n", set, entries, set.availAttrs);
                }
            }
            if (isInside) {
                // Going in the middle, need to make space.
                // memmove(entries+curEntry+1, entries+curEntry,
                // sizeof(bag_entry)*(set.numAttrs-curEntry));
                System.arraycopy(entries, curEntry, entries, curEntry + 1, set.numAttrs - curEntry);
                entries[curEntry] = null;
                set.numAttrs++;
            }
            if (kDebugTableNoisy) {
                ALOGI("#0x%x: Inserting new attribute: 0x%08x\n", curEntry, newName.get());
            }
        } else {
            if (kDebugTableNoisy) {
                ALOGI("#0x%x: Replacing existing attribute: 0x%08x\n", curEntry, oldName);
            }
        }
        bag_entry cur = entries[curEntry];
        if (cur == null) {
            cur = entries[curEntry] = new bag_entry();
        }
        cur.stringBlock = entry._package_.header.index;
        cur.map.name.ident = newName.get();
        // cur->map.value.copyFrom_dtoh(map->value);
        cur.map.value = map.value;
        final Ref<Res_value> valueRef = new Ref<>(cur.map.value);
        err = grp.dynamicRefTable.lookupResourceValue(valueRef);
        cur.map.value = map.value = valueRef.get();
        if (err != NO_ERROR) {
            ALOGE("Reference item(0x%08x) in bag could not be resolved.", cur.map.value.data);
            return UNKNOWN_ERROR;
        }
        if (kDebugTableNoisy) {
            ALOGI("Setting entry #0x%x %s: block=%d, name=0x%08d, type=%d, data=0x%08x\n", curEntry, cur, cur.stringBlock, cur.map.name.ident, cur.map.value.dataType, cur.map.value.data);
        }
        // On to the next!
        curEntry++;
        pos++;
        final int size = dtohs(map.value.size);
        // curOff += size + sizeof(*map)-sizeof(map->value);
        curOff += size + ResTable_map.SIZEOF - Res_value.SIZEOF;
    }
    ;
    if (curEntry > set.numAttrs) {
        set.numAttrs = curEntry;
    }
    // And this is it...
    typeSet[e] = set;
    if (isTruthy(set)) {
        if (outTypeSpecFlags != NULL) {
            outTypeSpecFlags.set(set.typeSpecFlags);
        }
        outBag.set(set.bag_entries);
        if (kDebugTableNoisy) {
            ALOGI("Returning 0x%x attrs\n", set.numAttrs);
        }
        return set.numAttrs;
    }
    return BAD_INDEX;
}
Also used : ResTable_map(org.robolectric.res.android.ResourceTypes.ResTable_map) Res_value(org.robolectric.res.android.ResourceTypes.Res_value) ResTable_map_entry(org.robolectric.res.android.ResourceTypes.ResTable_map_entry) ResTable_sparseTypeEntry(org.robolectric.res.android.ResourceTypes.ResTable_sparseTypeEntry)

Example 29 with Res_value

use of org.robolectric.res.android.ResourceTypes.Res_value in project robolectric by robolectric.

the class ResTableTheme method applyStyle.

public int applyStyle(int resID, boolean force) {
    AppliedStyle newAppliedStyle = new AppliedStyle(resID, force);
    if (styleDebug) {
        System.out.println("Apply " + newAppliedStyle + " to " + this);
    }
    styles.add(newAppliedStyle);
    final Ref<bag_entry[]> bag = new Ref<>(null);
    final Ref<Integer> bagTypeSpecFlags = new Ref<>(0);
    mTable.lock();
    final int N = mTable.getBagLocked(resID, bag, bagTypeSpecFlags);
    if (kDebugTableNoisy) {
        ALOGV("Applying style 0x%08x to theme %s, count=%d", resID, this, N);
    }
    if (N < 0) {
        mTable.unlock();
        return N;
    }
    mTypeSpecFlags.set(mTypeSpecFlags.get() | bagTypeSpecFlags.get());
    int curPackage = 0xffffffff;
    int curPackageIndex = 0;
    package_info curPI = null;
    int curType = 0xffffffff;
    int numEntries = 0;
    theme_entry[] curEntries = null;
    final int end = N;
    int bagIndex = 0;
    while (bagIndex < end) {
        bag_entry bag_entry = bag.get()[bagIndex];
        final int attrRes = bag_entry.map.name.ident;
        final int p = Res_GETPACKAGE(attrRes);
        final int t = Res_GETTYPE(attrRes);
        final int e = Res_GETENTRY(attrRes);
        if (curPackage != p) {
            final int pidx = mTable.getResourcePackageIndex(attrRes);
            if (pidx < 0) {
                ALOGE("Style contains key with bad package: 0x%08x\n", attrRes);
                bagIndex++;
                continue;
            }
            curPackage = p;
            curPackageIndex = pidx;
            curPI = mPackages[pidx];
            if (curPI == null) {
                curPI = new package_info();
                mPackages[pidx] = curPI;
            }
            curType = 0xffffffff;
        }
        if (curType != t) {
            if (t > Res_MAXTYPE) {
                ALOGE("Style contains key with bad type: 0x%08x\n", attrRes);
                bagIndex++;
                continue;
            }
            curType = t;
            curEntries = curPI.types[t] != null ? curPI.types[t].entries : null;
            if (curEntries == null) {
                final PackageGroup grp = mTable.mPackageGroups.get(curPackageIndex);
                final List<Type> typeList = getOrDefault(grp.types, t, Collections.emptyList());
                int cnt = typeList.isEmpty() ? 0 : typeList.get(0).entryCount;
                curEntries = new theme_entry[cnt];
                // memset(curEntries, Res_value::TYPE_NULL, buff_size);
                curPI.types[t] = new type_info();
                curPI.types[t].numEntries = cnt;
                curPI.types[t].entries = curEntries;
            }
            numEntries = curPI.types[t].numEntries;
        }
        if (e >= numEntries) {
            ALOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
            bagIndex++;
            continue;
        }
        if (curEntries[e] == null) {
            curEntries[e] = new theme_entry();
        }
        theme_entry curEntry = curEntries[e];
        if (styleDebug) {
            ResourceName outName = new ResourceName();
            mTable.getResourceName(attrRes, true, outName);
            System.out.println("  " + outName + "(" + attrRes + ")" + " := " + bag_entry.map.value);
        }
        if (kDebugTableNoisy) {
            ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x", attrRes, bag.get()[bagIndex].map.value.dataType, bag.get()[bagIndex].map.value.data, curEntry.value.dataType);
        }
        if (force || (curEntry.value.dataType == TYPE_NULL && curEntry.value.data != Res_value.DATA_NULL_EMPTY)) {
            curEntry.stringBlock = bag_entry.stringBlock;
            curEntry.typeSpecFlags |= bagTypeSpecFlags.get();
            curEntry.value = new Res_value(bag_entry.map.value);
        }
        bagIndex++;
    }
    mTable.unlock();
    if (kDebugTableTheme) {
        ALOGI("Applying style 0x%08x (force=%s)  theme %s...\n", resID, force, this);
        dumpToLog();
    }
    return NO_ERROR;
}
Also used : Res_value(org.robolectric.res.android.ResourceTypes.Res_value) ResourceName(org.robolectric.res.android.ResTable.ResourceName) PackageGroup(org.robolectric.res.android.ResTable.PackageGroup) Type(org.robolectric.res.android.ResTable.Type) ResTable.bag_entry(org.robolectric.res.android.ResTable.bag_entry)

Example 30 with Res_value

use of org.robolectric.res.android.ResourceTypes.Res_value in project robolectric by robolectric.

the class LoadedArsc method VerifyResTableEntry.

static boolean VerifyResTableEntry(ResTable_type type, int entry_offset) {
    // Check that the offset is aligned.
    if (isTruthy(entry_offset & 0x03)) {
        logError("Entry at offset " + entry_offset + " is not 4-byte aligned.");
        return false;
    }
    // if (entry_offset > std.numeric_limits<int>.max() - dtohl(type.entriesStart)) {
    if (entry_offset > Integer.MAX_VALUE - dtohl(type.entriesStart)) {
        // Overflow in offset.
        logError("Entry at offset " + entry_offset + " is too large.");
        return false;
    }
    int chunk_size = dtohl(type.header.size);
    entry_offset += dtohl(type.entriesStart);
    if (entry_offset > chunk_size - ResTable_entry.SIZEOF) {
        logError("Entry at offset " + entry_offset + " is too large. No room for ResTable_entry.");
        return false;
    }
    // ResTable_entry* entry = reinterpret_cast<ResTable_entry*>(
    // reinterpret_cast<uint8_t*>(type) + entry_offset);
    ResTable_entry entry = new ResTable_entry(type.myBuf(), type.myOffset() + entry_offset);
    int entry_size = dtohs(entry.size);
    // if (entry_size < sizeof(*entry)) {
    if (entry_size < ResTable_entry.SIZEOF) {
        logError("ResTable_entry size " + entry_size + " at offset " + entry_offset + " is too small.");
        return false;
    }
    if (entry_size > chunk_size || entry_offset > chunk_size - entry_size) {
        logError("ResTable_entry size " + entry_size + " at offset " + entry_offset + " is too large.");
        return false;
    }
    if (entry_size < ResTable_map_entry.BASE_SIZEOF) {
        // There needs to be room for one Res_value struct.
        if (entry_offset + entry_size > chunk_size - Res_value.SIZEOF) {
            logError("No room for Res_value after ResTable_entry at offset " + entry_offset + " for type " + (int) type.id + ".");
            return false;
        }
        // Res_value value =
        // reinterpret_cast<Res_value*>(reinterpret_cast<uint8_t*>(entry) + entry_size);
        Res_value value = new Res_value(entry.myBuf(), entry.myOffset() + ResTable_entry.SIZEOF);
        int value_size = dtohs(value.size);
        if (value_size < Res_value.SIZEOF) {
            logError("Res_value at offset " + entry_offset + " is too small.");
            return false;
        }
        if (value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size) {
            logError("Res_value size " + value_size + " at offset " + entry_offset + " is too large.");
            return false;
        }
    } else {
        ResTable_map_entry map = new ResTable_map_entry(entry.myBuf(), entry.myOffset());
        int map_entry_count = dtohl(map.count);
        int map_entries_start = entry_offset + entry_size;
        if (isTruthy(map_entries_start & 0x03)) {
            logError("Map entries at offset " + entry_offset + " start at unaligned offset.");
            return false;
        }
        // Each entry is sizeof(ResTable_map) big.
        if (map_entry_count > ((chunk_size - map_entries_start) / ResTable_map.SIZEOF)) {
            logError("Too many map entries in ResTable_map_entry at offset " + entry_offset + ".");
            return false;
        }
    }
    return true;
}
Also used : Res_value(org.robolectric.res.android.ResourceTypes.Res_value) ResTable_map_entry(org.robolectric.res.android.ResourceTypes.ResTable_map_entry) ResTable_entry(org.robolectric.res.android.ResourceTypes.ResTable_entry)

Aggregations

Res_value (org.robolectric.res.android.ResourceTypes.Res_value)36 Ref (org.robolectric.res.android.Ref)22 Implementation (org.robolectric.annotation.Implementation)21 ResTable_config (org.robolectric.res.android.ResTable_config)16 ApkAssetsCookie (org.robolectric.res.android.ApkAssetsCookie)14 CppAssetManager2 (org.robolectric.res.android.CppAssetManager2)14 ResolvedBag (org.robolectric.res.android.CppAssetManager2.ResolvedBag)14 Nullable (android.annotation.Nullable)6 HiddenApi (org.robolectric.annotation.HiddenApi)6 ResTable (org.robolectric.res.android.ResTable)6 ResTable.bag_entry (org.robolectric.res.android.ResTable.bag_entry)6 CppAssetManager (org.robolectric.res.android.CppAssetManager)5 Entry (org.robolectric.res.android.CppAssetManager2.ResolvedBag.Entry)5 ResStringPool (org.robolectric.res.android.ResStringPool)3 ResTable_map_entry (org.robolectric.res.android.ResourceTypes.ResTable_map_entry)3 CppApkAssets (org.robolectric.res.android.CppApkAssets)2 Theme (org.robolectric.res.android.CppAssetManager2.Theme)2 ResTable_map (org.robolectric.res.android.ResourceTypes.ResTable_map)2 ResTable_sparseTypeEntry (org.robolectric.res.android.ResourceTypes.ResTable_sparseTypeEntry)2 AttributeSet (android.util.AttributeSet)1