Chunk.h revision 136fd0764faf7a588b4a1b479d7a8cc6fe18fcc6
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
32namespace 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.
37class Chunk {
38 public:
39  explicit Chunk(const ResChunk_header* chunk) : device_chunk_(chunk) {}
40
41  // Returns the type of the chunk. Caller need not worry about endianness.
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.
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.
49  inline size_t header_size() const { return dtohs(device_chunk_->headerSize); }
50
51  template <typename T, size_t MinSize = sizeof(T)>
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
59  inline const void* data_ptr() const {
60    return reinterpret_cast<const uint8_t*>(device_chunk_) + header_size();
61  }
62
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//
85class ChunkIterator {
86 public:
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    VerifyNextChunk();
93  }
94
95  Chunk Next();
96  inline bool HasNext() const { return !HadError() && len_ != 0; };
97  inline bool HadError() const { return last_error_ != nullptr; }
98  inline std::string GetLastError() const { return last_error_; }
99
100 private:
101  DISALLOW_COPY_AND_ASSIGN(ChunkIterator);
102
103  // Returns false if there was an error.
104  bool VerifyNextChunk();
105
106  const ResChunk_header* next_chunk_;
107  size_t len_;
108  const char* last_error_;
109};
110
111}  // namespace android
112
113#endif /* CHUNK_H_ */
114