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