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(incfs::verified_map_ptr<ResChunk_header> chunk)39 explicit Chunk(incfs::verified_map_ptr<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 incfs::map_ptr<T> header() const { 53 return (header_size() >= MinSize) ? device_chunk_.convert<T>() : nullptr; 54 } 55 data_ptr()56 inline incfs::map_ptr<void> data_ptr() const { 57 return device_chunk_.offset(header_size()); 58 } 59 data_size()60 inline size_t data_size() const { return size() - header_size(); } 61 62 private: 63 const incfs::verified_map_ptr<ResChunk_header> device_chunk_; 64 }; 65 66 // Provides a Java style iterator over an array of ResChunk_header's. 67 // Validation is performed while iterating. 68 // The caller should check if there was an error during chunk validation 69 // by calling HadError() and GetLastError() to get the reason for failure. 70 // Example: 71 // 72 // ChunkIterator iter(data_ptr, data_len); 73 // while (iter.HasNext()) { 74 // const Chunk chunk = iter.Next(); 75 // ... 76 // } 77 // 78 // if (iter.HadError()) { 79 // LOG(ERROR) << iter.GetLastError(); 80 // } 81 // 82 class ChunkIterator { 83 public: ChunkIterator(incfs::map_ptr<void> data,size_t len)84 ChunkIterator(incfs::map_ptr<void> data, size_t len) 85 : next_chunk_(data.convert<ResChunk_header>()), 86 len_(len), 87 last_error_(nullptr) { 88 CHECK((bool) next_chunk_) << "data can't be null"; 89 if (len_ != 0) { 90 VerifyNextChunk(); 91 } 92 } 93 94 Chunk Next(); HasNext()95 inline bool HasNext() const { return !HadError() && len_ != 0; }; 96 // Returns whether there was an error and processing should stop HadError()97 inline bool HadError() const { return last_error_ != nullptr; } GetLastError()98 inline std::string GetLastError() const { return last_error_; } 99 // Returns whether there was an error and processing should stop. For legacy purposes, 100 // some errors are considered "non fatal". Fatal errors stop processing new chunks and 101 // throw away any chunks already processed. Non fatal errors also stop processing new 102 // chunks, but, will retain and use any valid chunks already processed. HadFatalError()103 inline bool HadFatalError() const { return HadError() && last_error_was_fatal_; } 104 105 private: 106 DISALLOW_COPY_AND_ASSIGN(ChunkIterator); 107 108 // Returns false if there was an error. 109 bool VerifyNextChunk(); 110 // Returns false if there was an error. For legacy purposes. 111 bool VerifyNextChunkNonFatal(); 112 113 incfs::map_ptr<ResChunk_header> next_chunk_; 114 size_t len_; 115 const char* last_error_; 116 bool last_error_was_fatal_ = true; 117 }; 118 119 } // namespace android 120 121 #endif /* CHUNK_H_ */ 122