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