Search in sources :

Example 1 with LoadedPackage

use of org.robolectric.res.android.LoadedArsc.LoadedPackage in project robolectric by robolectric.

the class CppAssetManager2 method GetResourceName.

// Populates the `out_name` parameter with resource name information.
// Utf8 strings are preferred, and only if they are unavailable are
// the Utf16 variants populated.
// Returns false if the resource was not found or the name was missing/corrupt.
// boolean GetResourceName(int resid, ResourceName* out_name);
public boolean GetResourceName(int resid, ResourceName out_name) {
    final Ref<FindEntryResult> entryRef = new Ref<>(null);
    ApkAssetsCookie cookie = FindEntry(resid, (short) 0, /* density_override */
    true, /* stop_at_first_match */
    entryRef);
    if (cookie.intValue() == kInvalidCookie) {
        return false;
    }
    final LoadedPackage package_ = apk_assets_.get(cookie.intValue()).GetLoadedArsc().GetPackageById(get_package_id(resid));
    if (package_ == null) {
        return false;
    }
    out_name.package_ = package_.GetPackageName();
    // out_name.package_len = out_name.package_.length();
    FindEntryResult entry = entryRef.get();
    out_name.type = entry.type_string_ref.string();
    // out_name.type16 = null;
    if (out_name.type == null) {
        // if (out_name.type16 == null) {
        return false;
    // }
    }
    out_name.entry = entry.entry_string_ref.string();
    // out_name.entry16 = null;
    if (out_name.entry == null) {
        // if (out_name.entry16 == null) {
        return false;
    // }
    }
    return true;
}
Also used : LoadedPackage(org.robolectric.res.android.LoadedArsc.LoadedPackage)

Example 2 with LoadedPackage

use of org.robolectric.res.android.LoadedArsc.LoadedPackage in project robolectric by robolectric.

the class CppAssetManager2 method GetResourceId.

// Finds the resource ID assigned to `resource_name`.
// `resource_name` must be of the form '[package:][type/]entry'.
// If no package is specified in `resource_name`, then `fallback_package` is used as the package.
// If no type is specified in `resource_name`, then `fallback_type` is used as the type.
// Returns 0x0 if no resource by that name was found.
// int GetResourceId(final String resource_name, final String fallback_type = {},
// final String fallback_package = {});
@SuppressWarnings("NewApi")
public int GetResourceId(final String resource_name, final String fallback_type, final String fallback_package) {
    final Ref<String> package_name = new Ref<>(null), type = new Ref<>(null), entry = new Ref<>(null);
    if (!ExtractResourceName(resource_name, package_name, type, entry)) {
        return 0;
    }
    if (entry.get().isEmpty()) {
        return 0;
    }
    if (package_name.get().isEmpty()) {
        package_name.set(fallback_package);
    }
    if (type.get().isEmpty()) {
        type.set(fallback_type);
    }
    String type16 = type.get();
    // if (!Utf8ToUtf16(type, &type16)) {
    // return 0;
    // }
    String entry16 = entry.get();
    // if (!Utf8ToUtf16(entry, &entry16)) {
    // return 0;
    // }
    final String kAttr16 = "attr";
    final String kAttrPrivate16 = "^attr-private";
    for (final PackageGroup package_group : package_groups_) {
        for (final ConfiguredPackage package_impl : package_group.packages_) {
            LoadedPackage package_ = package_impl.loaded_package_;
            if (!Objects.equals(package_name.get(), package_.GetPackageName())) {
                // All packages in the same group are expected to have the same package name.
                break;
            }
            int resid = package_.FindEntryByName(type16, entry16);
            if (resid == 0 && Objects.equals(kAttr16, type16)) {
                // Private attributes in libraries (such as the framework) are sometimes encoded
                // under the type '^attr-private' in order to leave the ID space of public 'attr'
                // free for future additions. Check '^attr-private' for the same name.
                resid = package_.FindEntryByName(kAttrPrivate16, entry16);
            }
            if (resid != 0) {
                return fix_package_id(resid, package_group.dynamic_ref_table.mAssignedPackageId);
            }
        }
    }
    return 0;
}
Also used : LoadedPackage(org.robolectric.res.android.LoadedArsc.LoadedPackage)

Example 3 with LoadedPackage

use of org.robolectric.res.android.LoadedArsc.LoadedPackage in project robolectric by robolectric.

the class CppAssetManager2 method FindEntry.

