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/ProtoSerialize.h"
     18 
     19 #include "ValueVisitor.h"
     20 #include "util/BigBuffer.h"
     21 
     22 using android::ConfigDescription;
     23 
     24 namespace aapt {
     25 
     26 void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool, IDiagnostics* diag) {
     27   BigBuffer buffer(1024);
     28   StringPool::FlattenUtf8(&buffer, pool, diag);
     29 
     30   std::string* data = out_pb_pool->mutable_data();
     31   data->reserve(buffer.size());
     32 
     33   size_t offset = 0;
     34   for (const BigBuffer::Block& block : buffer) {
     35     data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size);
     36     offset += block.size;
     37   }
     38 }
     39 
     40 void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source) {
     41   StringPool::Ref ref = src_pool->MakeRef(source.path);
     42   out_pb_source->set_path_idx(static_cast<uint32_t>(ref.index()));
     43   if (source.line) {
     44     out_pb_source->mutable_position()->set_line_number(static_cast<uint32_t>(source.line.value()));
     45   }
     46 }
     47 
     48 static pb::Visibility::Level SerializeVisibilityToPb(Visibility::Level state) {
     49   switch (state) {
     50     case Visibility::Level::kPrivate:
     51       return pb::Visibility::PRIVATE;
     52     case Visibility::Level::kPublic:
     53       return pb::Visibility::PUBLIC;
     54     default:
     55       break;
     56   }
     57   return pb::Visibility::UNKNOWN;
     58 }
     59 
     60 void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config) {
     61   out_pb_config->set_mcc(config.mcc);
     62   out_pb_config->set_mnc(config.mnc);
     63   out_pb_config->set_locale(config.GetBcp47LanguageTag());
     64 
     65   switch (config.screenLayout & ConfigDescription::MASK_LAYOUTDIR) {
     66     case ConfigDescription::LAYOUTDIR_LTR:
     67       out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR);
     68       break;
     69 
     70     case ConfigDescription::LAYOUTDIR_RTL:
     71       out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL);
     72       break;
     73   }
     74 
     75   out_pb_config->set_screen_width(config.screenWidth);
     76   out_pb_config->set_screen_height(config.screenHeight);
     77   out_pb_config->set_screen_width_dp(config.screenWidthDp);
     78   out_pb_config->set_screen_height_dp(config.screenHeightDp);
     79   out_pb_config->set_smallest_screen_width_dp(config.smallestScreenWidthDp);
     80 
     81   switch (config.screenLayout & ConfigDescription::MASK_SCREENSIZE) {
     82     case ConfigDescription::SCREENSIZE_SMALL:
     83       out_pb_config->set_screen_layout_size(
     84           pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL);
     85       break;
     86 
     87     case ConfigDescription::SCREENSIZE_NORMAL:
     88       out_pb_config->set_screen_layout_size(
     89           pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL);
     90       break;
     91 
     92     case ConfigDescription::SCREENSIZE_LARGE:
     93       out_pb_config->set_screen_layout_size(
     94           pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE);
     95       break;
     96 
     97     case ConfigDescription::SCREENSIZE_XLARGE:
     98       out_pb_config->set_screen_layout_size(
     99           pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE);
    100       break;
    101   }
    102 
    103   switch (config.screenLayout & ConfigDescription::MASK_SCREENLONG) {
    104     case ConfigDescription::SCREENLONG_YES:
    105       out_pb_config->set_screen_layout_long(
    106           pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG);
    107       break;
    108 
    109     case ConfigDescription::SCREENLONG_NO:
    110       out_pb_config->set_screen_layout_long(
    111           pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG);
    112       break;
    113   }
    114 
    115   switch (config.screenLayout2 & ConfigDescription::MASK_SCREENROUND) {
    116     case ConfigDescription::SCREENROUND_YES:
    117       out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND);
    118       break;
    119 
    120     case ConfigDescription::SCREENROUND_NO:
    121       out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND);
    122       break;
    123   }
    124 
    125   switch (config.colorMode & ConfigDescription::MASK_WIDE_COLOR_GAMUT) {
    126     case ConfigDescription::WIDE_COLOR_GAMUT_YES:
    127       out_pb_config->set_wide_color_gamut(pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG);
    128       break;
    129 
    130     case ConfigDescription::WIDE_COLOR_GAMUT_NO:
    131       out_pb_config->set_wide_color_gamut(
    132           pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG);
    133       break;
    134   }
    135 
    136   switch (config.colorMode & ConfigDescription::MASK_HDR) {
    137     case ConfigDescription::HDR_YES:
    138       out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_HIGHDR);
    139       break;
    140 
    141     case ConfigDescription::HDR_NO:
    142       out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_LOWDR);
    143       break;
    144   }
    145 
    146   switch (config.orientation) {
    147     case ConfigDescription::ORIENTATION_PORT:
    148       out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_PORT);
    149       break;
    150 
    151     case ConfigDescription::ORIENTATION_LAND:
    152       out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_LAND);
    153       break;
    154 
    155     case ConfigDescription::ORIENTATION_SQUARE:
    156       out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_SQUARE);
    157       break;
    158   }
    159 
    160   switch (config.uiMode & ConfigDescription::MASK_UI_MODE_TYPE) {
    161     case ConfigDescription::UI_MODE_TYPE_NORMAL:
    162       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL);
    163       break;
    164 
    165     case ConfigDescription::UI_MODE_TYPE_DESK:
    166       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_DESK);
    167       break;
    168 
    169     case ConfigDescription::UI_MODE_TYPE_CAR:
    170       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_CAR);
    171       break;
    172 
    173     case ConfigDescription::UI_MODE_TYPE_TELEVISION:
    174       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION);
    175       break;
    176 
    177     case ConfigDescription::UI_MODE_TYPE_APPLIANCE:
    178       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE);
    179       break;
    180 
    181     case ConfigDescription::UI_MODE_TYPE_WATCH:
    182       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH);
    183       break;
    184 
    185     case ConfigDescription::UI_MODE_TYPE_VR_HEADSET:
    186       out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET);
    187       break;
    188   }
    189 
    190   switch (config.uiMode & ConfigDescription::MASK_UI_MODE_NIGHT) {
    191     case ConfigDescription::UI_MODE_NIGHT_YES:
    192       out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT);
    193       break;
    194 
    195     case ConfigDescription::UI_MODE_NIGHT_NO:
    196       out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT);
    197       break;
    198   }
    199 
    200   out_pb_config->set_density(config.density);
    201 
    202   switch (config.touchscreen) {
    203     case ConfigDescription::TOUCHSCREEN_NOTOUCH:
    204       out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH);
    205       break;
    206 
    207     case ConfigDescription::TOUCHSCREEN_STYLUS:
    208       out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS);
    209       break;
    210 
    211     case ConfigDescription::TOUCHSCREEN_FINGER:
    212       out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER);
    213       break;
    214   }
    215 
    216   switch (config.inputFlags & ConfigDescription::MASK_KEYSHIDDEN) {
    217     case ConfigDescription::KEYSHIDDEN_NO:
    218       out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED);
    219       break;
    220 
    221     case ConfigDescription::KEYSHIDDEN_YES:
    222       out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN);
    223       break;
    224 
    225     case ConfigDescription::KEYSHIDDEN_SOFT:
    226       out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT);
    227       break;
    228   }
    229 
    230   switch (config.keyboard) {
    231     case ConfigDescription::KEYBOARD_NOKEYS:
    232       out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_NOKEYS);
    233       break;
    234 
    235     case ConfigDescription::KEYBOARD_QWERTY:
    236       out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_QWERTY);
    237       break;
    238 
    239     case ConfigDescription::KEYBOARD_12KEY:
    240       out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY);
    241       break;
    242   }
    243 
    244   switch (config.inputFlags & ConfigDescription::MASK_NAVHIDDEN) {
    245     case ConfigDescription::NAVHIDDEN_NO:
    246       out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED);
    247       break;
    248 
    249     case ConfigDescription::NAVHIDDEN_YES:
    250       out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN);
    251       break;
    252   }
    253 
    254   switch (config.navigation) {
    255     case ConfigDescription::NAVIGATION_NONAV:
    256       out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_NONAV);
    257       break;
    258 
    259     case ConfigDescription::NAVIGATION_DPAD:
    260       out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_DPAD);
    261       break;
    262 
    263     case ConfigDescription::NAVIGATION_TRACKBALL:
    264       out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_TRACKBALL);
    265       break;
    266 
    267     case ConfigDescription::NAVIGATION_WHEEL:
    268       out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_WHEEL);
    269       break;
    270   }
    271 
    272   out_pb_config->set_sdk_version(config.sdkVersion);
    273 }
    274 
    275 static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item,
    276                                          std::vector<Overlayable*>& serialized_overlayables,
    277                                          StringPool* source_pool, pb::Entry* pb_entry,
    278                                          pb::ResourceTable* pb_table) {
    279   // Retrieve the index of the overlayable in the list of groups that have already been serialized.
    280   size_t i;
    281   for (i = 0 ; i < serialized_overlayables.size(); i++) {
    282     if (overlayable_item.overlayable.get() == serialized_overlayables[i]) {
    283       break;
    284     }
    285   }
    286 
    287   // Serialize the overlayable if it has not been serialized already.
    288   if (i == serialized_overlayables.size()) {
    289     serialized_overlayables.push_back(overlayable_item.overlayable.get());
    290     pb::Overlayable* pb_overlayable = pb_table->add_overlayable();
    291     pb_overlayable->set_name(overlayable_item.overlayable->name);
    292     pb_overlayable->set_actor(overlayable_item.overlayable->actor);
    293     SerializeSourceToPb(overlayable_item.overlayable->source, source_pool,
    294                         pb_overlayable->mutable_source());
    295   }
    296 
    297   pb::OverlayableItem* pb_overlayable_item = pb_entry->mutable_overlayable_item();
    298   pb_overlayable_item->set_overlayable_idx(i);
    299 
    300   if (overlayable_item.policies & OverlayableItem::Policy::kPublic) {
    301     pb_overlayable_item->add_policy(pb::OverlayableItem::PUBLIC);
    302   }
    303   if (overlayable_item.policies & OverlayableItem::Policy::kProduct) {
    304     pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT);
    305   }
    306   if (overlayable_item.policies & OverlayableItem::Policy::kSystem) {
    307     pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM);
    308   }
    309   if (overlayable_item.policies & OverlayableItem::Policy::kVendor) {
    310     pb_overlayable_item->add_policy(pb::OverlayableItem::VENDOR);
    311   }
    312   if (overlayable_item.policies & OverlayableItem::Policy::kSignature) {
    313     pb_overlayable_item->add_policy(pb::OverlayableItem::SIGNATURE);
    314   }
    315   if (overlayable_item.policies & OverlayableItem::Policy::kOdm) {
    316     pb_overlayable_item->add_policy(pb::OverlayableItem::ODM);
    317   }
    318   if (overlayable_item.policies & OverlayableItem::Policy::kOem) {
    319     pb_overlayable_item->add_policy(pb::OverlayableItem::OEM);
    320   }
    321 
    322   SerializeSourceToPb(overlayable_item.source, source_pool,
    323                       pb_overlayable_item->mutable_source());
    324   pb_overlayable_item->set_comment(overlayable_item.comment);
    325 }
    326 
    327 void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
    328                         IDiagnostics* diag) {
    329   StringPool source_pool;
    330   pb::ToolFingerprint* pb_fingerprint = out_table->add_tool_fingerprint();
    331   pb_fingerprint->set_tool(util::GetToolName());
    332   pb_fingerprint->set_version(util::GetToolFingerprint());
    333 
    334   std::vector<Overlayable*> overlayables;
    335   for (const std::unique_ptr<ResourceTablePackage>& package : table.packages) {
    336     pb::Package* pb_package = out_table->add_package();
    337     if (package->id) {
    338       pb_package->mutable_package_id()->set_id(package->id.value());
    339     }
    340     pb_package->set_package_name(package->name);
    341 
    342     for (const std::unique_ptr<ResourceTableType>& type : package->types) {
    343       pb::Type* pb_type = pb_package->add_type();
    344       if (type->id) {
    345         pb_type->mutable_type_id()->set_id(type->id.value());
    346       }
    347       pb_type->set_name(to_string(type->type).to_string());
    348 
    349       for (const std::unique_ptr<ResourceEntry>& entry : type->entries) {
    350         pb::Entry* pb_entry = pb_type->add_entry();
    351         if (entry->id) {
    352           pb_entry->mutable_entry_id()->set_id(entry->id.value());
    353         }
    354         pb_entry->set_name(entry->name);
    355 
    356         // Write the Visibility struct.
    357         pb::Visibility* pb_visibility = pb_entry->mutable_visibility();
    358         pb_visibility->set_level(SerializeVisibilityToPb(entry->visibility.level));
    359         SerializeSourceToPb(entry->visibility.source, &source_pool,
    360                             pb_visibility->mutable_source());
    361         pb_visibility->set_comment(entry->visibility.comment);
    362 
    363         if (entry->allow_new) {
    364           pb::AllowNew* pb_allow_new = pb_entry->mutable_allow_new();
    365           SerializeSourceToPb(entry->allow_new.value().source, &source_pool,
    366                               pb_allow_new->mutable_source());
    367           pb_allow_new->set_comment(entry->allow_new.value().comment);
    368         }
    369 
    370         if (entry->overlayable_item) {
    371           SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables, &source_pool,
    372                                        pb_entry, out_table);
    373         }
    374 
    375         for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {
    376           pb::ConfigValue* pb_config_value = pb_entry->add_config_value();
    377           SerializeConfig(config_value->config, pb_config_value->mutable_config());
    378           pb_config_value->mutable_config()->set_product(config_value->product);
    379           SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(), &source_pool);
    380         }
    381       }
    382     }
    383   }
    384   SerializeStringPoolToPb(source_pool, out_table->mutable_source_pool(), diag);
    385 }
    386 
    387 static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) {
    388   switch (type) {
    389     case Reference::Type::kResource:
    390       return pb::Reference_Type_REFERENCE;
    391     case Reference::Type::kAttribute:
    392       return pb::Reference_Type_ATTRIBUTE;
    393     default:
    394       break;
    395   }
    396   return pb::Reference_Type_REFERENCE;
    397 }
    398 
    399 static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) {
    400   pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id);
    401 
    402   if (ref.name) {
    403     pb_ref->set_name(ref.name.value().to_string());
    404   }
    405 
    406   pb_ref->set_private_(ref.private_reference);
    407   pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type));
    408 }
    409 
    410 template <typename T>
    411 static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, StringPool* src_pool) {
    412   if (src_pool != nullptr) {
    413     SerializeSourceToPb(item.GetSource(), src_pool, pb_item->mutable_source());
    414   }
    415   pb_item->set_comment(item.GetComment());
    416 }
    417 
    418 static pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx) {
    419   switch (plural_idx) {
    420     case Plural::Zero:
    421       return pb::Plural_Arity_ZERO;
    422     case Plural::One:
    423       return pb::Plural_Arity_ONE;
    424     case Plural::Two:
    425       return pb::Plural_Arity_TWO;
    426     case Plural::Few:
    427       return pb::Plural_Arity_FEW;
    428     case Plural::Many:
    429       return pb::Plural_Arity_MANY;
    430     default:
    431       break;
    432   }
    433   return pb::Plural_Arity_OTHER;
    434 }
    435 
    436 static pb::FileReference::Type SerializeFileReferenceTypeToPb(const ResourceFile::Type& type) {
    437   switch (type) {
    438     case ResourceFile::Type::kBinaryXml:
    439       return pb::FileReference::BINARY_XML;
    440     case ResourceFile::Type::kProtoXml:
    441       return pb::FileReference::PROTO_XML;
    442     case ResourceFile::Type::kPng:
    443       return pb::FileReference::PNG;
    444     default:
    445       return pb::FileReference::UNKNOWN;
    446   }
    447 }
    448 
    449 namespace {
    450 
    451 class ValueSerializer : public ConstValueVisitor {
    452  public:
    453   using ConstValueVisitor::Visit;
    454 
    455   ValueSerializer(pb::Value* out_value, StringPool* src_pool)
    456       : out_value_(out_value), src_pool_(src_pool) {
    457   }
    458 
    459   void Visit(const Reference* ref) override {
    460     SerializeReferenceToPb(*ref, out_value_->mutable_item()->mutable_ref());
    461   }
    462 
    463   void Visit(const String* str) override {
    464     out_value_->mutable_item()->mutable_str()->set_value(*str->value);
    465   }
    466 
    467   void Visit(const RawString* str) override {
    468     out_value_->mutable_item()->mutable_raw_str()->set_value(*str->value);
    469   }
    470 
    471   void Visit(const StyledString* str) override {
    472     pb::StyledString* pb_str = out_value_->mutable_item()->mutable_styled_str();
    473     pb_str->set_value(str->value->value);
    474     for (const StringPool::Span& span : str->value->spans) {
    475       pb::StyledString::Span* pb_span = pb_str->add_span();
    476       pb_span->set_tag(*span.name);
    477       pb_span->set_first_char(span.first_char);
    478       pb_span->set_last_char(span.last_char);
    479     }
    480   }
    481 
    482   void Visit(const FileReference* file) override {
    483     pb::FileReference* pb_file = out_value_->mutable_item()->mutable_file();
    484     pb_file->set_path(*file->path);
    485     pb_file->set_type(SerializeFileReferenceTypeToPb(file->type));
    486   }
    487 
    488   void Visit(const Id* /*id*/) override {
    489     out_value_->mutable_item()->mutable_id();
    490   }
    491 
    492   void Visit(const BinaryPrimitive* prim) override {
    493     android::Res_value val = {};
    494     prim->Flatten(&val);
    495 
    496     pb::Primitive* pb_prim = out_value_->mutable_item()->mutable_prim();
    497 
    498     switch (val.dataType) {
    499       case android::Res_value::TYPE_NULL: {
    500         if (val.data == android::Res_value::DATA_NULL_UNDEFINED) {
    501           pb_prim->set_allocated_null_value(new pb::Primitive_NullType());
    502         } else if (val.data == android::Res_value::DATA_NULL_EMPTY) {
    503           pb_prim->set_allocated_empty_value(new pb::Primitive_EmptyType());
    504         } else {
    505           LOG(FATAL) << "Unexpected data value for TYPE_NULL BinaryPrimitive: " << val.data;
    506         }
    507       } break;
    508       case android::Res_value::TYPE_FLOAT: {
    509         pb_prim->set_float_value(*(float*)&val.data);
    510       } break;
    511       case android::Res_value::TYPE_DIMENSION: {
    512         pb_prim->set_dimension_value(val.data);
    513       } break;
    514       case android::Res_value::TYPE_FRACTION: {
    515         pb_prim->set_fraction_value(val.data);
    516       } break;
    517       case android::Res_value::TYPE_INT_DEC: {
    518         pb_prim->set_int_decimal_value(static_cast<int32_t>(val.data));
    519       } break;
    520       case android::Res_value::TYPE_INT_HEX: {
    521         pb_prim->set_int_hexadecimal_value(val.data);
    522       } break;
    523       case android::Res_value::TYPE_INT_BOOLEAN: {
    524         pb_prim->set_boolean_value(static_cast<bool>(val.data));
    525       } break;
    526       case android::Res_value::TYPE_INT_COLOR_ARGB8: {
    527         pb_prim->set_color_argb8_value(val.data);
    528       } break;
    529       case android::Res_value::TYPE_INT_COLOR_RGB8: {
    530         pb_prim->set_color_rgb8_value(val.data);
    531       } break;
    532       case android::Res_value::TYPE_INT_COLOR_ARGB4: {
    533         pb_prim->set_color_argb4_value(val.data);
    534       } break;
    535       case android::Res_value::TYPE_INT_COLOR_RGB4: {
    536         pb_prim->set_color_rgb4_value(val.data);
    537       } break;
    538       default:
    539         LOG(FATAL) << "Unexpected BinaryPrimitive type: " << val.dataType;
    540         break;
    541     }
    542   }
    543 
    544   void Visit(const Attribute* attr) override {
    545     pb::Attribute* pb_attr = out_value_->mutable_compound_value()->mutable_attr();
    546     pb_attr->set_format_flags(attr->type_mask);
    547     pb_attr->set_min_int(attr->min_int);
    548     pb_attr->set_max_int(attr->max_int);
    549 
    550     for (auto& symbol : attr->symbols) {
    551       pb::Attribute_Symbol* pb_symbol = pb_attr->add_symbol();
    552       SerializeItemMetaDataToPb(symbol.symbol, pb_symbol, src_pool_);
    553       SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name());
    554       pb_symbol->set_value(symbol.value);
    555     }
    556   }
    557 
    558   void Visit(const Style* style) override {
    559     pb::Style* pb_style = out_value_->mutable_compound_value()->mutable_style();
    560     if (style->parent) {
    561       const Reference& parent = style->parent.value();
    562       SerializeReferenceToPb(parent, pb_style->mutable_parent());
    563       if (src_pool_ != nullptr) {
    564         SerializeSourceToPb(parent.GetSource(), src_pool_, pb_style->mutable_parent_source());
    565       }
    566     }
    567 
    568     for (const Style::Entry& entry : style->entries) {
    569       pb::Style_Entry* pb_entry = pb_style->add_entry();
    570       SerializeReferenceToPb(entry.key, pb_entry->mutable_key());
    571       SerializeItemMetaDataToPb(entry.key, pb_entry, src_pool_);
    572       SerializeItemToPb(*entry.value, pb_entry->mutable_item());
    573     }
    574   }
    575 
    576   void Visit(const Styleable* styleable) override {
    577     pb::Styleable* pb_styleable = out_value_->mutable_compound_value()->mutable_styleable();
    578     for (const Reference& entry : styleable->entries) {
    579       pb::Styleable_Entry* pb_entry = pb_styleable->add_entry();
    580       SerializeItemMetaDataToPb(entry, pb_entry, src_pool_);
    581       SerializeReferenceToPb(entry, pb_entry->mutable_attr());
    582     }
    583   }
    584 
    585   void Visit(const Array* array) override {
    586     pb::Array* pb_array = out_value_->mutable_compound_value()->mutable_array();
    587     for (const std::unique_ptr<Item>& element : array->elements) {
    588       pb::Array_Element* pb_element = pb_array->add_element();
    589       SerializeItemMetaDataToPb(*element, pb_element, src_pool_);
    590       SerializeItemToPb(*element, pb_element->mutable_item());
    591     }
    592   }
    593 
    594   void Visit(const Plural* plural) override {
    595     pb::Plural* pb_plural = out_value_->mutable_compound_value()->mutable_plural();
    596     const size_t count = plural->values.size();
    597     for (size_t i = 0; i < count; i++) {
    598       if (!plural->values[i]) {
    599         // No plural value set here.
    600         continue;
    601       }
    602 
    603       pb::Plural_Entry* pb_entry = pb_plural->add_entry();
    604       pb_entry->set_arity(SerializePluralEnumToPb(i));
    605       SerializeItemMetaDataToPb(*plural->values[i], pb_entry, src_pool_);
    606       SerializeItemToPb(*plural->values[i], pb_entry->mutable_item());
    607     }
    608   }
    609 
    610   void VisitAny(const Value* unknown) override {
    611     LOG(FATAL) << "unimplemented value: " << *unknown;
    612   }
    613 
    614  private:
    615   pb::Value* out_value_;
    616   StringPool* src_pool_;
    617 };
    618 
    619 }  // namespace
    620 
    621 void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool) {
    622   ValueSerializer serializer(out_value, src_pool);
    623   value.Accept(&serializer);
    624 
    625   // Serialize the meta-data of the Value.
    626   out_value->set_comment(value.GetComment());
    627   out_value->set_weak(value.IsWeak());
    628   if (src_pool != nullptr) {
    629     SerializeSourceToPb(value.GetSource(), src_pool, out_value->mutable_source());
    630   }
    631 }
    632 
    633 void SerializeItemToPb(const Item& item, pb::Item* out_item) {
    634   pb::Value value;
    635   ValueSerializer serializer(&value, nullptr);
    636   item.Accept(&serializer);
    637   out_item->MergeFrom(value.item());
    638 }
    639 
    640 void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
    641   out_file->set_resource_name(file.name.to_string());
    642   out_file->set_source_path(file.source.path);
    643   out_file->set_type(SerializeFileReferenceTypeToPb(file.type));
    644   SerializeConfig(file.config, out_file->mutable_config());
    645 
    646   for (const SourcedResourceName& exported : file.exported_symbols) {
    647     pb::internal::CompiledFile_Symbol* pb_symbol = out_file->add_exported_symbol();
    648     pb_symbol->set_resource_name(exported.name.to_string());
    649     pb_symbol->mutable_source()->set_line_number(exported.line);
    650   }
    651 }
    652 
    653 static void SerializeXmlCommon(const xml::Node& node, pb::XmlNode* out_node) {
    654   pb::SourcePosition* pb_src = out_node->mutable_source();
    655   pb_src->set_line_number(node.line_number);
    656   pb_src->set_column_number(node.column_number);
    657 }
    658 
    659 void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node,
    660                       const SerializeXmlOptions options) {
    661   SerializeXmlCommon(el, out_node);
    662 
    663   pb::XmlElement* pb_element = out_node->mutable_element();
    664   pb_element->set_name(el.name);
    665   pb_element->set_namespace_uri(el.namespace_uri);
    666 
    667   for (const xml::NamespaceDecl& ns : el.namespace_decls) {
    668     pb::XmlNamespace* pb_ns = pb_element->add_namespace_declaration();
    669     pb_ns->set_prefix(ns.prefix);
    670     pb_ns->set_uri(ns.uri);
    671     pb::SourcePosition* pb_src = pb_ns->mutable_source();
    672     pb_src->set_line_number(ns.line_number);
    673     pb_src->set_column_number(ns.column_number);
    674   }
    675 
    676   for (const xml::Attribute& attr : el.attributes) {
    677     pb::XmlAttribute* pb_attr = pb_element->add_attribute();
    678     pb_attr->set_name(attr.name);
    679     pb_attr->set_namespace_uri(attr.namespace_uri);
    680     pb_attr->set_value(attr.value);
    681     if (attr.compiled_attribute) {
    682       const ResourceId attr_id = attr.compiled_attribute.value().id.value_or_default({});
    683       pb_attr->set_resource_id(attr_id.id);
    684     }
    685     if (attr.compiled_value != nullptr) {
    686       SerializeItemToPb(*attr.compiled_value, pb_attr->mutable_compiled_item());
    687       pb::SourcePosition* pb_src = pb_attr->mutable_source();
    688       pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or_default(0));
    689     }
    690   }
    691 
    692   for (const std::unique_ptr<xml::Node>& child : el.children) {
    693     if (const xml::Element* child_el = xml::NodeCast<xml::Element>(child.get())) {
    694       SerializeXmlToPb(*child_el, pb_element->add_child());
    695     } else if (const xml::Text* text_el = xml::NodeCast<xml::Text>(child.get())) {
    696       if (options.remove_empty_text_nodes && util::TrimWhitespace(text_el->text).empty()) {
    697         // Do not serialize whitespace text nodes if told not to
    698         continue;
    699       }
    700 
    701       pb::XmlNode *pb_child_node = pb_element->add_child();
    702       SerializeXmlCommon(*text_el, pb_child_node);
    703       pb_child_node->set_text(text_el->text);
    704     } else {
    705       LOG(FATAL) << "unhandled XmlNode type";
    706     }
    707   }
    708 }
    709 
    710 void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node,
    711                               const SerializeXmlOptions options) {
    712   SerializeXmlToPb(*resource.root, out_node, options);
    713 }
    714 
    715 }  // namespace aapt
    716