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