// Finds the best entry for `resid` from the set of ApkAssets. The entry can be a simple
// Res_value, or a complex map/bag type. If successful, it is available in `out_entry`.
// Returns kInvalidCookie on failure. Otherwise, the return value is the cookie associated with
// the ApkAssets in which the entry was found.
// 
// `density_override` overrides the density of the current configuration when doing a search.
// 
// When `stop_at_first_match` is true, the first match found is selected and the search
// terminates. This is useful for methods that just look up the name of a resource and don't
// care about the value. In this case, the value of `FindEntryResult::type_flags` is incomplete
// and should not be used.
// 
// NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
// bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
// ApkAssetsCookie FindEntry(int resid, short density_override, boolean stop_at_first_match,
// LoadedArscEntry* out_entry, ResTable_config out_selected_config,
// int* out_flags);
private ApkAssetsCookie FindEntry(int resid, short density_override, boolean stop_at_first_match, final Ref<FindEntryResult> out_entry) {
    ATRACE_CALL();
    // Might use this if density_override != 0.
    ResTable_config density_override_config;
    // Select our configuration or generate a density override configuration.
    ResTable_config desired_config = configuration_;
    if (density_override != 0 && density_override != configuration_.density) {
        density_override_config = configuration_;
        density_override_config.density = density_override;
        desired_config = density_override_config;
    }
    if (!is_valid_resid(resid)) {
        System.err.println(String.format("Invalid ID 0x%08x.", resid));
        return K_INVALID_COOKIE;
    }
    final int package_id = get_package_id(resid);
    final int type_idx = (byte) (get_type_id(resid) - 1);
    final int entry_idx = get_entry_id(resid);
    final byte package_idx = package_ids_[package_id];
    if (package_idx == (byte) 0xff) {
        System.err.println(String.format("No package ID %02x found for ID 0x%08x.", package_id, resid));
        return K_INVALID_COOKIE;
    }
    final PackageGroup package_group = package_groups_.get(package_idx);
    final int package_count = package_group.packages_.size();
    ApkAssetsCookie best_cookie = K_INVALID_COOKIE;
    LoadedPackage best_package = null;
    ResTable_type best_type = null;
    ResTable_config best_config = null;
    ResTable_config best_config_copy;
    int best_offset = 0;
    int type_flags = 0;
    // If desired_config is the same as the set configuration, then we can use our filtered list
    // and we don't need to match the configurations, since they already matched.
    boolean use_fast_path = desired_config == configuration_;
    for (int pi = 0; pi < package_count; pi++) {
        ConfiguredPackage loaded_package_impl = package_group.packages_.get(pi);
        LoadedPackage loaded_package = loaded_package_impl.loaded_package_;
        ApkAssetsCookie cookie = package_group.cookies_.get(pi);
        // If the type IDs are offset in this package, we need to take that into account when searching
        // for a type.
        TypeSpec type_spec = loaded_package.GetTypeSpecByTypeIndex(type_idx);
        if (Util.UNLIKELY(type_spec == null)) {
            continue;
        }
        int local_entry_idx = entry_idx;
        // If there is an IDMAP supplied with this package, translate the entry ID.
        if (type_spec.idmap_entries != null) {
            if (!LoadedIdmap.Lookup(type_spec.idmap_entries, local_entry_idx, new Ref<>(local_entry_idx))) {
                // There is no mapping, so the resource is not meant to be in this overlay package.
                continue;
            }
        }
        type_flags |= type_spec.GetFlagsForEntryIndex(local_entry_idx);
        // If the package is an overlay, then even configurations that are the same MUST be chosen.
        boolean package_is_overlay = loaded_package.IsOverlay();
        FilteredConfigGroup filtered_group = loaded_package_impl.filtered_configs_.get(type_idx);
        if (use_fast_path) {
            List<ResTable_config> candidate_configs = filtered_group.configurations;
            int type_count = candidate_configs.size();
            for (int i = 0; i < type_count; i++) {
                ResTable_config this_config = candidate_configs.get(i);
                // configurations that do NOT match have been filtered-out.
                if ((best_config == null || this_config.isBetterThan(best_config, desired_config)) || (package_is_overlay && this_config.compare(best_config) == 0)) {
                    // The configuration matches and is better than the previous selection.
                    // Find the entry value if it exists for this configuration.
                    ResTable_type type_chunk = filtered_group.types.get(i);
                    int offset = LoadedPackage.GetEntryOffset(type_chunk, local_entry_idx);
                    if (offset == ResTable_type.NO_ENTRY) {
                        continue;
                    }
                    best_cookie = cookie;
                    best_package = loaded_package;
                    best_type = type_chunk;
                    best_config = this_config;
                    best_offset = offset;
                }
            }
        } else {
            // for (auto iter = type_spec.types; iter != iter_end; ++iter) {
            for (ResTable_type type : type_spec.types) {
                ResTable_config this_config = ResTable_config.fromDtoH(type.config);
                if (this_config.match(desired_config)) {
                    if ((best_config == null || this_config.isBetterThan(best_config, desired_config)) || (package_is_overlay && this_config.compare(best_config) == 0)) {
                        // The configuration matches and is better than the previous selection.
                        // Find the entry value if it exists for this configuration.
                        int offset = LoadedPackage.GetEntryOffset(type, local_entry_idx);
                        if (offset == ResTable_type.NO_ENTRY) {
                            continue;
                        }
                        best_cookie = cookie;
                        best_package = loaded_package;
                        best_type = type;
                        best_config_copy = this_config;
                        best_config = best_config_copy;
                        best_offset = offset;
                    }
                }
            }
        }
    }
    if (Util.UNLIKELY(best_cookie.intValue() == kInvalidCookie)) {
        return K_INVALID_COOKIE;
    }
    ResTable_entry best_entry = LoadedPackage.GetEntryFromOffset(best_type, best_offset);
    if (Util.UNLIKELY(best_entry == null)) {
        return K_INVALID_COOKIE;
    }
    FindEntryResult out_entry_ = new FindEntryResult();
    out_entry_.entry = best_entry;
    out_entry_.config = best_config;
    out_entry_.type_flags = type_flags;
    out_entry_.type_string_ref = new StringPoolRef(best_package.GetTypeStringPool(), best_type.id - 1);
    out_entry_.entry_string_ref = new StringPoolRef(best_package.GetKeyStringPool(), best_entry.key.index);
    out_entry_.dynamic_ref_table = package_group.dynamic_ref_table;
    out_entry.set(out_entry_);
    return best_cookie;
}
Also used : ResTable_entry(org.robolectric.res.android.ResourceTypes.ResTable_entry) LoadedPackage(org.robolectric.res.android.LoadedArsc.LoadedPackage) ResTable_type(org.robolectric.res.android.ResourceTypes.ResTable_type) TypeSpec(org.robolectric.res.android.LoadedArsc.TypeSpec)

