Home | History | Annotate | Download | only in proto
      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 
     39   explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping)
     40       : mapping_(mapping) {
     41     CHECK(mapping_ != nullptr);
     42   }
     43 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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>
    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 
    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 
    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 
    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 
    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 
    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