Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f1f4fc1 authored by Mårten Kongstad's avatar Mårten Kongstad
Browse files

libandroidfw: add resource ID iterator

Add an iterator to LoadedPackage which allows the caller to iterate over
the resource IDs in the package. This will be used by idmap when
constructing the idmap file.

Bug: 78815803
Test: make libandroidfw_tests
Change-Id: Ia47daa21390d67ea2ef3665e88eb407837c4764f
parent 0b925f85
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -203,6 +203,39 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset
  return true;
}

LoadedPackage::iterator::iterator(const LoadedPackage* lp, size_t ti, size_t ei)
    : loadedPackage_(lp),
      typeIndex_(ti),
      entryIndex_(ei),
      typeIndexEnd_(lp->resource_ids_.size() + 1) {
  while (typeIndex_ < typeIndexEnd_ && loadedPackage_->resource_ids_[typeIndex_] == 0) {
    typeIndex_++;
  }
}

LoadedPackage::iterator& LoadedPackage::iterator::operator++() {
  while (typeIndex_ < typeIndexEnd_) {
    if (entryIndex_ + 1 < loadedPackage_->resource_ids_[typeIndex_]) {
      entryIndex_++;
      break;
    }
    entryIndex_ = 0;
    typeIndex_++;
    if (typeIndex_ < typeIndexEnd_ && loadedPackage_->resource_ids_[typeIndex_] != 0) {
      break;
    }
  }
  return *this;
}

uint32_t LoadedPackage::iterator::operator*() const {
  if (typeIndex_ >= typeIndexEnd_) {
    return 0;
  }
  return make_resid(loadedPackage_->package_id_, typeIndex_ + loadedPackage_->type_id_offset_,
          entryIndex_);
}

const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
                                              uint16_t entry_index) {
  uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
@@ -488,6 +521,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
        std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
        if (builder_ptr == nullptr) {
          builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
          loaded_package->resource_ids_.set(type_spec->id, entry_count);
        } else {
          LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
                                       type_spec->id);
+50 −0
Original line number Diff line number Diff line
@@ -78,6 +78,55 @@ using TypeSpecPtr = util::unique_cptr<TypeSpec>;

class LoadedPackage {
 public:
  class iterator {
   public:
    iterator& operator=(const iterator& rhs) {
      loadedPackage_ = rhs.loadedPackage_;
      typeIndex_ = rhs.typeIndex_;
      entryIndex_ = rhs.entryIndex_;
      return *this;
    }

    bool operator==(const iterator& rhs) const {
      return loadedPackage_ == rhs.loadedPackage_ &&
             typeIndex_ == rhs.typeIndex_ &&
             entryIndex_ == rhs.entryIndex_;
    }

    bool operator!=(const iterator& rhs) const {
      return !(*this == rhs);
    }

    iterator operator++(int) {
      size_t prevTypeIndex_ = typeIndex_;
      size_t prevEntryIndex_ = entryIndex_;
      operator++();
      return iterator(loadedPackage_, prevTypeIndex_, prevEntryIndex_);
    }

    iterator& operator++();

    uint32_t operator*() const;

   private:
    friend class LoadedPackage;

    iterator(const LoadedPackage* lp, size_t ti, size_t ei);

    const LoadedPackage* loadedPackage_;
    size_t typeIndex_;
    size_t entryIndex_;
    const size_t typeIndexEnd_;  // STL style end, so one past the last element
  };

  iterator begin() const {
    return iterator(this, 0, 0);
  }

  iterator end() const {
    return iterator(this, resource_ids_.size() + 1, 0);
  }

  static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk,
                                                   const LoadedIdmap* loaded_idmap, bool system,
                                                   bool load_as_shared_library);
@@ -182,6 +231,7 @@ class LoadedPackage {
  bool overlay_ = false;

  ByteBucketArray<TypeSpecPtr> type_specs_;
  ByteBucketArray<uint32_t> resource_ids_;
  std::vector<DynamicPackageEntry> dynamic_package_map_;
};

+48 −0
Original line number Diff line number Diff line
@@ -278,4 +278,52 @@ TEST(LoadedArscTest, LoadOverlay) {
// sizeof(Res_value) might not be backwards compatible.
TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }

TEST(LoadedArscTest, ResourceIdentifierIterator) {
  std::string contents;
  ASSERT_TRUE(
      ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));

  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
  ASSERT_NE(nullptr, loaded_arsc);

  const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
  ASSERT_EQ(1u, packages.size());
  EXPECT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName());

  const auto& loaded_package = packages[0];
  auto iter = loaded_package->begin();
  auto end = loaded_package->end();

  ASSERT_NE(end, iter);
  ASSERT_EQ(0x7f010000u, *iter++);
  ASSERT_EQ(0x7f010001u, *iter++);
  ASSERT_EQ(0x7f020000u, *iter++);
  ASSERT_EQ(0x7f020001u, *iter++);
  ASSERT_EQ(0x7f030000u, *iter++);
  ASSERT_EQ(0x7f030001u, *iter++);
  ASSERT_EQ(0x7f030002u, *iter++);  // note: string without default, excluded by aapt2 dump
  ASSERT_EQ(0x7f040000u, *iter++);
  ASSERT_EQ(0x7f040001u, *iter++);
  ASSERT_EQ(0x7f040002u, *iter++);
  ASSERT_EQ(0x7f040003u, *iter++);
  ASSERT_EQ(0x7f040004u, *iter++);
  ASSERT_EQ(0x7f040005u, *iter++);
  ASSERT_EQ(0x7f040006u, *iter++);
  ASSERT_EQ(0x7f040007u, *iter++);
  ASSERT_EQ(0x7f040008u, *iter++);
  ASSERT_EQ(0x7f040009u, *iter++);
  ASSERT_EQ(0x7f04000au, *iter++);
  ASSERT_EQ(0x7f04000bu, *iter++);
  ASSERT_EQ(0x7f04000cu, *iter++);
  ASSERT_EQ(0x7f04000du, *iter++);
  ASSERT_EQ(0x7f050000u, *iter++);
  ASSERT_EQ(0x7f050001u, *iter++);
  ASSERT_EQ(0x7f060000u, *iter++);
  ASSERT_EQ(0x7f070000u, *iter++);
  ASSERT_EQ(0x7f070001u, *iter++);
  ASSERT_EQ(0x7f070002u, *iter++);
  ASSERT_EQ(0x7f070003u, *iter++);
  ASSERT_EQ(end, iter);
}

}  // namespace android