Example 4 with LoadedPackage

use of org.robolectric.res.android.LoadedArsc.LoadedPackage in project robolectric by robolectric.

the class CppAssetManager2 method BuildDynamicRefTable.

// Assigns package IDs to all shared library ApkAssets.
// Should be called whenever the ApkAssets are changed.
// void BuildDynamicRefTable();
void BuildDynamicRefTable() {
    package_groups_.clear();
    // package_ids_.fill(0xff);
    for (int i = 0; i < package_ids_.length; i++) {
        package_ids_[i] = (byte) 0xff;
    }
    // 0x01 is reserved for the android package.
    int next_package_id = 0x02;
    final int apk_assets_count = apk_assets_.size();
    for (int i = 0; i < apk_assets_count; i++) {
        final LoadedArsc loaded_arsc = apk_assets_.get(i).GetLoadedArsc();
        // for (final std.unique_ptr<final LoadedPackage>& package_ :
        for (final LoadedPackage package_ : loaded_arsc.GetPackages()) {
            // Get the package ID or assign one if a shared library.
            int package_id;
            if (package_.IsDynamic()) {
                package_id = next_package_id++;
            } else {
                package_id = package_.GetPackageId();
            }
            // Add the mapping for package ID to index if not present.
            byte idx = package_ids_[package_id];
            if (idx == (byte) 0xff) {
                // package_ids_[package_id] = idx = static_cast<byte>(package_groups_.size());
                package_ids_[package_id] = idx = (byte) package_groups_.size();
                // DynamicRefTable& ref_table = package_groups_.back().dynamic_ref_table;
                // ref_table.mAssignedPackageId = package_id;
                // ref_table.mAppAsLib = package->IsDynamic() && package->GetPackageId() == 0x7f;
                DynamicRefTable ref_table = new DynamicRefTable((byte) package_id, package_.IsDynamic() && package_.GetPackageId() == 0x7f);
                PackageGroup newPackageGroup = new PackageGroup();
                newPackageGroup.dynamic_ref_table = ref_table;
                package_groups_.add(newPackageGroup);
            }
            PackageGroup package_group = package_groups_.get(idx);
            // Add the package and to the set of packages with the same ID.
            // package_group->packages_.push_back(ConfiguredPackage{package.get(), {}});
            // package_group.cookies_.push_back(static_cast<ApkAssetsCookie>(i));
            package_group.packages_.add(new ConfiguredPackage(package_));
            package_group.cookies_.add(ApkAssetsCookie.forInt(i));
            // Add the package name . build time ID mappings.
            for (final DynamicPackageEntry entry : package_.GetDynamicPackageMap()) {
                // String package_name(entry.package_name.c_str(), entry.package_name.size());
                package_group.dynamic_ref_table.mEntries.put(entry.package_name, (byte) entry.package_id);
            }
        }
    }
    // Now assign the runtime IDs so that we have a build-time to runtime ID map.
    for (PackageGroup iter : package_groups_) {
        String package_name = iter.packages_.get(0).loaded_package_.GetPackageName();
        for (PackageGroup iter2 : package_groups_) {
            iter2.dynamic_ref_table.addMapping(package_name, iter.dynamic_ref_table.mAssignedPackageId);
        }
    }
}
Also used : LoadedPackage(org.robolectric.res.android.LoadedArsc.LoadedPackage) DynamicPackageEntry(org.robolectric.res.android.LoadedArsc.DynamicPackageEntry)

Aggregations

LoadedPackage (org.robolectric.res.android.LoadedArsc.LoadedPackage)4 DynamicPackageEntry (org.robolectric.res.android.LoadedArsc.DynamicPackageEntry)1 TypeSpec (org.robolectric.res.android.LoadedArsc.TypeSpec)1 ResTable_entry (org.robolectric.res.android.ResourceTypes.ResTable_entry)1 ResTable_type (org.robolectric.res.android.ResourceTypes.ResTable_type)1