1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef CHUNK_H_ 18 #define CHUNK_H_ 19 20 #include "android-base/logging.h" 21 #include "android-base/macros.h" 22 #include "utils/ByteOrder.h" 23 24 #ifdef _WIN32 25 #ifdef ERROR 26 #undef ERROR 27 #endif 28 #endif 29 30 #include "androidfw/ResourceTypes.h" 31 32 namespace android { 33 34 // Helpful wrapper around a ResChunk_header that provides getter methods 35 // that handle endianness conversions and provide access to the data portion 36 // of the chunk. 37 class Chunk { 38 public: Chunk(const ResChunk_header * chunk)39 explicit Chunk(const ResChunk_header* chunk) : device_chunk_(chunk) {} 40 41 // Returns the type of the chunk. Caller need not worry about endianness. type()42 inline int type() const { return dtohs(device_chunk_->type); } 43 44 // Returns the size of the entire chunk. This can be useful for skipping 45 // over the entire chunk. Caller need not worry about endianness. size()46 inline size_t size() const { return dtohl(device_chunk_->size); } 47 48 // Returns the size of the header. Caller need not worry about endianness. header_size()49 inline size_t header_size() const { return dtohs(device_chunk_->headerSize); } 50 51 template <typename T, size_t MinSize = sizeof(T)> header()52 inline const T* header() const { 53 if (header_size() >= MinSize) { 54 return reinterpret_cast<const T*>(device_chunk_); 55 } 56 return nullptr; 57 } 58 data_ptr()59 inline const void* data_ptr() const { 60 return reinterpret_cast<const uint8_t*>(device_chunk_) + header_size(); 61 } 62 data_size()63 inline size_t data_size() const { return size() - header_size(); } 64 65 private: 66 const ResChunk_header* device_chunk_; 67 }; 68 69 // Provides a Java style iterator over an array of ResChunk_header's. 70 // Validation is performed while iterating. 71 // The caller should check if there was an error during chunk validation 72 // by calling HadError() and GetLastError() to get the reason for failure. 73 // Example: 74 // 75 // ChunkIterator iter(data_ptr, data_len); 76 // while (iter.HasNext()) { 77 // const Chunk chunk = iter.Next(); 78 // ... 79 // } 80 // 81 // if (iter.HadError()) { 82 // LOG(ERROR) << iter.GetLastError(); 83 // } 84 // 85 class ChunkIterator { 86 public: ChunkIterator(const void * data,size_t len)87 ChunkIterator(const void* data, size_t len) 88 : next_chunk_(reinterpret_cast<const ResChunk_header*>(data)), 89 len_(len), 90 last_error_(nullptr) { 91 CHECK(next_chunk_ != nullptr) << "data can't be nullptr"; 92 if (len_ != 0) { 93 VerifyNextChunk(); 94 } 95 } 96 97 Chunk Next(); HasNext()98 inline bool HasNext() const { return !HadError() && len_ != 0; }; 99 // Returns whether there was an error and processing should stop HadError()100 inline bool HadError() const { return last_error_ != nullptr; } GetLastError()101 inline std::string GetLastError() const { return last_error_; } 102 // Returns whether there was an error and processing should stop. For legacy purposes, 103 // some errors are considered "non fatal". Fatal errors stop processing new chunks and 104 // throw away any chunks already processed. Non fatal errors also stop processing new 105 // chunks, but, will retain and use any valid chunks already processed. HadFatalError()106 inline bool HadFatalError() const { return HadError() && last_error_was_fatal_; } 107 108 private: 109 DISALLOW_COPY_AND_ASSIGN(ChunkIterator); 110 111 // Returns false if there was an error. 112 bool VerifyNextChunk(); 113 // Returns false if there was an error. For legacy purposes. 114 bool VerifyNextChunkNonFatal(); 115 116 const ResChunk_header* next_chunk_; 117 size_t len_; 118 const char* last_error_; 119 bool last_error_was_fatal_ = true; 120 }; 121 122 } // namespace android 123 124 #endif /* CHUNK_H_ */ 125