| /* |
| * Copyright (C) 2016 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 CHUNK_H_ |
| #define CHUNK_H_ |
| |
| #include "android-base/logging.h" |
| #include "android-base/macros.h" |
| #include "utils/ByteOrder.h" |
| |
| #ifdef _WIN32 |
| #ifdef ERROR |
| #undef ERROR |
| #endif |
| #endif |
| |
| #include "androidfw/ResourceTypes.h" |
| |
| namespace android { |
| |
| // Helpful wrapper around a ResChunk_header that provides getter methods |
| // that handle endianness conversions and provide access to the data portion |
| // of the chunk. |
| class Chunk { |
| public: |
| explicit Chunk(const ResChunk_header* chunk) : device_chunk_(chunk) {} |
| |
| // Returns the type of the chunk. Caller need not worry about endianness. |
| inline int type() const { return dtohs(device_chunk_->type); } |
| |
| // Returns the size of the entire chunk. This can be useful for skipping |
| // over the entire chunk. Caller need not worry about endianness. |
| inline size_t size() const { return dtohl(device_chunk_->size); } |
| |
| // Returns the size of the header. Caller need not worry about endianness. |
| inline size_t header_size() const { return dtohs(device_chunk_->headerSize); } |
| |
| template <typename T> |
| inline const T* header() const { |
| if (header_size() >= sizeof(T)) { |
| return reinterpret_cast<const T*>(device_chunk_); |
| } |
| return nullptr; |
| } |
| |
| inline const void* data_ptr() const { |
| return reinterpret_cast<const uint8_t*>(device_chunk_) + header_size(); |
| } |
| |
| inline size_t data_size() const { return size() - header_size(); } |
| |
| private: |
| const ResChunk_header* device_chunk_; |
| }; |
| |
| // Provides a Java style iterator over an array of ResChunk_header's. |
| // Validation is performed while iterating. |
| // The caller should check if there was an error during chunk validation |
| // by calling HadError() and GetLastError() to get the reason for failure. |
| // Example: |
| // |
| // ChunkIterator iter(data_ptr, data_len); |
| // while (iter.HasNext()) { |
| // const Chunk chunk = iter.Next(); |
| // ... |
| // } |
| // |
| // if (iter.HadError()) { |
| // LOG(ERROR) << iter.GetLastError(); |
| // } |
| // |
| class ChunkIterator { |
| public: |
| ChunkIterator(const void* data, size_t len) |
| : next_chunk_(reinterpret_cast<const ResChunk_header*>(data)), |
| len_(len), |
| last_error_(nullptr) { |
| CHECK(next_chunk_ != nullptr) << "data can't be nullptr"; |
| VerifyNextChunk(); |
| } |
| |
| Chunk Next(); |
| inline bool HasNext() const { return !HadError() && len_ != 0; }; |
| inline bool HadError() const { return last_error_ != nullptr; } |
| inline std::string GetLastError() const { return last_error_; } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ChunkIterator); |
| |
| // Returns false if there was an error. |
| bool VerifyNextChunk(); |
| |
| const ResChunk_header* next_chunk_; |
| size_t len_; |
| const char* last_error_; |
| }; |
| |
| } // namespace android |
| |
| #endif /* CHUNK_H_ */ |