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