static LoadedPackage Load()

in resources/src/main/java/org/robolectric/res/android/LoadedArsc.java [544:785]


    static LoadedPackage Load(Chunk chunk,
        LoadedIdmap loaded_idmap,
        boolean system, boolean load_as_shared_library) {
      // ATRACE_NAME("LoadedPackage::Load");
      LoadedPackage loaded_package = new LoadedPackage();

      // typeIdOffset was added at some point, but we still must recognize apps built before this
      // was added.
      // constexpr int kMinPackageSize =
      //     sizeof(ResTable_package) - sizeof(ResTable_package.typeIdOffset);
      final int kMinPackageSize = ResTable_package.SIZEOF - 4;
      // ResTable_package header = chunk.header<ResTable_package, kMinPackageSize>();
      ResTable_package header = chunk.asResTable_package(kMinPackageSize);
      if (header == null) {
        logError("RES_TABLE_PACKAGE_TYPE too small.");
        return emptyBraces();
      }

      loaded_package.system_ = system;

      loaded_package.package_id_ = dtohl(header.id);
      if (loaded_package.package_id_ == 0 ||
          (loaded_package.package_id_ == kAppPackageId && load_as_shared_library)) {
        // Package ID of 0 means this is a shared library.
        loaded_package.dynamic_ = true;
      }

      if (loaded_idmap != null) {
        // This is an overlay and so it needs to pretend to be the target package.
        loaded_package.package_id_ = loaded_idmap.TargetPackageId();
        loaded_package.overlay_ = true;
      }

      if (header.header.headerSize >= ResTable_package.SIZEOF) {
        int type_id_offset = dtohl(header.typeIdOffset);
        // if (type_id_offset > std.numeric_limits<uint8_t>.max()) {
        if (type_id_offset > 255) {
          logError("RES_TABLE_PACKAGE_TYPE type ID offset too large.");
          return emptyBraces();
        }
        loaded_package.type_id_offset_ = type_id_offset;
      }

      loaded_package.package_name_ = Util
          .ReadUtf16StringFromDevice(header.name, header.name.length);

      // A map of TypeSpec builders, each associated with an type index.
      // We use these to accumulate the set of Types available for a TypeSpec, and later build a single,
      // contiguous block of memory that holds all the Types together with the TypeSpec.
      Map<Integer, TypeSpecPtrBuilder> type_builder_map = new HashMap<>();

      Chunk.Iterator iter = new Iterator(chunk.data_ptr(), chunk.data_size());
      while (iter.HasNext()) {
        Chunk child_chunk = iter.Next();
        switch (child_chunk.type()) {
          case RES_STRING_POOL_TYPE: {
            // uintptr_t pool_address =
            //     reinterpret_cast<uintptr_t>(child_chunk.header<ResChunk_header>());
            // uintptr_t header_address = reinterpret_cast<uintptr_t>(header);
            int pool_address =
                child_chunk.myOffset();
            int header_address = header.myOffset();
            if (pool_address == header_address + dtohl(header.typeStrings)) {
              // This string pool is the type string pool.
              int err = loaded_package.type_string_pool_.setTo(
                  child_chunk.myBuf(), child_chunk.myOffset(), child_chunk.size(), false);
              if (err != NO_ERROR) {
                logError("RES_STRING_POOL_TYPE for types corrupt.");
                return emptyBraces();
              }
            } else if (pool_address == header_address + dtohl(header.keyStrings)) {
              // This string pool is the key string pool.
              int err = loaded_package.key_string_pool_.setTo(
                  child_chunk.myBuf(), child_chunk.myOffset(), child_chunk.size(), false);
              if (err != NO_ERROR) {
                logError("RES_STRING_POOL_TYPE for keys corrupt.");
                return emptyBraces();
              }
            } else {
              logWarning("Too many RES_STRING_POOL_TYPEs found in RES_TABLE_PACKAGE_TYPE.");
            }
          } break;

          case RES_TABLE_TYPE_SPEC_TYPE: {
            ResTable_typeSpec type_spec = new ResTable_typeSpec(child_chunk.myBuf(),
                child_chunk.myOffset());
            if (type_spec == null) {
              logError("RES_TABLE_TYPE_SPEC_TYPE too small.");
              return emptyBraces();
            }

            if (type_spec.id == 0) {
              logError("RES_TABLE_TYPE_SPEC_TYPE has invalid ID 0.");
              return emptyBraces();
            }

            // if (loaded_package.type_id_offset_ + static_cast<int>(type_spec.id) >
            //     std.numeric_limits<uint8_t>.max()) {
            if (loaded_package.type_id_offset_ + type_spec.id > 255) {
              logError("RES_TABLE_TYPE_SPEC_TYPE has out of range ID.");
              return emptyBraces();
            }

            // The data portion of this chunk contains entry_count 32bit entries,
            // each one representing a set of flags.
            // Here we only validate that the chunk is well formed.
            int entry_count = dtohl(type_spec.entryCount);

            // There can only be 2^16 entries in a type, because that is the ID
            // space for entries (EEEE) in the resource ID 0xPPTTEEEE.
            // if (entry_count > std.numeric_limits<short>.max()) {
            if (entry_count > 0xffff) {
              logError("RES_TABLE_TYPE_SPEC_TYPE has too many entries (" + entry_count + ").");
              return emptyBraces();
            }

            if (entry_count * 4 /*sizeof(int)*/ > chunk.data_size()) {
              logError("RES_TABLE_TYPE_SPEC_TYPE too small to hold entries.");
              return emptyBraces();
            }

            // If this is an overlay, associate the mapping of this type to the target type
            // from the IDMAP.
            IdmapEntry_header idmap_entry_header = null;
            if (loaded_idmap != null) {
              idmap_entry_header = loaded_idmap.GetEntryMapForType(type_spec.id);
            }

            TypeSpecPtrBuilder builder_ptr = type_builder_map.get(type_spec.id - 1);
            if (builder_ptr == null) {
              // builder_ptr = util.make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
              builder_ptr = new TypeSpecPtrBuilder(type_spec, idmap_entry_header);
              type_builder_map.put(type_spec.id - 1, builder_ptr);
            } else {
              logWarning(String.format("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
                  type_spec.id));
            }
          } break;

          case RES_TABLE_TYPE_TYPE: {
            // ResTable_type type = child_chunk.header<ResTable_type, kResTableTypeMinSize>();
            ResTable_type type = child_chunk.asResTable_type(kResTableTypeMinSize);
            if (type == null) {
              logError("RES_TABLE_TYPE_TYPE too small.");
              return emptyBraces();
            }

            if (!VerifyResTableType(type)) {
              return emptyBraces();
            }

            // Type chunks must be preceded by their TypeSpec chunks.
            TypeSpecPtrBuilder builder_ptr = type_builder_map.get(type.id - 1);
            if (builder_ptr != null) {
              builder_ptr.AddType(type);
            } else {
              logError(String.format(
                  "RES_TABLE_TYPE_TYPE with ID %02x found without preceding RES_TABLE_TYPE_SPEC_TYPE.",
                  type.id));
              return emptyBraces();
            }
          } break;

          case RES_TABLE_LIBRARY_TYPE: {
            ResTable_lib_header lib = child_chunk.asResTable_lib_header();
            if (lib == null) {
              logError("RES_TABLE_LIBRARY_TYPE too small.");
              return emptyBraces();
            }

            if (child_chunk.data_size() / ResTable_lib_entry.SIZEOF < dtohl(lib.count)) {
              logError("RES_TABLE_LIBRARY_TYPE too small to hold entries.");
              return emptyBraces();
            }

            // loaded_package.dynamic_package_map_.reserve(dtohl(lib.count));

            // ResTable_lib_entry entry_begin =
            //     reinterpret_cast<ResTable_lib_entry*>(child_chunk.data_ptr());
            ResTable_lib_entry entry_begin =
                child_chunk.asResTable_lib_entry();
            // ResTable_lib_entry entry_end = entry_begin + dtohl(lib.count);
            // for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) {
            for (ResTable_lib_entry entry_iter = entry_begin;
                entry_iter.myOffset() != entry_begin.myOffset() + dtohl(lib.count);
                entry_iter = new ResTable_lib_entry(entry_iter.myBuf(), entry_iter.myOffset() + ResTable_lib_entry.SIZEOF)) {
              String package_name =
                  Util.ReadUtf16StringFromDevice(entry_iter.packageName,
                      entry_iter.packageName.length);
              
              if (dtohl(entry_iter.packageId) >= 255) {
                logError(String.format(
                    "Package ID %02x in RES_TABLE_LIBRARY_TYPE too large for package '%s'.",
                    dtohl(entry_iter.packageId), package_name));
                return emptyBraces();
              }

              // loaded_package.dynamic_package_map_.emplace_back(std.move(package_name),
              //     dtohl(entry_iter.packageId));
              loaded_package.dynamic_package_map_.add(new DynamicPackageEntry(package_name,
                  dtohl(entry_iter.packageId)));
            }

          } break;

          default:
            logWarning(String.format("Unknown chunk type '%02x'.", chunk.type()));
            break;
        }
      }

      if (iter.HadError()) {
        logError(iter.GetLastError());
        if (iter.HadFatalError()) {
          return emptyBraces();
        }
      }

      // Flatten and construct the TypeSpecs.
      for (Entry<Integer, TypeSpecPtrBuilder> entry : type_builder_map.entrySet()) {
        byte type_idx = (byte) entry.getKey().byteValue();
        TypeSpec type_spec_ptr = entry.getValue().Build();
        if (type_spec_ptr == null) {
          logError("Too many type configurations, overflow detected.");
          return emptyBraces();
        }

        // We only add the type to the package if there is no IDMAP, or if the type is
        // overlaying something.
        if (loaded_idmap == null || type_spec_ptr.idmap_entries != null) {
          // If this is an overlay, insert it at the target type ID.
          if (type_spec_ptr.idmap_entries != null) {
            type_idx = (byte) (dtohs(type_spec_ptr.idmap_entries.target_type_id) - 1);
          }
          // loaded_package.type_specs_.editItemAt(type_idx) = std.move(type_spec_ptr);
          loaded_package.type_specs_.put((int) type_idx, type_spec_ptr);
        }
      }

      // return std.move(loaded_package);
      return loaded_package;
    }