All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robolectric.res.android.DynamicRefTable Maven / Gradle / Ivy

There is a newer version: 4.14.1
Show newest version
package org.robolectric.res.android;

// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/include/androidfw/ResourceTypes.h

import static org.robolectric.res.android.Errors.NO_ERROR;
import static org.robolectric.res.android.Errors.UNKNOWN_ERROR;
import static org.robolectric.res.android.ResTable.APP_PACKAGE_ID;
import static org.robolectric.res.android.ResTable.Res_GETPACKAGE;
import static org.robolectric.res.android.ResTable.SYS_PACKAGE_ID;
import static org.robolectric.res.android.Util.ALOGW;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.robolectric.res.android.ResourceTypes.Res_value;

/**
 * Holds the shared library ID table. Shared libraries are assigned package IDs at
 * build time, but they may be loaded in a different order, so we need to maintain
 * a mapping of build-time package ID to run-time assigned package ID.
 *
 * Dynamic references are not currently supported in overlays. Only the base package
 * may have dynamic references.
 */
public class DynamicRefTable
{
  DynamicRefTable(byte packageId, boolean appAsLib) {
    this.mAssignedPackageId = packageId;
    this.mAppAsLib = appAsLib;

    mLookupTable[APP_PACKAGE_ID] = APP_PACKAGE_ID;
    mLookupTable[SYS_PACKAGE_ID] = SYS_PACKAGE_ID;
  }

//  // Loads an unmapped reference table from the package.
//  Errors load(final ResTable_lib_header header) {
//    return null;
//  }

  // Adds mappings from the other DynamicRefTable
  int addMappings(final DynamicRefTable other) {
    if (mAssignedPackageId != other.mAssignedPackageId) {
      return UNKNOWN_ERROR;
    }

//    final int entryCount = other.mEntries.size();
//    for (size_t i = 0; i < entryCount; i++) {
//      ssize_t index = mEntries.indexOfKey(other.mEntries.keyAt(i));
//      if (index < 0) {
//        mEntries.add(other.mEntries.keyAt(i), other.mEntries[i]);
//      } else {
//        if (other.mEntries[i] != mEntries[index]) {
//          return UNKNOWN_ERROR;
//        }
//      }
//    }
    for (Entry otherEntry : other.mEntries.entrySet()) {
      String key = otherEntry.getKey();
      Byte curValue = mEntries.get(key);
      if (curValue == null) {
        mEntries.put(key, otherEntry.getValue());
      } else {
        if (!Objects.equals(otherEntry.getValue(), curValue)) {
          return UNKNOWN_ERROR;
        }
      }
    }

    // Merge the lookup table. No entry can conflict
    // (value of 0 means not set).
    for (int i = 0; i < 256; i++) {
      if (mLookupTable[i] != other.mLookupTable[i]) {
        if (mLookupTable[i] == 0) {
          mLookupTable[i] = other.mLookupTable[i];
        } else if (other.mLookupTable[i] != 0) {
          return UNKNOWN_ERROR;
        }
      }
    }
    return NO_ERROR;
  }

  // Creates a mapping from build-time package ID to run-time package ID for
  // the given package.
  int addMapping(final String packageName, byte packageId) {
    Byte index = mEntries.get(packageName);
    if (index == null) {
      return UNKNOWN_ERROR;
    }
    mLookupTable[index] = packageId;
    return NO_ERROR;
  }

  void addAlias(int stagedId, int finalizedId) {
    mAliasId.put(stagedId, finalizedId);
  }

//  // Performs the actual conversion of build-time resource ID to run-time
//  // resource ID.
  int lookupResourceId(Ref resId) {
    int res = resId.get();
    int packageId = Res_GETPACKAGE(res) + 1;

    Integer aliasId = mAliasId.get(res);
    if (aliasId != null) {
      // Rewrite the resource id to its alias resource id. Since the alias resource id is a
      // compile-time id, it still needs to be resolved further.
      res = aliasId;
    }

    if (packageId == SYS_PACKAGE_ID || (packageId == APP_PACKAGE_ID && !mAppAsLib)) {
      // No lookup needs to be done, app and framework package IDs are absolute.
      resId.set(res);
      return NO_ERROR;
    }

    if (packageId == 0 || (packageId == APP_PACKAGE_ID && mAppAsLib)) {
      // The package ID is 0x00. That means that a shared library is accessing
      // its own local resource.
      // Or if app resource is loaded as shared library, the resource which has
      // app package Id is local resources.
      // so we fix up those resources with the calling package ID.
      resId.set((0xFFFFFF & resId.get()) | (((int) mAssignedPackageId) << 24));
      return NO_ERROR;
    }

    // Do a proper lookup.
    int translatedId = mLookupTable[packageId];
    if (translatedId == 0) {
      ALOGW("DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.",
          mAssignedPackageId, packageId);
      for (int i = 0; i < 256; i++) {
        if (mLookupTable[i] != 0) {
          ALOGW("e[0x%02x] . 0x%02x", i, mLookupTable[i]);
        }
      }
      return UNKNOWN_ERROR;
    }

    resId.set((res & 0x00ffffff) | (((int) translatedId) << 24));
    return NO_ERROR;
  }
//
  int lookupResourceValue(Ref 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;
        }

        // If the package is loaded as shared library, the resource reference
        // also need to be fixed.
        break;
      case DYNAMIC_ATTRIBUTE:
        resolvedType = DataType.ATTRIBUTE.code();
        // fallthrough
      case DYNAMIC_REFERENCE:
        break;
      default:
        return NO_ERROR;
    }

    final Ref 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;
 }

  public Map entries() {
    return mEntries;
  }

  //
//  final KeyedVector& entries() final {
//  return mEntries;
//}
//
//  private:
    final byte                   mAssignedPackageId;
  final byte[]                         mLookupTable = new byte[256];
  final Map mEntries = new HashMap<>();
  boolean                            mAppAsLib;
  final Map mAliasId = new HashMap<>();
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy