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 
SerializeStringPoolToPb(const StringPool & pool,pb::StringPool * out_pb_pool,IDiagnostics * diag)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 
SerializeSourceToPb(const Source & source,StringPool * src_pool,pb::Source * out_pb_source)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 
SerializeVisibilityToPb(Visibility::Level state)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 
SerializeConfig(const ConfigDescription & config,pb::Configuration * out_pb_config)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 
SerializeOverlayableItemToPb(const OverlayableItem & overlayable_item,std::vector<Overlayable * > & serialized_overlayables,StringPool * source_pool,pb::Entry * pb_entry,pb::ResourceTable * pb_table)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 
SerializeTableToPb(const ResourceTable & table,pb::ResourceTable * out_table,IDiagnostics * diag)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 
SerializeReferenceTypeToPb(Reference::Type type)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 
SerializeReferenceToPb(const Reference & ref,pb::Reference * pb_ref)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>
SerializeItemMetaDataToPb(const Item & item,T * pb_item,StringPool * src_pool)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 
SerializePluralEnumToPb(size_t plural_idx)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 
SerializeFileReferenceTypeToPb(const ResourceFile::Type & type)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 
ValueSerializer(pb::Value * out_value,StringPool * src_pool)455   ValueSerializer(pb::Value* out_value, StringPool* src_pool)
456       : out_value_(out_value), src_pool_(src_pool) {
457   }
458 
Visit(const Reference * ref)459   void Visit(const Reference* ref) override {
460     SerializeReferenceToPb(*ref, out_value_->mutable_item()->mutable_ref());
461   }
462 
Visit(const String * str)463   void Visit(const String* str) override {
464     out_value_->mutable_item()->mutable_str()->set_value(*str->value);
465   }
466 
Visit(const RawString * str)467   void Visit(const RawString* str) override {
468     out_value_->mutable_item()->mutable_raw_str()->set_value(*str->value);
469   }
470 
Visit(const StyledString * str)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 
Visit(const FileReference * file)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 
Visit(const Id *)488   void Visit(const Id* /*id*/) override {
489     out_value_->mutable_item()->mutable_id();
490   }
491 
Visit(const BinaryPrimitive * prim)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 
Visit(const Attribute * attr)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 
Visit(const Style * style)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 
Visit(const Styleable * styleable)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 
Visit(const Array * array)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 
Visit(const Plural * plural)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 
VisitAny(const Value * unknown)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 
SerializeValueToPb(const Value & value,pb::Value * out_value,StringPool * src_pool)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 
SerializeItemToPb(const Item & item,pb::Item * out_item)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 
SerializeCompiledFileToPb(const ResourceFile & file,pb::internal::CompiledFile * out_file)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 
SerializeXmlCommon(const xml::Node & node,pb::XmlNode * out_node)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 
SerializeXmlToPb(const xml::Element & el,pb::XmlNode * out_node,const SerializeXmlOptions options)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 
SerializeXmlResourceToPb(const xml::XmlResource & resource,pb::XmlNode * out_node,const SerializeXmlOptions options)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