blob: a59f5d31cab8d577780c3366e07d5a2a8f61ca30 [file] [log] [blame]
Colin Cross13221c92014-02-11 18:04:44 -08001#include "idmap.h"
2
3#include <androidfw/AssetManager.h>
4#include <androidfw/ResourceTypes.h>
5#include <utils/String8.h>
6
7#include <fcntl.h>
8#include <sys/mman.h>
9#include <sys/stat.h>
10
11using namespace android;
12
13#define NEXT(b, i, o) do { if (buf.next(&i, &o) < 0) { return -1; } } while (0)
14
15namespace {
16 static const uint32_t IDMAP_MAGIC = 0x706d6469;
17 static const size_t PATH_LENGTH = 256;
18 static const uint32_t IDMAP_HEADER_SIZE = (3 + 2 * (PATH_LENGTH / sizeof(uint32_t)));
19
20 void printe(const char *fmt, ...);
21
22 class IdmapBuffer {
23 private:
24 char *buf_;
25 size_t len_;
26 mutable size_t pos_;
27 public:
28 IdmapBuffer() : buf_((char *)MAP_FAILED), len_(0), pos_(0) {}
29
30 ~IdmapBuffer() {
31 if (buf_ != MAP_FAILED) {
32 munmap(buf_, len_);
33 }
34 }
35
36 int init(const char *idmap_path)
37 {
38 struct stat st;
39 int fd;
40
41 if (stat(idmap_path, &st) < 0) {
42 printe("failed to stat idmap '%s': %s\n", idmap_path, strerror(errno));
43 return -1;
44 }
45 len_ = st.st_size;
46 if ((fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY))) < 0) {
47 printe("failed to open idmap '%s': %s\n", idmap_path, strerror(errno));
48 return -1;
49 }
50 if ((buf_ = (char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
51 close(fd);
52 printe("failed to mmap idmap: %s\n", strerror(errno));
53 return -1;
54 }
55 close(fd);
56 return 0;
57 }
58
59 int next(uint32_t *i, uint32_t *offset) const
60 {
61 if (!buf_) {
62 printe("failed to read next uint32_t: buffer not initialized\n");
63 return -1;
64 }
65 if (pos_ + 4 > len_) {
66 printe("failed to read next uint32_t: end of buffer reached at pos=0x%08x\n",
67 pos_);
68 return -1;
69 }
70 *offset = pos_ / sizeof(uint32_t);
71 char a = buf_[pos_++];
72 char b = buf_[pos_++];
73 char c = buf_[pos_++];
74 char d = buf_[pos_++];
75 *i = (d << 24) | (c << 16) | (b << 8) | a;
76 return 0;
77 }
78
79 int nextPath(char *b, uint32_t *offset_start, uint32_t *offset_end) const
80 {
81 if (!buf_) {
82 printe("failed to read next path: buffer not initialized\n");
83 return -1;
84 }
85 if (pos_ + PATH_LENGTH > len_) {
86 printe("failed to read next path: end of buffer reached at pos=0x%08x\n", pos_);
87 return -1;
88 }
89 memcpy(b, buf_ + pos_, PATH_LENGTH);
90 *offset_start = pos_ / sizeof(uint32_t);
91 pos_ += PATH_LENGTH;
92 *offset_end = pos_ / sizeof(uint32_t) - 1;
93 return 0;
94 }
95 };
96
97 void printe(const char *fmt, ...)
98 {
99 va_list ap;
100
101 va_start(ap, fmt);
102 fprintf(stderr, "error: ");
103 vfprintf(stderr, fmt, ap);
104 va_end(ap);
105 }
106
107 void print_header()
108 {
109 printf("SECTION ENTRY VALUE OFFSET COMMENT\n");
110 }
111
112 void print(const char *section, const char *subsection, uint32_t value, uint32_t offset,
113 const char *fmt, ...)
114 {
115 va_list ap;
116
117 va_start(ap, fmt);
118 printf("%-12s %-12s 0x%08x 0x%-4x ", section, subsection, value, offset);
119 vprintf(fmt, ap);
120 printf("\n");
121 va_end(ap);
122 }
123
124 void print_path(const char *section, const char *subsection, uint32_t offset_start,
125 uint32_t offset_end, const char *fmt, ...)
126 {
127 va_list ap;
128
129 va_start(ap, fmt);
130 printf("%-12s %-12s .......... 0x%02x-0x%02x ", section, subsection, offset_start,
131 offset_end);
132 vprintf(fmt, ap);
133 printf("\n");
134 va_end(ap);
135 }
136
137 int resource_metadata(const AssetManager& am, uint32_t res_id,
138 String8 *package, String8 *type, String8 *name)
139 {
140 const ResTable& rt = am.getResources();
141 struct ResTable::resource_name data;
142 if (!rt.getResourceName(res_id, false, &data)) {
143 printe("failed to get resource name id=0x%08x\n", res_id);
144 return -1;
145 }
146 if (package) {
147 *package = String8(String16(data.package, data.packageLen));
148 }
149 if (type) {
150 *type = String8(String16(data.type, data.typeLen));
151 }
152 if (name) {
153 *name = String8(String16(data.name, data.nameLen));
154 }
155 return 0;
156 }
157
158 int package_id(const AssetManager& am)
159 {
160 return (am.getResources().getBasePackageId(0)) << 24;
161 }
162
163 int parse_idmap_header(const IdmapBuffer& buf, AssetManager& am)
164 {
165 uint32_t i, o, e;
166 char path[PATH_LENGTH];
167
168 NEXT(buf, i, o);
169 if (i != IDMAP_MAGIC) {
170 printe("not an idmap file: actual magic constant 0x%08x does not match expected magic "
171 "constant 0x%08x\n", i, IDMAP_MAGIC);
172 return -1;
173 }
174 print_header();
175 print("IDMAP HEADER", "magic", i, o, "");
176
177 NEXT(buf, i, o);
178 print("", "base crc", i, o, "");
179
180 NEXT(buf, i, o);
181 print("", "overlay crc", i, o, "");
182
183 if (buf.nextPath(path, &o, &e) < 0) {
184 // printe done from IdmapBuffer::nextPath
185 return -1;
186 }
187 print_path("", "base path", o, e, "%s", path);
188 if (!am.addAssetPath(String8(path), NULL)) {
189 printe("failed to add '%s' as asset path\n", path);
190 return -1;
191 }
192
193 if (buf.nextPath(path, &o, &e) < 0) {
194 // printe done from IdmapBuffer::nextPath
195 return -1;
196 }
197 print_path("", "overlay path", o, e, "%s", path);
198
199 return 0;
200 }
201
202 int parse_data_header(const IdmapBuffer& buf, const AssetManager& am, Vector<uint32_t>& types)
203 {
204 uint32_t i, o;
205 const uint32_t numeric_package = package_id(am);
206
207 NEXT(buf, i, o);
208 print("DATA HEADER", "types count", i, o, "");
209 const uint32_t N = i;
210
211 for (uint32_t j = 0; j < N; ++j) {
212 NEXT(buf, i, o);
213 if (i == 0) {
214 print("", "padding", i, o, "");
215 } else {
216 String8 type;
217 const uint32_t numeric_type = (j + 1) << 16;
218 const uint32_t res_id = numeric_package | numeric_type;
219 if (resource_metadata(am, res_id, NULL, &type, NULL) < 0) {
220 // printe done from resource_metadata
221 return -1;
222 }
223 print("", "type offset", i, o, "absolute offset 0x%02x, %s",
224 i + IDMAP_HEADER_SIZE, type.string());
225 types.add(numeric_type);
226 }
227 }
228
229 return 0;
230 }
231
232 int parse_data_block(const IdmapBuffer& buf, const AssetManager& am, size_t numeric_type)
233 {
234 uint32_t i, o, n, id_offset;
235 const uint32_t numeric_package = package_id(am);
236
237 NEXT(buf, i, o);
238 print("DATA BLOCK", "entry count", i, o, "");
239 n = i;
240
241 NEXT(buf, i, o);
242 print("", "entry offset", i, o, "");
243 id_offset = i;
244
245 for ( ; n > 0; --n) {
246 String8 type, name;
247
248 NEXT(buf, i, o);
249 if (i == 0) {
250 print("", "padding", i, o, "");
251 } else {
252 uint32_t res_id = numeric_package | numeric_type | id_offset;
253 if (resource_metadata(am, res_id, NULL, &type, &name) < 0) {
254 // printe done from resource_metadata
255 return -1;
256 }
257 print("", "entry", i, o, "%s/%s", type.string(), name.string());
258 }
259 ++id_offset;
260 }
261
262 return 0;
263 }
264}
265
266int idmap_inspect(const char *idmap_path)
267{
268 IdmapBuffer buf;
269 if (buf.init(idmap_path) < 0) {
270 // printe done from IdmapBuffer::init
271 return EXIT_FAILURE;
272 }
273 AssetManager am;
274 if (parse_idmap_header(buf, am) < 0) {
275 // printe done from parse_idmap_header
276 return EXIT_FAILURE;
277 }
278 Vector<uint32_t> types;
279 if (parse_data_header(buf, am, types) < 0) {
280 // printe done from parse_data_header
281 return EXIT_FAILURE;
282 }
283 const size_t N = types.size();
284 for (size_t i = 0; i < N; ++i) {
285 if (parse_data_block(buf, am, types.itemAt(i)) < 0) {
286 // printe done from parse_data_block
287 return EXIT_FAILURE;
288 }
289 }
290 return EXIT_SUCCESS;
291}