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
SerializeStringPoolToPb(const StringPool & pool,pb::StringPool * out_pb_pool,IDiagnostics * diag)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
SerializeSourceToPb(const Source & source,StringPool * src_pool,pb::Source * out_pb_source)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
SerializeVisibilityToPb(Visibility::Level state)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
SerializeConfig(const ConfigDescription & config,pb::Configuration * out_pb_config)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
SerializeTableToPb(const ResourceTable & table,pb::ResourceTable * out_table,IDiagnostics * diag)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
SerializeReferenceTypeToPb(Reference::Type type)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
SerializeReferenceToPb(const Reference & ref,pb::Reference * pb_ref)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>
SerializeItemMetaDataToPb(const Item & item,T * pb_item,StringPool * src_pool)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
SerializePluralEnumToPb(size_t plural_idx)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
SerializeFileReferenceTypeToPb(const ResourceFile::Type & type)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
ValueSerializer(pb::Value * out_value,StringPool * src_pool)398 ValueSerializer(pb::Value* out_value, StringPool* src_pool)
399 : out_value_(out_value), src_pool_(src_pool) {
400 }
401
Visit(const Reference * ref)402 void Visit(const Reference* ref) override {
403 SerializeReferenceToPb(*ref, out_value_->mutable_item()->mutable_ref());
404 }
405
Visit(const String * str)406 void Visit(const String* str) override {
407 out_value_->mutable_item()->mutable_str()->set_value(*str->value);
408 }
409
Visit(const RawString * str)410 void Visit(const RawString* str) override {
411 out_value_->mutable_item()->mutable_raw_str()->set_value(*str->value);
412 }
413
Visit(const StyledString * str)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
Visit(const FileReference * file)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
Visit(const Id *)431 void Visit(const Id* /*id*/) override {
432 out_value_->mutable_item()->mutable_id();
433 }
434
Visit(const BinaryPrimitive * prim)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
Visit(const Attribute * attr)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
Visit(const Style * style)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
Visit(const Styleable * styleable)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
Visit(const Array * array)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
Visit(const Plural * plural)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
VisitAny(const Value * unknown)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
SerializeValueToPb(const Value & value,pb::Value * out_value,StringPool * src_pool)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
SerializeItemToPb(const Item & item,pb::Item * out_item)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
SerializeCompiledFileToPb(const ResourceFile & file,pb::internal::CompiledFile * out_file)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
SerializeXmlCommon(const xml::Node & node,pb::XmlNode * out_node)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
SerializeXmlToPb(const xml::Element & el,pb::XmlNode * out_node)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
SerializeXmlResourceToPb(const xml::XmlResource & resource,pb::XmlNode * out_node)647 void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node) {
648 SerializeXmlToPb(*resource.root, out_node);
649 }
650
651 } // namespace aapt
652