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