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
644 out_file->flag_status = (FlagStatus)pb_file.flag_status();
645 if (!pb_file.flag_name().empty()) {
646 out_file->flag =
647 FeatureFlagAttribute{.name = pb_file.flag_name(), .negated = pb_file.flag_negated()};
648 }
649
650 std::string config_error;
651 if (!DeserializeConfigFromPb(pb_file.config(), &out_file->config, &config_error)) {
652 std::ostringstream error;
653 error << "invalid resource configuration in compiled file header: " << config_error;
654 *out_error = error.str();
655 return false;
656 }
657
658 for (const pb::internal::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbol()) {
659 if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), &name_ref)) {
660 std::ostringstream error;
661 error << "invalid resource name for exported symbol in compiled file header: "
662 << pb_file.resource_name();
663 *out_error = error.str();
664 return false;
665 }
666
667 size_t line = 0u;
668 if (pb_symbol.has_source()) {
669 line = pb_symbol.source().line_number();
670 }
671 out_file->exported_symbols.push_back(SourcedResourceName{name_ref.ToResourceName(), line});
672 }
673 return true;
674 }
675
DeserializeReferenceTypeFromPb(const pb::Reference_Type & pb_type)676 static Reference::Type DeserializeReferenceTypeFromPb(const pb::Reference_Type& pb_type) {
677 switch (pb_type) {
678 case pb::Reference_Type_REFERENCE:
679 return Reference::Type::kResource;
680 case pb::Reference_Type_ATTRIBUTE:
681 return Reference::Type::kAttribute;
682 default:
683 break;
684 }
685 return Reference::Type::kResource;
686 }
687
DeserializeReferenceFromPb(const pb::Reference & pb_ref,Reference * out_ref,std::string * out_error)688 static bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref,
689 std::string* out_error) {
690 out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type());
691 out_ref->private_reference = pb_ref.private_();
692 out_ref->is_dynamic = pb_ref.is_dynamic().value();
693
694 if (pb_ref.id() != 0) {
695 out_ref->id = ResourceId(pb_ref.id());
696 }
697
698 if (!pb_ref.name().empty()) {
699 ResourceNameRef name_ref;
700 if (!ResourceUtils::ParseResourceName(pb_ref.name(), &name_ref, nullptr)) {
701 std::ostringstream error;
702 error << "reference has invalid resource name '" << pb_ref.name() << "'";
703 *out_error = error.str();
704 return false;
705 }
706 out_ref->name = name_ref.ToResourceName();
707 }
708 if (pb_ref.type_flags() != 0) {
709 out_ref->type_flags = pb_ref.type_flags();
710 }
711 out_ref->allow_raw = pb_ref.allow_raw();
712 return true;
713 }
714
DeserializeMacroFromPb(const pb::MacroBody & pb_ref,Macro * out_ref,std::string * out_error)715 static bool DeserializeMacroFromPb(const pb::MacroBody& pb_ref, Macro* out_ref,
716 std::string* out_error) {
717 out_ref->raw_value = pb_ref.raw_string();
718
719 if (pb_ref.has_style_string()) {
720 out_ref->style_string.str = pb_ref.style_string().str();
721 for (const auto& span : pb_ref.style_string().spans()) {
722 out_ref->style_string.spans.emplace_back(android::Span{
723 .name = span.name(), .first_char = span.start_index(), .last_char = span.end_index()});
724 }
725 }
726
727 for (const auto& untranslatable_section : pb_ref.untranslatable_sections()) {
728 out_ref->untranslatable_sections.emplace_back(
729 UntranslatableSection{.start = static_cast<size_t>(untranslatable_section.start_index()),
730 .end = static_cast<size_t>(untranslatable_section.end_index())});
731 }
732
733 for (const auto& namespace_decls : pb_ref.namespace_stack()) {
734 out_ref->alias_namespaces.emplace_back(
735 Macro::Namespace{.alias = namespace_decls.prefix(),
736 .package_name = namespace_decls.package_name(),
737 .is_private = namespace_decls.is_private()});
738 }
739
740 return true;
741 }
742
743 template <typename T>
DeserializeItemMetaDataFromPb(const T & pb_item,const android::ResStringPool & src_pool,Value * out_value)744 static void DeserializeItemMetaDataFromPb(const T& pb_item, const android::ResStringPool& src_pool,
745 Value* out_value) {
746 if (pb_item.has_source()) {
747 android::Source source;
748 DeserializeSourceFromPb(pb_item.source(), src_pool, &source);
749 out_value->SetSource(std::move(source));
750 }
751 out_value->SetComment(pb_item.comment());
752 }
753
DeserializePluralEnumFromPb(const pb::Plural_Arity & arity)754 static size_t DeserializePluralEnumFromPb(const pb::Plural_Arity& arity) {
755 switch (arity) {
756 case pb::Plural_Arity_ZERO:
757 return Plural::Zero;
758 case pb::Plural_Arity_ONE:
759 return Plural::One;
760 case pb::Plural_Arity_TWO:
761 return Plural::Two;
762 case pb::Plural_Arity_FEW:
763 return Plural::Few;
764 case pb::Plural_Arity_MANY:
765 return Plural::Many;
766 default:
767 break;
768 }
769 return Plural::Other;
770 }
771
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)772 std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
773 const android::ResStringPool& src_pool,
774 const ConfigDescription& config,
775 android::StringPool* value_pool,
776 io::IFileCollection* files, std::string* out_error) {
777 std::unique_ptr<Value> value;
778 if (pb_value.has_item()) {
779 value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, files, out_error);
780 if (value == nullptr) {
781 return {};
782 }
783 } else if (pb_value.has_compound_value()) {
784 const pb::CompoundValue& pb_compound_value = pb_value.compound_value();
785 switch (pb_compound_value.value_case()) {
786 case pb::CompoundValue::kAttr: {
787 const pb::Attribute& pb_attr = pb_compound_value.attr();
788 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(pb_attr.format_flags());
789 attr->min_int = pb_attr.min_int();
790 attr->max_int = pb_attr.max_int();
791 for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbol()) {
792 Attribute::Symbol symbol;
793 DeserializeItemMetaDataFromPb(pb_symbol, src_pool, &symbol.symbol);
794 if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol, out_error)) {
795 return {};
796 }
797 symbol.value = pb_symbol.value();
798 symbol.type = pb_symbol.type() != 0U ? pb_symbol.type()
799 : android::Res_value::TYPE_INT_DEC;
800 attr->symbols.push_back(std::move(symbol));
801 }
802 value = std::move(attr);
803 } break;
804
805 case pb::CompoundValue::kStyle: {
806 const pb::Style& pb_style = pb_compound_value.style();
807 std::unique_ptr<Style> style = util::make_unique<Style>();
808 if (pb_style.has_parent()) {
809 style->parent = Reference();
810 if (!DeserializeReferenceFromPb(pb_style.parent(), &style->parent.value(), out_error)) {
811 return {};
812 }
813
814 if (pb_style.has_parent_source()) {
815 android::Source parent_source;
816 DeserializeSourceFromPb(pb_style.parent_source(), src_pool, &parent_source);
817 style->parent.value().SetSource(std::move(parent_source));
818 }
819 }
820
821 for (const pb::Style_Entry& pb_entry : pb_style.entry()) {
822 Style::Entry entry;
823 if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key, out_error)) {
824 return {};
825 }
826 DeserializeItemMetaDataFromPb(pb_entry, src_pool, &entry.key);
827 entry.value = DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, files,
828 out_error);
829 if (entry.value == nullptr) {
830 return {};
831 }
832
833 // Copy the meta-data into the value as well.
834 DeserializeItemMetaDataFromPb(pb_entry, src_pool, entry.value.get());
835 style->entries.push_back(std::move(entry));
836 }
837 value = std::move(style);
838 } break;
839
840 case pb::CompoundValue::kStyleable: {
841 const pb::Styleable& pb_styleable = pb_compound_value.styleable();
842 std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
843 for (const pb::Styleable_Entry& pb_entry : pb_styleable.entry()) {
844 Reference attr_ref;
845 DeserializeItemMetaDataFromPb(pb_entry, src_pool, &attr_ref);
846 DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref, out_error);
847 styleable->entries.push_back(std::move(attr_ref));
848 }
849 value = std::move(styleable);
850 } break;
851
852 case pb::CompoundValue::kArray: {
853 const pb::Array& pb_array = pb_compound_value.array();
854 std::unique_ptr<Array> array = util::make_unique<Array>();
855 for (const pb::Array_Element& pb_entry : pb_array.element()) {
856 std::unique_ptr<Item> item = DeserializeItemFromPb(pb_entry.item(), src_pool, config,
857 value_pool, files, out_error);
858 if (item == nullptr) {
859 return {};
860 }
861
862 DeserializeItemMetaDataFromPb(pb_entry, src_pool, item.get());
863 array->elements.push_back(std::move(item));
864 }
865 value = std::move(array);
866 } break;
867
868 case pb::CompoundValue::kPlural: {
869 const pb::Plural& pb_plural = pb_compound_value.plural();
870 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
871 for (const pb::Plural_Entry& pb_entry : pb_plural.entry()) {
872 size_t plural_idx = DeserializePluralEnumFromPb(pb_entry.arity());
873 plural->values[plural_idx] = DeserializeItemFromPb(pb_entry.item(), src_pool, config,
874 value_pool, files, out_error);
875 if (!plural->values[plural_idx]) {
876 return {};
877 }
878
879 DeserializeItemMetaDataFromPb(pb_entry, src_pool, plural->values[plural_idx].get());
880 }
881 value = std::move(plural);
882 } break;
883
884 case pb::CompoundValue::kMacro: {
885 const pb::MacroBody& pb_macro = pb_compound_value.macro();
886 auto macro = std::make_unique<Macro>();
887 if (!DeserializeMacroFromPb(pb_macro, macro.get(), out_error)) {
888 return {};
889 }
890 value = std::move(macro);
891 } break;
892
893 default:
894 LOG(FATAL) << "unknown compound value: " << (int)pb_compound_value.value_case();
895 break;
896 }
897 value->SetFlagStatus((FlagStatus)pb_compound_value.flag_status());
898 value->SetFlag(FeatureFlagAttribute{.name = pb_compound_value.flag_name(),
899 .negated = pb_compound_value.flag_negated()});
900 } else {
901 LOG(FATAL) << "unknown value: " << (int)pb_value.value_case();
902 return {};
903 }
904
905 CHECK(value) << "forgot to set value";
906
907 value->SetWeak(pb_value.weak());
908 DeserializeItemMetaDataFromPb(pb_value, src_pool, value.get());
909 return value;
910 }
911
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)912 std::unique_ptr<Item> DeserializeItemFromPbInternal(const pb::Item& pb_item,
913 const android::ResStringPool& src_pool,
914 const ConfigDescription& config,
915 android::StringPool* value_pool,
916 io::IFileCollection* files,
917 std::string* out_error) {
918 switch (pb_item.value_case()) {
919 case pb::Item::kRef: {
920 const pb::Reference& pb_ref = pb_item.ref();
921 std::unique_ptr<Reference> ref = util::make_unique<Reference>();
922 if (!DeserializeReferenceFromPb(pb_ref, ref.get(), out_error)) {
923 return {};
924 }
925 return std::move(ref);
926 } break;
927
928 case pb::Item::kPrim: {
929 const pb::Primitive& pb_prim = pb_item.prim();
930 android::Res_value val = {};
931 switch (pb_prim.oneof_value_case()) {
932 case pb::Primitive::kNullValue: {
933 val.dataType = android::Res_value::TYPE_NULL;
934 val.data = android::Res_value::DATA_NULL_UNDEFINED;
935 } break;
936 case pb::Primitive::kEmptyValue: {
937 val.dataType = android::Res_value::TYPE_NULL;
938 val.data = android::Res_value::DATA_NULL_EMPTY;
939 } break;
940 case pb::Primitive::kFloatValue: {
941 val.dataType = android::Res_value::TYPE_FLOAT;
942 float float_val = pb_prim.float_value();
943 val.data = *(uint32_t*)&float_val;
944 } break;
945 case pb::Primitive::kDimensionValue: {
946 val.dataType = android::Res_value::TYPE_DIMENSION;
947 val.data = pb_prim.dimension_value();
948 } break;
949 case pb::Primitive::kFractionValue: {
950 val.dataType = android::Res_value::TYPE_FRACTION;
951 val.data = pb_prim.fraction_value();
952 } break;
953 case pb::Primitive::kIntDecimalValue: {
954 val.dataType = android::Res_value::TYPE_INT_DEC;
955 val.data = static_cast<int32_t>(pb_prim.int_decimal_value());
956 } break;
957 case pb::Primitive::kIntHexadecimalValue: {
958 val.dataType = android::Res_value::TYPE_INT_HEX;
959 val.data = pb_prim.int_hexadecimal_value();
960 } break;
961 case pb::Primitive::kBooleanValue: {
962 val.dataType = android::Res_value::TYPE_INT_BOOLEAN;
963 val.data = pb_prim.boolean_value() ? 0xFFFFFFFF : 0x0;
964 } break;
965 case pb::Primitive::kColorArgb8Value: {
966 val.dataType = android::Res_value::TYPE_INT_COLOR_ARGB8;
967 val.data = pb_prim.color_argb8_value();
968 } break;
969 case pb::Primitive::kColorRgb8Value: {
970 val.dataType = android::Res_value::TYPE_INT_COLOR_RGB8;
971 val.data = pb_prim.color_rgb8_value();
972 } break;
973 case pb::Primitive::kColorArgb4Value: {
974 val.dataType = android::Res_value::TYPE_INT_COLOR_ARGB4;
975 val.data = pb_prim.color_argb4_value();
976 } break;
977 case pb::Primitive::kColorRgb4Value: {
978 val.dataType = android::Res_value::TYPE_INT_COLOR_RGB4;
979 val.data = pb_prim.color_rgb4_value();
980 } break;
981 case pb::Primitive::kDimensionValueDeprecated: { // DEPRECATED
982 val.dataType = android::Res_value::TYPE_DIMENSION;
983 float dimen_val = pb_prim.dimension_value_deprecated();
984 val.data = *(uint32_t*)&dimen_val;
985 } break;
986 case pb::Primitive::kFractionValueDeprecated: { // DEPRECATED
987 val.dataType = android::Res_value::TYPE_FRACTION;
988 float fraction_val = pb_prim.fraction_value_deprecated();
989 val.data = *(uint32_t*)&fraction_val;
990 } break;
991 default: {
992 LOG(FATAL) << "Unexpected Primitive type: "
993 << static_cast<uint32_t>(pb_prim.oneof_value_case());
994 return {};
995 } break;
996 }
997 return util::make_unique<BinaryPrimitive>(val);
998 } break;
999
1000 case pb::Item::kId: {
1001 return util::make_unique<Id>();
1002 } break;
1003
1004 case pb::Item::kStr: {
1005 return util::make_unique<String>(
1006 value_pool->MakeRef(pb_item.str().value(), android::StringPool::Context(config)));
1007 } break;
1008
1009 case pb::Item::kRawStr: {
1010 return util::make_unique<RawString>(
1011 value_pool->MakeRef(pb_item.raw_str().value(), android::StringPool::Context(config)));
1012 } break;
1013
1014 case pb::Item::kStyledStr: {
1015 const pb::StyledString& pb_str = pb_item.styled_str();
1016 android::StyleString style_str{pb_str.value()};
1017 for (const pb::StyledString::Span& pb_span : pb_str.span()) {
1018 style_str.spans.push_back(
1019 android::Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()});
1020 }
1021 return util::make_unique<StyledString>(value_pool->MakeRef(
1022 style_str,
1023 android::StringPool::Context(android::StringPool::Context::kNormalPriority, config)));
1024 } break;
1025
1026 case pb::Item::kFile: {
1027 const pb::FileReference& pb_file = pb_item.file();
1028 std::unique_ptr<FileReference> file_ref =
1029 util::make_unique<FileReference>(value_pool->MakeRef(
1030 pb_file.path(),
1031 android::StringPool::Context(android::StringPool::Context::kHighPriority, config)));
1032 file_ref->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
1033 if (files != nullptr) {
1034 file_ref->file = files->FindFile(*file_ref->path);
1035 }
1036 return std::move(file_ref);
1037 } break;
1038
1039 default:
1040 LOG(FATAL) << "unknown item: " << (int)pb_item.value_case();
1041 break;
1042 }
1043 return {};
1044 }
1045
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)1046 std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
1047 const android::ResStringPool& src_pool,
1048 const ConfigDescription& config,
1049 android::StringPool* value_pool,
1050 io::IFileCollection* files, std::string* out_error) {
1051 auto item =
1052 DeserializeItemFromPbInternal(pb_item, src_pool, config, value_pool, files, out_error);
1053 if (item) {
1054 item->SetFlagStatus((FlagStatus)pb_item.flag_status());
1055 if (!pb_item.flag_name().empty()) {
1056 item->SetFlag(
1057 FeatureFlagAttribute{.name = pb_item.flag_name(), .negated = pb_item.flag_negated()});
1058 }
1059 }
1060 return item;
1061 }
1062
DeserializeXmlResourceFromPb(const pb::XmlNode & pb_node,std::string * out_error)1063 std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
1064 std::string* out_error) {
1065 if (!pb_node.has_element()) {
1066 return {};
1067 }
1068
1069 std::unique_ptr<xml::XmlResource> resource = util::make_unique<xml::XmlResource>();
1070 resource->root = util::make_unique<xml::Element>();
1071 if (!DeserializeXmlFromPb(pb_node, resource->root.get(), &resource->string_pool, out_error)) {
1072 return {};
1073 }
1074 return resource;
1075 }
1076
DeserializeXmlFromPb(const pb::XmlNode & pb_node,xml::Element * out_el,android::StringPool * value_pool,std::string * out_error)1077 bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el,
1078 android::StringPool* value_pool, std::string* out_error) {
1079 const pb::XmlElement& pb_el = pb_node.element();
1080 out_el->name = pb_el.name();
1081 out_el->namespace_uri = pb_el.namespace_uri();
1082 out_el->line_number = pb_node.source().line_number();
1083 out_el->column_number = pb_node.source().column_number();
1084
1085 for (const pb::XmlNamespace& pb_ns : pb_el.namespace_declaration()) {
1086 xml::NamespaceDecl decl;
1087 decl.uri = pb_ns.uri();
1088 decl.prefix = pb_ns.prefix();
1089 decl.line_number = pb_ns.source().line_number();
1090 decl.column_number = pb_ns.source().column_number();
1091 out_el->namespace_decls.push_back(std::move(decl));
1092 }
1093
1094 for (const pb::XmlAttribute& pb_attr : pb_el.attribute()) {
1095 xml::Attribute attr;
1096 attr.name = pb_attr.name();
1097 attr.namespace_uri = pb_attr.namespace_uri();
1098 attr.value = pb_attr.value();
1099 if (pb_attr.resource_id() != 0u) {
1100 attr.compiled_attribute = xml::AaptAttribute{Attribute(), ResourceId(pb_attr.resource_id())};
1101 }
1102 if (pb_attr.has_compiled_item()) {
1103 attr.compiled_value =
1104 DeserializeItemFromPb(pb_attr.compiled_item(), {}, {}, value_pool, nullptr, out_error);
1105 if (attr.compiled_value == nullptr) {
1106 return {};
1107 }
1108 attr.compiled_value->SetSource(android::Source().WithLine(pb_attr.source().line_number()));
1109 }
1110 out_el->attributes.push_back(std::move(attr));
1111 }
1112
1113 // Deserialize the children.
1114 for (const pb::XmlNode& pb_child : pb_el.child()) {
1115 switch (pb_child.node_case()) {
1116 case pb::XmlNode::NodeCase::kText: {
1117 std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
1118 text->line_number = pb_child.source().line_number();
1119 text->column_number = pb_child.source().column_number();
1120 text->text = pb_child.text();
1121 out_el->AppendChild(std::move(text));
1122 } break;
1123
1124 case pb::XmlNode::NodeCase::kElement: {
1125 std::unique_ptr<xml::Element> child_el = util::make_unique<xml::Element>();
1126 if (!DeserializeXmlFromPb(pb_child, child_el.get(), value_pool, out_error)) {
1127 return false;
1128 }
1129 out_el->AppendChild(std::move(child_el));
1130 } break;
1131
1132 default:
1133 LOG(FATAL) << "unknown XmlNode " << (int)pb_child.node_case();
1134 break;
1135 }
1136 }
1137 return true;
1138 }
1139
1140 } // namespace aapt
1141