libresource/utils/Visitor.h (84 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #ifndef _FB_ANDROID_VISITOR_H #define _FB_ANDROID_VISITOR_H #include <string> #include <vector> #include "androidfw/ResourceTypes.h" namespace arsc { // Helper methods regarding the serialization format. void collect_spans(android::ResStringPool_span* ptr, std::vector<android::ResStringPool_span*>* out); // Class to traverse various structures in resources.arsc file. Callers should // override various methods that are relevant for their use case. Mutating data // is allowed, though traversal logic will not expect anything data to change // its size (so only use this to make simple edits like changing IDs, changing // string pool references, etc). class ResourceTableVisitor { public: virtual bool visit(void* data, size_t len); virtual bool visit_table(android::ResTable_header* table); virtual bool visit_global_strings(android::ResStringPool_header* pool); // There can be many packages virtual bool visit_package(android::ResTable_package* package); virtual bool visit_type_strings(android::ResTable_package* package, android::ResStringPool_header* pool); virtual bool visit_key_strings(android::ResTable_package* package, android::ResStringPool_header* pool); // One type spec will exist per type in the package. virtual bool visit_type_spec(android::ResTable_package* package, android::ResTable_typeSpec* type_spec); // Per type spec, many types can exist for the entries in various // configurations (i.e. differnet locales, landscape vs portrait, etc). virtual bool visit_type(android::ResTable_package* package, android::ResTable_typeSpec* type_spec, android::ResTable_type* type); // Visit a basic entry and its value. virtual bool visit_entry(android::ResTable_package* package, android::ResTable_typeSpec* type_spec, android::ResTable_type* type, android::ResTable_entry* entry, android::Res_value* value); // Visit a map entry. Values, if any will be dispatched to separate calls. virtual bool visit_map_entry(android::ResTable_package* package, android::ResTable_typeSpec* type_spec, android::ResTable_type* type, android::ResTable_map_entry* entry); // Visit a map entry and its value (called many times for the same // android::ResTable_map_entry* pointer for the N ResTable_map* pointers). virtual bool visit_map_value(android::ResTable_package* package, android::ResTable_typeSpec* type_spec, android::ResTable_type* type, android::ResTable_map_entry* entry, android::ResTable_map* value); // Callback for a chunk type that was not recognized (the format does change) virtual bool visit_unknown_chunk(android::ResTable_package* package, android::ResChunk_header* header); virtual ~ResourceTableVisitor() {} // Returns how far into the file this pointer is. long get_file_offset(const void* ptr) { auto delta = (const uint8_t*)ptr - (const uint8_t*)m_data; LOG_FATAL_IF(delta < 0, "Chunk %p is smaller than file start %p.", ptr, m_data); LOG_FATAL_IF(delta >= (long)m_length, "Chunk %p is beyond file end. Start = %p, Length = %zu", ptr, m_data, m_length); return delta; } private: bool valid(const android::ResTable_package*); bool valid(const android::ResTable_typeSpec*); bool valid(const android::ResTable_type*); void* m_data; size_t m_length; }; // A visitor that can find string pool references into multiple different pools! // This, by default will traverse Res_value structs, which index into the global // string pool, and Entries, which index into the key strings pool. class StringPoolRefVisitor : public ResourceTableVisitor { public: // Meant to be overridden by sub classes if they need to access/edit key // strings. virtual bool visit_key_strings_ref(android::ResTable_package* package, android::ResStringPool_ref* ref); // Meant to be overridden by sub class if they need to access/edit global key // strings. virtual bool visit_global_strings_ref(android::Res_value* ref); // Meant to be overridden by sub class if they need to access/edit global key // strings. This method is for a style pointer into the global string pool. virtual bool visit_global_strings_ref(android::ResStringPool_ref* ref); using ResourceTableVisitor::visit_global_strings; bool visit_global_strings(android::ResStringPool_header* pool); using ResourceTableVisitor::visit_entry; bool visit_entry(android::ResTable_package* package, android::ResTable_typeSpec* type_spec, android::ResTable_type* type, android::ResTable_entry* entry, android::Res_value* value); using ResourceTableVisitor::visit_map_entry; bool visit_map_entry(android::ResTable_package* package, android::ResTable_typeSpec* type_spec, android::ResTable_type* type, android::ResTable_map_entry* entry); using ResourceTableVisitor::visit_map_value; bool visit_map_value(android::ResTable_package* package, android::ResTable_typeSpec* type_spec, android::ResTable_type* type, android::ResTable_map_entry* entry, android::ResTable_map* value); virtual ~StringPoolRefVisitor() {} }; } // namespace arsc #endif