blob: 5ff13598a31d88d0f78d09752a5770eff1306a89 [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
2 * Copyright (C) 2015 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
Adam Lesinski46708052017-09-29 14:49:15 -070017#ifndef AAPT_FORMAT_BINARY_RESCHUNKPULLPARSER_H
18#define AAPT_FORMAT_BINARY_RESCHUNKPULLPARSER_H
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080019
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080020#include <string>
21
Adam Lesinskice5e56e2016-10-21 17:56:45 -070022#include "android-base/macros.h"
23#include "androidfw/ResourceTypes.h"
24
25#include "util/Util.h"
26
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080027namespace aapt {
28
Adam Lesinski46708052017-09-29 14:49:15 -070029// A pull parser, modeled after XmlPullParser, that reads android::ResChunk_header structs from a
30// block of data.
31// An android::ResChunk_header specifies a type, headerSize, and size. The pull parser will verify
32// that the chunk's size doesn't extend beyond the available data, and will iterate over each chunk
33// in the given block of data.
34// Processing nested chunks is done by creating a new ResChunkPullParser pointing to the data
35// portion of a chunk.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080036class ResChunkPullParser {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070037 public:
38 enum class Event {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070039 kStartDocument,
40 kEndDocument,
41 kBadDocument,
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080042
Adam Lesinskice5e56e2016-10-21 17:56:45 -070043 kChunk,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070044 };
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080045
Adam Lesinski46708052017-09-29 14:49:15 -070046 // Returns false if the event is EndDocument or BadDocument.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070047 static bool IsGoodEvent(Event event);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080048
Adam Lesinski46708052017-09-29 14:49:15 -070049 // Create a ResChunkPullParser to read android::ResChunk_headers from the memory pointed to by
50 // data, of len bytes.
Adam Lesinskicacb28f2016-10-19 12:18:14 -070051 ResChunkPullParser(const void* data, size_t len);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080052
Adam Lesinskice5e56e2016-10-21 17:56:45 -070053 Event event() const;
54 const std::string& error() const;
55 const android::ResChunk_header* chunk() const;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080056
Adam Lesinski46708052017-09-29 14:49:15 -070057 // Move to the next android::ResChunk_header.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070058 Event Next();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080059
Adam Lesinskicacb28f2016-10-19 12:18:14 -070060 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -070061 DISALLOW_COPY_AND_ASSIGN(ResChunkPullParser);
62
63 Event event_;
64 const android::ResChunk_header* data_;
65 size_t len_;
66 const android::ResChunk_header* current_chunk_;
67 std::string error_;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080068};
69
Adam Lesinski136fd072017-03-03 13:50:21 -080070template <typename T, size_t MinSize = sizeof(T)>
Adam Lesinskice5e56e2016-10-21 17:56:45 -070071inline static const T* ConvertTo(const android::ResChunk_header* chunk) {
Adam Lesinski136fd072017-03-03 13:50:21 -080072 if (util::DeviceToHost16(chunk->headerSize) < MinSize) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073 return nullptr;
74 }
75 return reinterpret_cast<const T*>(chunk);
Adam Lesinski769de982015-04-10 19:43:55 -070076}
77
Adam Lesinski46708052017-09-29 14:49:15 -070078inline static const uint8_t* GetChunkData(const android::ResChunk_header* chunk) {
79 return reinterpret_cast<const uint8_t*>(chunk) + util::DeviceToHost16(chunk->headerSize);
Adam Lesinski769de982015-04-10 19:43:55 -070080}
81
Adam Lesinskice5e56e2016-10-21 17:56:45 -070082inline static uint32_t GetChunkDataLen(const android::ResChunk_header* chunk) {
Adam Lesinski46708052017-09-29 14:49:15 -070083 return util::DeviceToHost32(chunk->size) - util::DeviceToHost16(chunk->headerSize);
Adam Lesinski769de982015-04-10 19:43:55 -070084}
85
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080086//
87// Implementation
88//
89
Adam Lesinskice5e56e2016-10-21 17:56:45 -070090inline bool ResChunkPullParser::IsGoodEvent(ResChunkPullParser::Event event) {
91 return event != Event::kEndDocument && event != Event::kBadDocument;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080092}
93
Adam Lesinskicacb28f2016-10-19 12:18:14 -070094inline ResChunkPullParser::ResChunkPullParser(const void* data, size_t len)
Adam Lesinskice5e56e2016-10-21 17:56:45 -070095 : event_(Event::kStartDocument),
96 data_(reinterpret_cast<const android::ResChunk_header*>(data)),
97 len_(len),
Adam Lesinski46708052017-09-29 14:49:15 -070098 current_chunk_(nullptr) {
99}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800100
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700101inline ResChunkPullParser::Event ResChunkPullParser::event() const {
102 return event_;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800103}
104
Adam Lesinski46708052017-09-29 14:49:15 -0700105inline const std::string& ResChunkPullParser::error() const {
106 return error_;
107}
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800108
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700109inline const android::ResChunk_header* ResChunkPullParser::chunk() const {
110 return current_chunk_;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800111}
112
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700113} // namespace aapt
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800114
Adam Lesinski46708052017-09-29 14:49:15 -0700115#endif // AAPT_FORMAT_BINARY_RESCHUNKPULLPARSER_H