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