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
329 if (source_pool != nullptr) {
330 SerializeSourceToPb(overlayable_item.source, source_pool,
331 pb_overlayable_item->mutable_source());
332 }
333 pb_overlayable_item->set_comment(overlayable_item.comment);
334 }
335
SerializeTableToPb(const ResourceTable & table,pb::ResourceTable * out_table,IDiagnostics * diag,SerializeTableOptions options)336 void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
337 IDiagnostics* diag, SerializeTableOptions options) {
338 auto source_pool = (options.exclude_sources) ? nullptr : util::make_unique<StringPool>();
339
340 pb::ToolFingerprint* pb_fingerprint = out_table->add_tool_fingerprint();
341 pb_fingerprint->set_tool(util::GetToolName());
342 pb_fingerprint->set_version(util::GetToolFingerprint());
343
344 std::vector<Overlayable*> overlayables;
345 for (const std::unique_ptr<ResourceTablePackage>& package : table.packages) {
346 pb::Package* pb_package = out_table->add_package();
347 if (package->id) {
348 pb_package->mutable_package_id()->set_id(package->id.value());
349 }
350 pb_package->set_package_name(package->name);
351
352 for (const std::unique_ptr<ResourceTableType>& type : package->types) {
353 pb::Type* pb_type = pb_package->add_type();
354 if (type->id) {
355 pb_type->mutable_type_id()->set_id(type->id.value());
356 }
357 pb_type->set_name(to_string(type->type).to_string());
358
359 for (const std::unique_ptr<ResourceEntry>& entry : type->entries) {
360 pb::Entry* pb_entry = pb_type->add_entry();
361 if (entry->id) {
362 pb_entry->mutable_entry_id()->set_id(entry->id.value());
363 }
364 pb_entry->set_name(entry->name);
365
366 // Write the Visibility struct.
367 pb::Visibility* pb_visibility = pb_entry->mutable_visibility();
368 pb_visibility->set_level(SerializeVisibilityToPb(entry->visibility.level));
369 if (source_pool != nullptr) {
370 SerializeSourceToPb(entry->visibility.source, source_pool.get(),
371 pb_visibility->mutable_source());
372 }
373 pb_visibility->set_comment(entry->visibility.comment);
374
375 if (entry->allow_new) {
376 pb::AllowNew* pb_allow_new = pb_entry->mutable_allow_new();
377 if (source_pool != nullptr) {
378 SerializeSourceToPb(entry->allow_new.value().source, source_pool.get(),
379 pb_allow_new->mutable_source());
380 }
381 pb_allow_new->set_comment(entry->allow_new.value().comment);
382 }
383
384 if (entry->overlayable_item) {
385 SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables,
386 source_pool.get(), pb_entry, out_table);
387 }
388
389 for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {
390 pb::ConfigValue* pb_config_value = pb_entry->add_config_value();
391 SerializeConfig(config_value->config, pb_config_value->mutable_config());
392 pb_config_value->mutable_config()->set_product(config_value->product);
393 SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(),
394 source_pool.get());
395 }
396 }
397 }
398 }
399
400 if (source_pool != nullptr) {
401 SerializeStringPoolToPb(*source_pool, out_table->mutable_source_pool(), diag);
402 }
403 }
404
SerializeReferenceTypeToPb(Reference::Type type)405 static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) {
406 switch (type) {
407 case Reference::Type::kResource:
408 return pb::Reference_Type_REFERENCE;
409 case Reference::Type::kAttribute:
410 return pb::Reference_Type_ATTRIBUTE;
411 default:
412 break;
413 }
414 return pb::Reference_Type_REFERENCE;
415 }
416
SerializeReferenceToPb(const Reference & ref,pb::Reference * pb_ref)417 static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) {
418 pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id);
419
420 if (ref.name) {
421 pb_ref->set_name(ref.name.value().to_string());
422 }
423
424 pb_ref->set_private_(ref.private_reference);
425 pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type));
426 if (ref.is_dynamic) {
427 pb_ref->mutable_is_dynamic()->set_value(ref.is_dynamic);
428 }
429 }
430
431 template <typename T>
SerializeItemMetaDataToPb(const Item & item,T * pb_item,StringPool * src_pool)432 static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, StringPool* src_pool) {
433 if (src_pool != nullptr) {
434 SerializeSourceToPb(item.GetSource(), src_pool, pb_item->mutable_source());
435 }
436 pb_item->set_comment(item.GetComment());
437 }
438
SerializePluralEnumToPb(size_t plural_idx)439 static pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx) {
440 switch (plural_idx) {
441 case Plural::Zero:
442 return pb::Plural_Arity_ZERO;
443 case Plural::One:
444 return pb::Plural_Arity_ONE;
445 case Plural::Two:
446 return pb::Plural_Arity_TWO;
447 case Plural::Few:
448 return pb::Plural_Arity_FEW;
449 case Plural::Many:
450 return pb::Plural_Arity_MANY;
451 default:
452 break;
453 }
454 return pb::Plural_Arity_OTHER;
455 }
456
SerializeFileReferenceTypeToPb(const ResourceFile::Type & type)457 static pb::FileReference::Type SerializeFileReferenceTypeToPb(const ResourceFile::Type& type) {
458 switch (type) {
459 case ResourceFile::Type::kBinaryXml:
460 return pb::FileReference::BINARY_XML;
461 case ResourceFile::Type::kProtoXml:
462 return pb::FileReference::PROTO_XML;
463 case ResourceFile::Type::kPng:
464 return pb::FileReference::PNG;
465 default:
466 return pb::FileReference::UNKNOWN;
467 }
468 }
469
470 namespace {
471
472 class ValueSerializer : public ConstValueVisitor {
473 public:
474 using ConstValueVisitor::Visit;
475
ValueSerializer(pb::Value * out_value,StringPool * src_pool)476 ValueSerializer(pb::Value* out_value, StringPool* src_pool)
477 : out_value_(out_value), src_pool_(src_pool) {
478 }
479
Visit(const Reference * ref)480 void Visit(const Reference* ref) override {
481 SerializeReferenceToPb(*ref, out_value_->mutable_item()->mutable_ref());
482 }
483
Visit(const String * str)484 void Visit(const String* str) override {
485 out_value_->mutable_item()->mutable_str()->set_value(*str->value);
486 }
487
Visit(const RawString * str)488 void Visit(const RawString* str) override {
489 out_value_->mutable_item()->mutable_raw_str()->set_value(*str->value);
490 }
491
Visit(const StyledString * str)492 void Visit(const StyledString* str) override {
493 pb::StyledString* pb_str = out_value_->mutable_item()->mutable_styled_str();
494 pb_str->set_value(str->value->value);
495 for (const StringPool::Span& span : str->value->spans) {
496 pb::StyledString::Span* pb_span = pb_str->add_span();
497 pb_span->set_tag(*span.name);
498 pb_span->set_first_char(span.first_char);
499 pb_span->set_last_char(span.last_char);
500 }
501 }
502
Visit(const FileReference * file)503 void Visit(const FileReference* file) override {
504 pb::FileReference* pb_file = out_value_->mutable_item()->mutable_file();
505 pb_file->set_path(*file->path);
506 pb_file->set_type(SerializeFileReferenceTypeToPb(file->type));
507 }
508
Visit(const Id *)509 void Visit(const Id* /*id*/) override {
510 out_value_->mutable_item()->mutable_id();
511 }
512
Visit(const BinaryPrimitive * prim)513 void Visit(const BinaryPrimitive* prim) override {
514 android::Res_value val = {};
515 prim->Flatten(&val);
516
517 pb::Primitive* pb_prim = out_value_->mutable_item()->mutable_prim();
518
519 switch (val.dataType) {
520 case android::Res_value::TYPE_NULL: {
521 if (val.data == android::Res_value::DATA_NULL_UNDEFINED) {
522 pb_prim->set_allocated_null_value(new pb::Primitive_NullType());
523 } else if (val.data == android::Res_value::DATA_NULL_EMPTY) {
524 pb_prim->set_allocated_empty_value(new pb::Primitive_EmptyType());
525 } else {
526 LOG(FATAL) << "Unexpected data value for TYPE_NULL BinaryPrimitive: " << val.data;
527 }
528 } break;
529 case android::Res_value::TYPE_FLOAT: {
530 pb_prim->set_float_value(*(float*)&val.data);
531 } break;
532 case android::Res_value::TYPE_DIMENSION: {
533 pb_prim->set_dimension_value(val.data);
534 } break;
535 case android::Res_value::TYPE_FRACTION: {
536 pb_prim->set_fraction_value(val.data);
537 } break;
538 case android::Res_value::TYPE_INT_DEC: {
539 pb_prim->set_int_decimal_value(static_cast<int32_t>(val.data));
540 } break;
541 case android::Res_value::TYPE_INT_HEX: {
542 pb_prim->set_int_hexadecimal_value(val.data);
543 } break;
544 case android::Res_value::TYPE_INT_BOOLEAN: {
545 pb_prim->set_boolean_value(static_cast<bool>(val.data));
546 } break;
547 case android::Res_value::TYPE_INT_COLOR_ARGB8: {
548 pb_prim->set_color_argb8_value(val.data);
549 } break;
550 case android::Res_value::TYPE_INT_COLOR_RGB8: {
551 pb_prim->set_color_rgb8_value(val.data);
552 } break;
553 case android::Res_value::TYPE_INT_COLOR_ARGB4: {
554 pb_prim->set_color_argb4_value(val.data);
555 } break;
556 case android::Res_value::TYPE_INT_COLOR_RGB4: {
557 pb_prim->set_color_rgb4_value(val.data);
558 } break;
559 default:
560 LOG(FATAL) << "Unexpected BinaryPrimitive type: " << val.dataType;
561 break;
562 }
563 }
564
Visit(const Attribute * attr)565 void Visit(const Attribute* attr) override {
566 pb::Attribute* pb_attr = out_value_->mutable_compound_value()->mutable_attr();
567 pb_attr->set_format_flags(attr->type_mask);
568 pb_attr->set_min_int(attr->min_int);
569 pb_attr->set_max_int(attr->max_int);
570
571 for (auto& symbol : attr->symbols) {
572 pb::Attribute_Symbol* pb_symbol = pb_attr->add_symbol();
573 SerializeItemMetaDataToPb(symbol.symbol, pb_symbol, src_pool_);
574 SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name());
575 pb_symbol->set_value(symbol.value);
576 pb_symbol->set_type(symbol.type);
577 }
578 }
579
Visit(const Style * style)580 void Visit(const Style* style) override {
581 pb::Style* pb_style = out_value_->mutable_compound_value()->mutable_style();
582 if (style->parent) {
583 const Reference& parent = style->parent.value();
584 SerializeReferenceToPb(parent, pb_style->mutable_parent());
585 if (src_pool_ != nullptr) {
586 SerializeSourceToPb(parent.GetSource(), src_pool_, pb_style->mutable_parent_source());
587 }
588 }
589
590 for (const Style::Entry& entry : style->entries) {
591 pb::Style_Entry* pb_entry = pb_style->add_entry();
592 SerializeReferenceToPb(entry.key, pb_entry->mutable_key());
593 SerializeItemMetaDataToPb(entry.key, pb_entry, src_pool_);
594 SerializeItemToPb(*entry.value, pb_entry->mutable_item());
595 }
596 }
597
Visit(const Styleable * styleable)598 void Visit(const Styleable* styleable) override {
599 pb::Styleable* pb_styleable = out_value_->mutable_compound_value()->mutable_styleable();
600 for (const Reference& entry : styleable->entries) {
601 pb::Styleable_Entry* pb_entry = pb_styleable->add_entry();
602 SerializeItemMetaDataToPb(entry, pb_entry, src_pool_);
603 SerializeReferenceToPb(entry, pb_entry->mutable_attr());
604 }
605 }
606
Visit(const Array * array)607 void Visit(const Array* array) override {
608 pb::Array* pb_array = out_value_->mutable_compound_value()->mutable_array();
609 for (const std::unique_ptr<Item>& element : array->elements) {
610 pb::Array_Element* pb_element = pb_array->add_element();
611 SerializeItemMetaDataToPb(*element, pb_element, src_pool_);
612 SerializeItemToPb(*element, pb_element->mutable_item());
613 }
614 }
615
Visit(const Plural * plural)616 void Visit(const Plural* plural) override {
617 pb::Plural* pb_plural = out_value_->mutable_compound_value()->mutable_plural();
618 const size_t count = plural->values.size();
619 for (size_t i = 0; i < count; i++) {
620 if (!plural->values[i]) {
621 // No plural value set here.
622 continue;
623 }
624
625 pb::Plural_Entry* pb_entry = pb_plural->add_entry();
626 pb_entry->set_arity(SerializePluralEnumToPb(i));
627 SerializeItemMetaDataToPb(*plural->values[i], pb_entry, src_pool_);
628 SerializeItemToPb(*plural->values[i], pb_entry->mutable_item());
629 }
630 }
631
VisitAny(const Value * unknown)632 void VisitAny(const Value* unknown) override {
633 LOG(FATAL) << "unimplemented value: " << *unknown;
634 }
635
636 private:
637 pb::Value* out_value_;
638 StringPool* src_pool_;
639 };
640
641 } // namespace
642
SerializeValueToPb(const Value & value,pb::Value * out_value,StringPool * src_pool)643 void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool) {
644 ValueSerializer serializer(out_value, src_pool);
645 value.Accept(&serializer);
646
647 // Serialize the meta-data of the Value.
648 out_value->set_comment(value.GetComment());
649 out_value->set_weak(value.IsWeak());
650 if (src_pool != nullptr) {
651 SerializeSourceToPb(value.GetSource(), src_pool, out_value->mutable_source());
652 }
653 }
654
SerializeItemToPb(const Item & item,pb::Item * out_item)655 void SerializeItemToPb(const Item& item, pb::Item* out_item) {
656 pb::Value value;
657 ValueSerializer serializer(&value, nullptr);
658 item.Accept(&serializer);
659 out_item->MergeFrom(value.item());
660 }
661
SerializeCompiledFileToPb(const ResourceFile & file,pb::internal::CompiledFile * out_file)662 void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
663 out_file->set_resource_name(file.name.to_string());
664 out_file->set_source_path(file.source.path);
665 out_file->set_type(SerializeFileReferenceTypeToPb(file.type));
666 SerializeConfig(file.config, out_file->mutable_config());
667
668 for (const SourcedResourceName& exported : file.exported_symbols) {
669 pb::internal::CompiledFile_Symbol* pb_symbol = out_file->add_exported_symbol();
670 pb_symbol->set_resource_name(exported.name.to_string());
671 pb_symbol->mutable_source()->set_line_number(exported.line);
672 }
673 }
674
SerializeXmlCommon(const xml::Node & node,pb::XmlNode * out_node)675 static void SerializeXmlCommon(const xml::Node& node, pb::XmlNode* out_node) {
676 pb::SourcePosition* pb_src = out_node->mutable_source();
677 pb_src->set_line_number(node.line_number);
678 pb_src->set_column_number(node.column_number);
679 }
680
SerializeXmlToPb(const xml::Element & el,pb::XmlNode * out_node,const SerializeXmlOptions options)681 void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node,
682 const SerializeXmlOptions options) {
683 SerializeXmlCommon(el, out_node);
684
685 pb::XmlElement* pb_element = out_node->mutable_element();
686 pb_element->set_name(el.name);
687 pb_element->set_namespace_uri(el.namespace_uri);
688
689 for (const xml::NamespaceDecl& ns : el.namespace_decls) {
690 pb::XmlNamespace* pb_ns = pb_element->add_namespace_declaration();
691 pb_ns->set_prefix(ns.prefix);
692 pb_ns->set_uri(ns.uri);
693 pb::SourcePosition* pb_src = pb_ns->mutable_source();
694 pb_src->set_line_number(ns.line_number);
695 pb_src->set_column_number(ns.column_number);
696 }
697
698 for (const xml::Attribute& attr : el.attributes) {
699 pb::XmlAttribute* pb_attr = pb_element->add_attribute();
700 pb_attr->set_name(attr.name);
701 pb_attr->set_namespace_uri(attr.namespace_uri);
702 pb_attr->set_value(attr.value);
703 if (attr.compiled_attribute) {
704 const ResourceId attr_id = attr.compiled_attribute.value().id.value_or_default({});
705 pb_attr->set_resource_id(attr_id.id);
706 }
707 if (attr.compiled_value != nullptr) {
708 SerializeItemToPb(*attr.compiled_value, pb_attr->mutable_compiled_item());
709 pb::SourcePosition* pb_src = pb_attr->mutable_source();
710 pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or_default(0));
711 }
712 }
713
714 for (const std::unique_ptr<xml::Node>& child : el.children) {
715 if (const xml::Element* child_el = xml::NodeCast<xml::Element>(child.get())) {
716 SerializeXmlToPb(*child_el, pb_element->add_child());
717 } else if (const xml::Text* text_el = xml::NodeCast<xml::Text>(child.get())) {
718 if (options.remove_empty_text_nodes && util::TrimWhitespace(text_el->text).empty()) {
719 // Do not serialize whitespace text nodes if told not to
720 continue;
721 }
722
723 pb::XmlNode *pb_child_node = pb_element->add_child();
724 SerializeXmlCommon(*text_el, pb_child_node);
725 pb_child_node->set_text(text_el->text);
726 } else {
727 LOG(FATAL) << "unhandled XmlNode type";
728 }
729 }
730 }
731
SerializeXmlResourceToPb(const xml::XmlResource & resource,pb::XmlNode * out_node,const SerializeXmlOptions options)732 void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node,
733 const SerializeXmlOptions options) {
734 SerializeXmlToPb(*resource.root, out_node, options);
735 }
736
737 } // namespace aapt
738