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