blob: 135aa489c0ffeac1448b8e22d178e19afb2de08e [file] [log] [blame]
Adam Lesinski8cdca1b2017-09-28 15:50:03 -07001/*
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
Adam Lesinski46708052017-09-29 14:49:15 -070017#include "format/proto/ProtoDeserialize.h"
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070018
19#include "android-base/logging.h"
20#include "android-base/macros.h"
21#include "androidfw/ResourceTypes.h"
22
23#include "Locale.h"
24#include "ResourceTable.h"
25#include "ResourceUtils.h"
Michael Wachenschwanzd06f1f32018-01-11 18:36:22 -080026#include "ResourceValues.h"
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070027#include "ValueVisitor.h"
28
29using ::android::ResStringPool;
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070030
31namespace aapt {
32
33namespace {
34
35class ReferenceIdToNameVisitor : public DescendingValueVisitor {
36 public:
37 using DescendingValueVisitor::Visit;
38
39 explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping)
40 : mapping_(mapping) {
41 CHECK(mapping_ != nullptr);
42 }
43
44 void Visit(Reference* reference) override {
45 if (!reference->id || !reference->id.value().is_valid()) {
46 return;
47 }
48
49 ResourceId id = reference->id.value();
50 auto cache_iter = mapping_->find(id);
51 if (cache_iter != mapping_->end()) {
52 reference->name = cache_iter->second.ToResourceName();
53 }
54 }
55
56 private:
57 DISALLOW_COPY_AND_ASSIGN(ReferenceIdToNameVisitor);
58
59 const std::map<ResourceId, ResourceNameRef>* mapping_;
60};
61
62} // namespace
63
64bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config,
65 std::string* out_error) {
66 out_config->mcc = static_cast<uint16_t>(pb_config.mcc());
67 out_config->mnc = static_cast<uint16_t>(pb_config.mnc());
68
69 if (!pb_config.locale().empty()) {
70 LocaleValue lv;
71 if (!lv.InitFromBcp47Tag(pb_config.locale())) {
72 std::ostringstream error;
73 error << "configuration has invalid locale '" << pb_config.locale() << "'";
74 *out_error = error.str();
75 return false;
76 }
77 lv.WriteTo(out_config);
78 }
79
80 switch (pb_config.layout_direction()) {
81 case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR:
82 out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) |
83 ConfigDescription::LAYOUTDIR_LTR;
84 break;
85
86 case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL:
87 out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) |
88 ConfigDescription::LAYOUTDIR_RTL;
89 break;
90
91 default:
92 break;
93 }
94
95 out_config->smallestScreenWidthDp = static_cast<uint16_t>(pb_config.smallest_screen_width_dp());
96 out_config->screenWidthDp = static_cast<uint16_t>(pb_config.screen_width_dp());
97 out_config->screenHeightDp = static_cast<uint16_t>(pb_config.screen_height_dp());
98
99 switch (pb_config.screen_layout_size()) {
100 case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL:
101 out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
102 ConfigDescription::SCREENSIZE_SMALL;
103 break;
104
105 case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL:
106 out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
107 ConfigDescription::SCREENSIZE_NORMAL;
108 break;
109
110 case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE:
111 out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
112 ConfigDescription::SCREENSIZE_LARGE;
113 break;
114
115 case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE:
116 out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) |
117 ConfigDescription::SCREENSIZE_XLARGE;
118 break;
119
120 default:
121 break;
122 }
123
124 switch (pb_config.screen_layout_long()) {
125 case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG:
126 out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) |
127 ConfigDescription::SCREENLONG_YES;
128 break;
129
130 case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG:
131 out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) |
132 ConfigDescription::SCREENLONG_NO;
133 break;
134
135 default:
136 break;
137 }
138
139 switch (pb_config.screen_round()) {
140 case pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND:
141 out_config->screenLayout2 =
142 (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) |
143 ConfigDescription::SCREENROUND_YES;
144 break;
145
146 case pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND:
147 out_config->screenLayout2 =
148 (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) |
149 ConfigDescription::SCREENROUND_NO;
150 break;
151
152 default:
153 break;
154 }
155
156 switch (pb_config.wide_color_gamut()) {
157 case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG:
158 out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) |
159 ConfigDescription::WIDE_COLOR_GAMUT_YES;
160 break;
161
162 case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG:
163 out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) |
164 ConfigDescription::WIDE_COLOR_GAMUT_NO;
165 break;
166
167 default:
168 break;
169 }
170
171 switch (pb_config.hdr()) {
172 case pb::Configuration_Hdr_HDR_HIGHDR:
173 out_config->colorMode =
174 (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_YES;
175 break;
176
177 case pb::Configuration_Hdr_HDR_LOWDR:
178 out_config->colorMode =
179 (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_NO;
180 break;
181
182 default:
183 break;
184 }
185
186 switch (pb_config.orientation()) {
187 case pb::Configuration_Orientation_ORIENTATION_PORT:
188 out_config->orientation = ConfigDescription::ORIENTATION_PORT;
189 break;
190
191 case pb::Configuration_Orientation_ORIENTATION_LAND:
192 out_config->orientation = ConfigDescription::ORIENTATION_LAND;
193 break;
194
195 case pb::Configuration_Orientation_ORIENTATION_SQUARE:
196 out_config->orientation = ConfigDescription::ORIENTATION_SQUARE;
197 break;
198
199 default:
200 break;
201 }
202
203 switch (pb_config.ui_mode_type()) {
204 case pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL:
205 out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
206 ConfigDescription::UI_MODE_TYPE_NORMAL;
207 break;
208
209 case pb::Configuration_UiModeType_UI_MODE_TYPE_DESK:
210 out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
211 ConfigDescription::UI_MODE_TYPE_DESK;
212 break;
213
214 case pb::Configuration_UiModeType_UI_MODE_TYPE_CAR:
215 out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
216 ConfigDescription::UI_MODE_TYPE_CAR;
217 break;
218
219 case pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION:
220 out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
221 ConfigDescription::UI_MODE_TYPE_TELEVISION;
222 break;
223
224 case pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE:
225 out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
226 ConfigDescription::UI_MODE_TYPE_APPLIANCE;
227 break;
228
229 case pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH:
230 out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
231 ConfigDescription::UI_MODE_TYPE_WATCH;
232 break;
233
234 case pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET:
235 out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) |
236 ConfigDescription::UI_MODE_TYPE_VR_HEADSET;
237 break;
238
239 default:
240 break;
241 }
242
243 switch (pb_config.ui_mode_night()) {
244 case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT:
245 out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) |
246 ConfigDescription::UI_MODE_NIGHT_YES;
247 break;
248
249 case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT:
250 out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) |
251 ConfigDescription::UI_MODE_NIGHT_NO;
252 break;
253
254 default:
255 break;
256 }
257
258 out_config->density = static_cast<uint16_t>(pb_config.density());
259
260 switch (pb_config.touchscreen()) {
261 case pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH:
262 out_config->touchscreen = ConfigDescription::TOUCHSCREEN_NOTOUCH;
263 break;
264
265 case pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS:
266 out_config->touchscreen = ConfigDescription::TOUCHSCREEN_STYLUS;
267 break;
268
269 case pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER:
270 out_config->touchscreen = ConfigDescription::TOUCHSCREEN_FINGER;
271 break;
272
273 default:
274 break;
275 }
276
277 switch (pb_config.keys_hidden()) {
278 case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED:
279 out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
280 ConfigDescription::KEYSHIDDEN_NO;
281 break;
282
283 case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN:
284 out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
285 ConfigDescription::KEYSHIDDEN_YES;
286 break;
287
288 case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT:
289 out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) |
290 ConfigDescription::KEYSHIDDEN_SOFT;
291 break;
292
293 default:
294 break;
295 }
296
297 switch (pb_config.keyboard()) {
298 case pb::Configuration_Keyboard_KEYBOARD_NOKEYS:
299 out_config->keyboard = ConfigDescription::KEYBOARD_NOKEYS;
300 break;
301
302 case pb::Configuration_Keyboard_KEYBOARD_QWERTY:
303 out_config->keyboard = ConfigDescription::KEYBOARD_QWERTY;
304 break;
305
306 case pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY:
307 out_config->keyboard = ConfigDescription::KEYBOARD_12KEY;
308 break;
309
310 default:
311 break;
312 }
313
314 switch (pb_config.nav_hidden()) {
315 case pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED:
316 out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) |
317 ConfigDescription::NAVHIDDEN_NO;
318 break;
319
320 case pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN:
321 out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) |
322 ConfigDescription::NAVHIDDEN_YES;
323 break;
324
325 default:
326 break;
327 }
328
329 switch (pb_config.navigation()) {
330 case pb::Configuration_Navigation_NAVIGATION_NONAV:
331 out_config->navigation = ConfigDescription::NAVIGATION_NONAV;
332 break;
333
334 case pb::Configuration_Navigation_NAVIGATION_DPAD:
335 out_config->navigation = ConfigDescription::NAVIGATION_DPAD;
336 break;
337
338 case pb::Configuration_Navigation_NAVIGATION_TRACKBALL:
339 out_config->navigation = ConfigDescription::NAVIGATION_TRACKBALL;
340 break;
341
342 case pb::Configuration_Navigation_NAVIGATION_WHEEL:
343 out_config->navigation = ConfigDescription::NAVIGATION_WHEEL;
344 break;
345
346 default:
347 break;
348 }
349
350 out_config->screenWidth = static_cast<uint16_t>(pb_config.screen_width());
351 out_config->screenHeight = static_cast<uint16_t>(pb_config.screen_height());
352 out_config->sdkVersion = static_cast<uint16_t>(pb_config.sdk_version());
353 return true;
354}
355
356static void DeserializeSourceFromPb(const pb::Source& pb_source, const ResStringPool& src_pool,
357 Source* out_source) {
358 out_source->path = util::GetString(src_pool, pb_source.path_idx());
359 out_source->line = static_cast<size_t>(pb_source.position().line_number());
360}
361
362static SymbolState DeserializeVisibilityFromPb(const pb::SymbolStatus_Visibility& pb_visibility) {
363 switch (pb_visibility) {
364 case pb::SymbolStatus_Visibility_PRIVATE:
365 return SymbolState::kPrivate;
366 case pb::SymbolStatus_Visibility_PUBLIC:
367 return SymbolState::kPublic;
368 default:
369 break;
370 }
371 return SymbolState::kUndefined;
372}
373
374static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStringPool& src_pool,
Adam Lesinski8780eb62017-10-31 17:44:39 -0700375 io::IFileCollection* files, ResourceTable* out_table,
376 std::string* out_error) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700377 Maybe<uint8_t> id;
378 if (pb_package.has_package_id()) {
379 id = static_cast<uint8_t>(pb_package.package_id().id());
380 }
381
382 std::map<ResourceId, ResourceNameRef> id_index;
383
384 ResourceTablePackage* pkg = out_table->CreatePackage(pb_package.package_name(), id);
385 for (const pb::Type& pb_type : pb_package.type()) {
386 const ResourceType* res_type = ParseResourceType(pb_type.name());
387 if (res_type == nullptr) {
388 std::ostringstream error;
389 error << "unknown type '" << pb_type.name() << "'";
390 *out_error = error.str();
391 return false;
392 }
393
394 ResourceTableType* type = pkg->FindOrCreateType(*res_type);
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700395 if (pb_type.has_type_id()) {
396 type->id = static_cast<uint8_t>(pb_type.type_id().id());
397 }
398
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700399 for (const pb::Entry& pb_entry : pb_type.entry()) {
400 ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name());
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700401 if (pb_entry.has_entry_id()) {
402 entry->id = static_cast<uint16_t>(pb_entry.entry_id().id());
403 }
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700404
405 // Deserialize the symbol status (public/private with source and comments).
406 if (pb_entry.has_symbol_status()) {
407 const pb::SymbolStatus& pb_status = pb_entry.symbol_status();
408 if (pb_status.has_source()) {
409 DeserializeSourceFromPb(pb_status.source(), src_pool, &entry->symbol_status.source);
410 }
411
412 entry->symbol_status.comment = pb_status.comment();
413 entry->symbol_status.allow_new = pb_status.allow_new();
414
415 const SymbolState visibility = DeserializeVisibilityFromPb(pb_status.visibility());
416 entry->symbol_status.state = visibility;
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700417 if (visibility == SymbolState::kPublic) {
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700418 // Propagate the public visibility up to the Type.
419 type->symbol_status.state = SymbolState::kPublic;
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700420 } else if (visibility == SymbolState::kPrivate) {
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700421 // Only propagate if no previous state was assigned.
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700422 if (type->symbol_status.state == SymbolState::kUndefined) {
423 type->symbol_status.state = SymbolState::kPrivate;
424 }
425 }
426 }
427
428 ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
429 pb_entry.entry_id().id());
430 if (resid.is_valid()) {
431 id_index[resid] = ResourceNameRef(pkg->name, type->type, entry->name);
432 }
433
434 for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) {
435 const pb::Configuration& pb_config = pb_config_value.config();
436
437 ConfigDescription config;
438 if (!DeserializeConfigFromPb(pb_config, &config, out_error)) {
439 return false;
440 }
441
442 ResourceConfigValue* config_value = entry->FindOrCreateValue(config, pb_config.product());
443 if (config_value->value != nullptr) {
444 *out_error = "duplicate configuration in resource table";
445 return false;
446 }
447
448 config_value->value = DeserializeValueFromPb(pb_config_value.value(), src_pool, config,
Adam Lesinski8780eb62017-10-31 17:44:39 -0700449 &out_table->string_pool, files, out_error);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700450 if (config_value->value == nullptr) {
451 return false;
452 }
453 }
454 }
455 }
456
457 ReferenceIdToNameVisitor visitor(&id_index);
458 VisitAllValuesInPackage(pkg, &visitor);
459 return true;
460}
461
Adam Lesinski8780eb62017-10-31 17:44:39 -0700462bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, io::IFileCollection* files,
463 ResourceTable* out_table, std::string* out_error) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700464 // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
465 // causes errors when qualifying it with android::
466 using namespace android;
467
468 ResStringPool source_pool;
469 if (pb_table.has_source_pool()) {
470 status_t result = source_pool.setTo(pb_table.source_pool().data().data(),
471 pb_table.source_pool().data().size());
472 if (result != NO_ERROR) {
473 *out_error = "invalid source pool";
474 return false;
475 }
476 }
477
478 for (const pb::Package& pb_package : pb_table.package()) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700479 if (!DeserializePackageFromPb(pb_package, source_pool, files, out_table, out_error)) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700480 return false;
481 }
482 }
483 return true;
484}
485
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700486static ResourceFile::Type DeserializeFileReferenceTypeFromPb(const pb::FileReference::Type& type) {
487 switch (type) {
488 case pb::FileReference::BINARY_XML:
Adam Lesinski00451162017-10-03 07:44:08 -0700489 return ResourceFile::Type::kBinaryXml;
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700490 case pb::FileReference::PROTO_XML:
Adam Lesinski00451162017-10-03 07:44:08 -0700491 return ResourceFile::Type::kProtoXml;
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700492 case pb::FileReference::PNG:
493 return ResourceFile::Type::kPng;
Adam Lesinski00451162017-10-03 07:44:08 -0700494 default:
495 return ResourceFile::Type::kUnknown;
496 }
497}
498
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700499bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file,
500 ResourceFile* out_file, std::string* out_error) {
501 ResourceNameRef name_ref;
502 if (!ResourceUtils::ParseResourceName(pb_file.resource_name(), &name_ref)) {
503 std::ostringstream error;
504 error << "invalid resource name in compiled file header: " << pb_file.resource_name();
505 *out_error = error.str();
506 return false;
507 }
508
509 out_file->name = name_ref.ToResourceName();
510 out_file->source.path = pb_file.source_path();
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700511 out_file->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700512
513 std::string config_error;
514 if (!DeserializeConfigFromPb(pb_file.config(), &out_file->config, &config_error)) {
515 std::ostringstream error;
516 error << "invalid resource configuration in compiled file header: " << config_error;
517 *out_error = error.str();
518 return false;
519 }
520
521 for (const pb::internal::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbol()) {
522 if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), &name_ref)) {
523 std::ostringstream error;
524 error << "invalid resource name for exported symbol in compiled file header: "
525 << pb_file.resource_name();
526 *out_error = error.str();
527 return false;
528 }
529
530 size_t line = 0u;
531 if (pb_symbol.has_source()) {
532 line = pb_symbol.source().line_number();
533 }
534 out_file->exported_symbols.push_back(SourcedResourceName{name_ref.ToResourceName(), line});
535 }
536 return true;
537}
538
539static Reference::Type DeserializeReferenceTypeFromPb(const pb::Reference_Type& pb_type) {
540 switch (pb_type) {
541 case pb::Reference_Type_REFERENCE:
542 return Reference::Type::kResource;
543 case pb::Reference_Type_ATTRIBUTE:
544 return Reference::Type::kAttribute;
545 default:
546 break;
547 }
548 return Reference::Type::kResource;
549}
550
551static bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref,
552 std::string* out_error) {
553 out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type());
554 out_ref->private_reference = pb_ref.private_();
555
556 if (pb_ref.id() != 0) {
557 out_ref->id = ResourceId(pb_ref.id());
558 }
559
560 if (!pb_ref.name().empty()) {
561 ResourceNameRef name_ref;
562 if (!ResourceUtils::ParseResourceName(pb_ref.name(), &name_ref, nullptr)) {
563 std::ostringstream error;
564 error << "reference has invalid resource name '" << pb_ref.name() << "'";
565 *out_error = error.str();
566 return false;
567 }
568 out_ref->name = name_ref.ToResourceName();
569 }
570 return true;
571}
572
573template <typename T>
574static void DeserializeItemMetaDataFromPb(const T& pb_item, const android::ResStringPool& src_pool,
575 Value* out_value) {
576 if (pb_item.has_source()) {
577 Source source;
578 DeserializeSourceFromPb(pb_item.source(), src_pool, &source);
579 out_value->SetSource(std::move(source));
580 }
581 out_value->SetComment(pb_item.comment());
582}
583
584static size_t DeserializePluralEnumFromPb(const pb::Plural_Arity& arity) {
585 switch (arity) {
586 case pb::Plural_Arity_ZERO:
587 return Plural::Zero;
588 case pb::Plural_Arity_ONE:
589 return Plural::One;
590 case pb::Plural_Arity_TWO:
591 return Plural::Two;
592 case pb::Plural_Arity_FEW:
593 return Plural::Few;
594 case pb::Plural_Arity_MANY:
595 return Plural::Many;
596 default:
597 break;
598 }
599 return Plural::Other;
600}
601
602std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
603 const android::ResStringPool& src_pool,
604 const ConfigDescription& config,
Adam Lesinski8780eb62017-10-31 17:44:39 -0700605 StringPool* value_pool, io::IFileCollection* files,
606 std::string* out_error) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700607 std::unique_ptr<Value> value;
608 if (pb_value.has_item()) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700609 value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, files, out_error);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700610 if (value == nullptr) {
611 return {};
612 }
613
614 } else if (pb_value.has_compound_value()) {
615 const pb::CompoundValue& pb_compound_value = pb_value.compound_value();
616 switch (pb_compound_value.value_case()) {
617 case pb::CompoundValue::kAttr: {
618 const pb::Attribute& pb_attr = pb_compound_value.attr();
619 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>();
620 attr->type_mask = pb_attr.format_flags();
621 attr->min_int = pb_attr.min_int();
622 attr->max_int = pb_attr.max_int();
623 for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbol()) {
624 Attribute::Symbol symbol;
625 DeserializeItemMetaDataFromPb(pb_symbol, src_pool, &symbol.symbol);
626 if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol, out_error)) {
627 return {};
628 }
629 symbol.value = pb_symbol.value();
630 attr->symbols.push_back(std::move(symbol));
631 }
632 value = std::move(attr);
633 } break;
634
635 case pb::CompoundValue::kStyle: {
636 const pb::Style& pb_style = pb_compound_value.style();
637 std::unique_ptr<Style> style = util::make_unique<Style>();
638 if (pb_style.has_parent()) {
639 style->parent = Reference();
640 if (!DeserializeReferenceFromPb(pb_style.parent(), &style->parent.value(), out_error)) {
641 return {};
642 }
643
644 if (pb_style.has_parent_source()) {
645 Source parent_source;
646 DeserializeSourceFromPb(pb_style.parent_source(), src_pool, &parent_source);
647 style->parent.value().SetSource(std::move(parent_source));
648 }
649 }
650
651 for (const pb::Style_Entry& pb_entry : pb_style.entry()) {
652 Style::Entry entry;
653 if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key, out_error)) {
654 return {};
655 }
656 DeserializeItemMetaDataFromPb(pb_entry, src_pool, &entry.key);
Adam Lesinski8780eb62017-10-31 17:44:39 -0700657 entry.value = DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, files,
658 out_error);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700659 if (entry.value == nullptr) {
660 return {};
661 }
662
663 // Copy the meta-data into the value as well.
664 DeserializeItemMetaDataFromPb(pb_entry, src_pool, entry.value.get());
665 style->entries.push_back(std::move(entry));
666 }
667 value = std::move(style);
668 } break;
669
670 case pb::CompoundValue::kStyleable: {
671 const pb::Styleable& pb_styleable = pb_compound_value.styleable();
672 std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
673 for (const pb::Styleable_Entry& pb_entry : pb_styleable.entry()) {
674 Reference attr_ref;
675 DeserializeItemMetaDataFromPb(pb_entry, src_pool, &attr_ref);
676 DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref, out_error);
677 styleable->entries.push_back(std::move(attr_ref));
678 }
679 value = std::move(styleable);
680 } break;
681
682 case pb::CompoundValue::kArray: {
683 const pb::Array& pb_array = pb_compound_value.array();
684 std::unique_ptr<Array> array = util::make_unique<Array>();
685 for (const pb::Array_Element& pb_entry : pb_array.element()) {
Adam Lesinski8780eb62017-10-31 17:44:39 -0700686 std::unique_ptr<Item> item = DeserializeItemFromPb(pb_entry.item(), src_pool, config,
687 value_pool, files, out_error);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700688 if (item == nullptr) {
689 return {};
690 }
691
692 DeserializeItemMetaDataFromPb(pb_entry, src_pool, item.get());
693 array->elements.push_back(std::move(item));
694 }
695 value = std::move(array);
696 } break;
697
698 case pb::CompoundValue::kPlural: {
699 const pb::Plural& pb_plural = pb_compound_value.plural();
700 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
701 for (const pb::Plural_Entry& pb_entry : pb_plural.entry()) {
702 size_t plural_idx = DeserializePluralEnumFromPb(pb_entry.arity());
Adam Lesinski8780eb62017-10-31 17:44:39 -0700703 plural->values[plural_idx] = DeserializeItemFromPb(pb_entry.item(), src_pool, config,
704 value_pool, files, out_error);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700705 if (!plural->values[plural_idx]) {
706 return {};
707 }
708
709 DeserializeItemMetaDataFromPb(pb_entry, src_pool, plural->values[plural_idx].get());
710 }
711 value = std::move(plural);
712 } break;
713
714 default:
Adam Lesinski46708052017-09-29 14:49:15 -0700715 LOG(FATAL) << "unknown compound value: " << (int)pb_compound_value.value_case();
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700716 break;
717 }
718 } else {
Adam Lesinski46708052017-09-29 14:49:15 -0700719 LOG(FATAL) << "unknown value: " << (int)pb_value.value_case();
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700720 return {};
721 }
722
723 CHECK(value) << "forgot to set value";
724
725 value->SetWeak(pb_value.weak());
726 DeserializeItemMetaDataFromPb(pb_value, src_pool, value.get());
727 return value;
728}
729
730std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
731 const android::ResStringPool& src_pool,
732 const ConfigDescription& config, StringPool* value_pool,
Adam Lesinski8780eb62017-10-31 17:44:39 -0700733 io::IFileCollection* files, std::string* out_error) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700734 switch (pb_item.value_case()) {
735 case pb::Item::kRef: {
736 const pb::Reference& pb_ref = pb_item.ref();
737 std::unique_ptr<Reference> ref = util::make_unique<Reference>();
738 if (!DeserializeReferenceFromPb(pb_ref, ref.get(), out_error)) {
739 return {};
740 }
741 return std::move(ref);
742 } break;
743
744 case pb::Item::kPrim: {
745 const pb::Primitive& pb_prim = pb_item.prim();
Michael Wachenschwanzd06f1f32018-01-11 18:36:22 -0800746 android::Res_value val = {};
747 switch (pb_prim.oneof_value_case()) {
748 case pb::Primitive::kNullValue: {
749 val.dataType = android::Res_value::TYPE_NULL;
750 val.data = android::Res_value::DATA_NULL_UNDEFINED;
751 } break;
752 case pb::Primitive::kEmptyValue: {
753 val.dataType = android::Res_value::TYPE_NULL;
754 val.data = android::Res_value::DATA_NULL_EMPTY;
755 } break;
756 case pb::Primitive::kFloatValue: {
757 val.dataType = android::Res_value::TYPE_FLOAT;
758 float float_val = pb_prim.float_value();
759 val.data = *(uint32_t*)&float_val;
760 } break;
761 case pb::Primitive::kDimensionValue: {
762 val.dataType = android::Res_value::TYPE_DIMENSION;
763 float dimen_val = pb_prim.dimension_value();
764 val.data = *(uint32_t*)&dimen_val;
765 } break;
766 case pb::Primitive::kFractionValue: {
767 val.dataType = android::Res_value::TYPE_FRACTION;
768 float fraction_val = pb_prim.fraction_value();
769 val.data = *(uint32_t*)&fraction_val;
770 } break;
771 case pb::Primitive::kIntDecimalValue: {
772 val.dataType = android::Res_value::TYPE_INT_DEC;
773 val.data = static_cast<uint32_t>(pb_prim.int_decimal_value());
774 } break;
775 case pb::Primitive::kIntHexidecimalValue: {
776 val.dataType = android::Res_value::TYPE_INT_HEX;
777 val.data = pb_prim.int_hexidecimal_value();
778 } break;
779 case pb::Primitive::kBooleanValue: {
780 val.dataType = android::Res_value::TYPE_INT_BOOLEAN;
781 val.data = pb_prim.boolean_value() ? 0xFFFFFFFF : 0x0;
782 } break;
783 case pb::Primitive::kColorArgb8Value: {
784 val.dataType = android::Res_value::TYPE_INT_COLOR_ARGB8;
785 val.data = pb_prim.color_argb8_value();
786 } break;
787 case pb::Primitive::kColorRgb8Value: {
788 val.dataType = android::Res_value::TYPE_INT_COLOR_RGB8;
789 val.data = pb_prim.color_rgb8_value();
790 } break;
791 case pb::Primitive::kColorArgb4Value: {
792 val.dataType = android::Res_value::TYPE_INT_COLOR_ARGB4;
793 val.data = pb_prim.color_argb4_value();
794 } break;
795 case pb::Primitive::kColorRgb4Value: {
796 val.dataType = android::Res_value::TYPE_INT_COLOR_RGB4;
797 val.data = pb_prim.color_rgb4_value();
798 } break;
799 default: {
800 LOG(FATAL) << "Unexpected Primitive type: "
801 << static_cast<uint32_t>(pb_prim.oneof_value_case());
802 return {};
803 } break;
804 }
805 return util::make_unique<BinaryPrimitive>(val);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700806 } break;
807
808 case pb::Item::kId: {
809 return util::make_unique<Id>();
810 } break;
811
812 case pb::Item::kStr: {
813 return util::make_unique<String>(
814 value_pool->MakeRef(pb_item.str().value(), StringPool::Context(config)));
815 } break;
816
817 case pb::Item::kRawStr: {
818 return util::make_unique<RawString>(
819 value_pool->MakeRef(pb_item.raw_str().value(), StringPool::Context(config)));
820 } break;
821
822 case pb::Item::kStyledStr: {
823 const pb::StyledString& pb_str = pb_item.styled_str();
824 StyleString style_str{pb_str.value()};
825 for (const pb::StyledString::Span& pb_span : pb_str.span()) {
826 style_str.spans.push_back(Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()});
827 }
828 return util::make_unique<StyledString>(value_pool->MakeRef(
829 style_str, StringPool::Context(StringPool::Context::kNormalPriority, config)));
830 } break;
831
832 case pb::Item::kFile: {
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700833 const pb::FileReference& pb_file = pb_item.file();
834 std::unique_ptr<FileReference> file_ref =
835 util::make_unique<FileReference>(value_pool->MakeRef(
836 pb_file.path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
837 file_ref->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
Adam Lesinski8780eb62017-10-31 17:44:39 -0700838 if (files != nullptr) {
839 file_ref->file = files->FindFile(*file_ref->path);
840 }
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700841 return std::move(file_ref);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700842 } break;
843
844 default:
Adam Lesinski46708052017-09-29 14:49:15 -0700845 LOG(FATAL) << "unknown item: " << (int)pb_item.value_case();
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700846 break;
847 }
848 return {};
849}
850
851std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
852 std::string* out_error) {
853 if (!pb_node.has_element()) {
854 return {};
855 }
856
857 std::unique_ptr<xml::XmlResource> resource = util::make_unique<xml::XmlResource>();
858 resource->root = util::make_unique<xml::Element>();
859 if (!DeserializeXmlFromPb(pb_node, resource->root.get(), &resource->string_pool, out_error)) {
860 return {};
861 }
862 return resource;
863}
864
865bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool,
866 std::string* out_error) {
867 const pb::XmlElement& pb_el = pb_node.element();
868 out_el->name = pb_el.name();
869 out_el->namespace_uri = pb_el.namespace_uri();
870 out_el->line_number = pb_node.source().line_number();
871 out_el->column_number = pb_node.source().column_number();
872
873 for (const pb::XmlNamespace& pb_ns : pb_el.namespace_declaration()) {
874 xml::NamespaceDecl decl;
875 decl.uri = pb_ns.uri();
876 decl.prefix = pb_ns.prefix();
877 decl.line_number = pb_ns.source().line_number();
878 decl.column_number = pb_ns.source().column_number();
879 out_el->namespace_decls.push_back(std::move(decl));
880 }
881
882 for (const pb::XmlAttribute& pb_attr : pb_el.attribute()) {
883 xml::Attribute attr;
884 attr.name = pb_attr.name();
885 attr.namespace_uri = pb_attr.namespace_uri();
886 attr.value = pb_attr.value();
887 if (pb_attr.resource_id() != 0u) {
888 attr.compiled_attribute = xml::AaptAttribute{Attribute(), ResourceId(pb_attr.resource_id())};
889 }
890 if (pb_attr.has_compiled_item()) {
891 attr.compiled_value =
Adam Lesinski8780eb62017-10-31 17:44:39 -0700892 DeserializeItemFromPb(pb_attr.compiled_item(), {}, {}, value_pool, nullptr, out_error);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700893 if (attr.compiled_value == nullptr) {
894 return {};
895 }
896 attr.compiled_value->SetSource(Source().WithLine(pb_attr.source().line_number()));
897 }
898 out_el->attributes.push_back(std::move(attr));
899 }
900
901 // Deserialize the children.
902 for (const pb::XmlNode& pb_child : pb_el.child()) {
903 switch (pb_child.node_case()) {
904 case pb::XmlNode::NodeCase::kText: {
905 std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
906 text->line_number = pb_child.source().line_number();
907 text->column_number = pb_child.source().column_number();
908 text->text = pb_child.text();
909 out_el->AppendChild(std::move(text));
910 } break;
911
912 case pb::XmlNode::NodeCase::kElement: {
913 std::unique_ptr<xml::Element> child_el = util::make_unique<xml::Element>();
914 if (!DeserializeXmlFromPb(pb_child, child_el.get(), value_pool, out_error)) {
915 return false;
916 }
917 out_el->AppendChild(std::move(child_el));
918 } break;
919
920 default:
Adam Lesinski46708052017-09-29 14:49:15 -0700921 LOG(FATAL) << "unknown XmlNode " << (int)pb_child.node_case();
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700922 break;
923 }
924 }
925 return true;
926}
927
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700928} // namespace aapt