/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef AAPT_FORMAT_BINARY_RESENTRY_SERIALIZER_H #define AAPT_FORMAT_BINARY_RESENTRY_SERIALIZER_H #include #include "ResourceTable.h" #include "ValueVisitor.h" #include "android-base/macros.h" #include "androidfw/BigBuffer.h" #include "androidfw/ResourceTypes.h" namespace aapt { struct FlatEntry { const ResourceTableEntryView* entry; const Value* value; // The entry string pool index to the entry's name. uint32_t entry_key; }; // Pair of ResTable_entry and Res_value. These pairs are stored sequentially in values buffer. // We introduce this structure for ResEntryWriter to a have single allocation using // BigBuffer::NextBlock which allows to return it back with BigBuffer::Backup. struct ResEntryValuePair { android::ResTable_entry entry; android::Res_value value; }; // References ResEntryValuePair object stored in BigBuffer used as a key in std::unordered_map. // Allows access to memory address where ResEntryValuePair is stored. union ResEntryValuePairRef { const std::reference_wrapper pair; const u_char* ptr; explicit ResEntryValuePairRef(const ResEntryValuePair& ref) : pair(ref) { } }; // Hasher which computes hash of ResEntryValuePair using its bytes representation in memory. struct ResEntryValuePairContentHasher { std::size_t operator()(const ResEntryValuePairRef& ref) const; }; // Equaler which compares ResEntryValuePairs using theirs bytes representation in memory. struct ResEntryValuePairContentEqualTo { bool operator()(const ResEntryValuePairRef& a, const ResEntryValuePairRef& b) const; }; // Base class that allows to write FlatEntries into entries_buffer. class ResEntryWriter { public: virtual ~ResEntryWriter() = default; // Writes resource table entry and its value into 'entries_buffer_' and returns offset // in the buffer where entry was written. int32_t Write(const FlatEntry* entry) { if (ValueCast(entry->value) != nullptr) { return WriteItem(entry); } else { return WriteMap(entry); } } protected: ResEntryWriter(android::BigBuffer* entries_buffer) : entries_buffer_(entries_buffer) { } android::BigBuffer* entries_buffer_; virtual int32_t WriteItem(const FlatEntry* entry) = 0; virtual int32_t WriteMap(const FlatEntry* entry) = 0; private: DISALLOW_COPY_AND_ASSIGN(ResEntryWriter); }; // ResEntryWriter which writes FlatEntries sequentially into entries_buffer. // Next entry is always written right after previous one in the buffer. class SequentialResEntryWriter : public ResEntryWriter { public: explicit SequentialResEntryWriter(android::BigBuffer* entries_buffer) : ResEntryWriter(entries_buffer) { } ~SequentialResEntryWriter() override = default; int32_t WriteItem(const FlatEntry* entry) override; int32_t WriteMap(const FlatEntry* entry) override; private: DISALLOW_COPY_AND_ASSIGN(SequentialResEntryWriter); }; // ResEntryWriter that writes only unique entry and value pairs into entries_buffer. // Next entry is written into buffer only if there is no entry with the same bytes representation // in memory written before. Otherwise returns offset of already written entry. class DeduplicateItemsResEntryWriter : public ResEntryWriter { public: explicit DeduplicateItemsResEntryWriter(android::BigBuffer* entries_buffer) : ResEntryWriter(entries_buffer) { } ~DeduplicateItemsResEntryWriter() override = default; int32_t WriteItem(const FlatEntry* entry) override; int32_t WriteMap(const FlatEntry* entry) override; private: DISALLOW_COPY_AND_ASSIGN(DeduplicateItemsResEntryWriter); std::unordered_map entry_offsets; }; } // namespace aapt #endif