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