diff options
| -rw-r--r-- | tools/aapt2/Android.bp | 5 | ||||
| -rw-r--r-- | tools/aapt2/cmd/Compile.cpp | 27 | ||||
| -rw-r--r-- | tools/aapt2/cmd/Dump.cpp | 142 | ||||
| -rw-r--r-- | tools/aapt2/cmd/Link.cpp | 23 | ||||
| -rw-r--r-- | tools/aapt2/proto/ProtoDeserialize.cpp | 918 | ||||
| -rw-r--r-- | tools/aapt2/proto/ProtoDeserialize.h | 78 | ||||
| -rw-r--r-- | tools/aapt2/proto/ProtoHelpers.cpp | 639 | ||||
| -rw-r--r-- | tools/aapt2/proto/ProtoHelpers.h | 58 | ||||
| -rw-r--r-- | tools/aapt2/proto/ProtoSerialize.cpp | 622 | ||||
| -rw-r--r-- | tools/aapt2/proto/ProtoSerialize.h | 78 | ||||
| -rw-r--r-- | tools/aapt2/proto/ProtoSerialize_test.cpp (renamed from tools/aapt2/proto/TableProtoSerializer_test.cpp) | 201 | ||||
| -rw-r--r-- | tools/aapt2/proto/TableProtoDeserializer.cpp | 420 | ||||
| -rw-r--r-- | tools/aapt2/proto/TableProtoSerializer.cpp | 389 |
13 files changed, 1913 insertions, 1687 deletions
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index f0ebf10ec527..7a8a4eea1aa6 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -106,9 +106,8 @@ cc_library_host_static { "optimize/ResourceDeduper.cpp", "optimize/VersionCollapser.cpp", "process/SymbolTable.cpp", - "proto/ProtoHelpers.cpp", - "proto/TableProtoDeserializer.cpp", - "proto/TableProtoSerializer.cpp", + "proto/ProtoDeserialize.cpp", + "proto/ProtoSerialize.cpp", "split/TableSplitter.cpp", "text/Unicode.cpp", "text/Utf8Iterator.cpp", diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index 7f5bbf042766..0690dc1b8ec6 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -248,8 +248,9 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options, // ZeroCopyOutputStream interface. CopyingOutputStreamAdaptor copying_adaptor(writer); - std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(&table); - if (!pb_table->SerializeToZeroCopyStream(©ing_adaptor)) { + pb::ResourceTable pb_table; + SerializeTableToPb(table, &pb_table); + if (!pb_table.SerializeToZeroCopyStream(©ing_adaptor)) { context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write"); return false; } @@ -282,9 +283,10 @@ static bool WriteHeaderAndBufferToWriter(const StringPiece& output_path, const R // Number of CompiledFiles. output_stream.WriteLittleEndian32(1); - std::unique_ptr<pb::internal::CompiledFile> compiled_file = SerializeCompiledFileToPb(file); - output_stream.WriteCompiledFile(compiled_file.get()); - output_stream.WriteData(&buffer); + pb::internal::CompiledFile pb_compiled_file; + SerializeCompiledFileToPb(file, &pb_compiled_file); + output_stream.WriteCompiledFile(pb_compiled_file); + output_stream.WriteData(buffer); if (output_stream.HadError()) { diag->Error(DiagMessage(output_path) << "failed to write data"); @@ -319,8 +321,9 @@ static bool WriteHeaderAndMmapToWriter(const StringPiece& output_path, const Res // Number of CompiledFiles. output_stream.WriteLittleEndian32(1); - std::unique_ptr<pb::internal::CompiledFile> compiled_file = SerializeCompiledFileToPb(file); - output_stream.WriteCompiledFile(compiled_file.get()); + pb::internal::CompiledFile pb_compiled_file; + SerializeCompiledFileToPb(file, &pb_compiled_file); + output_stream.WriteCompiledFile(pb_compiled_file); output_stream.WriteData(map.getDataPtr(), map.getDataLength()); if (output_stream.HadError()) { @@ -346,13 +349,13 @@ static bool FlattenXmlToOutStream(IAaptContext* context, const StringPiece& outp return false; } - std::unique_ptr<pb::internal::CompiledFile> pb_compiled_file = - SerializeCompiledFileToPb(xmlres->file); - out->WriteCompiledFile(pb_compiled_file.get()); - out->WriteData(&buffer); + pb::internal::CompiledFile pb_compiled_file; + SerializeCompiledFileToPb(xmlres->file, &pb_compiled_file); + out->WriteCompiledFile(pb_compiled_file); + out->WriteData(buffer); if (out->HadError()) { - context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write data"); + context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write XML data"); return false; } return true; diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp index 0965910ca853..0dedc91d2d2e 100644 --- a/tools/aapt2/cmd/Dump.cpp +++ b/tools/aapt2/cmd/Dump.cpp @@ -23,7 +23,7 @@ #include "Flags.h" #include "io/ZipArchive.h" #include "process/IResourceTableConsumer.h" -#include "proto/ProtoSerialize.h" +#include "proto/ProtoDeserialize.h" #include "unflatten/BinaryResourceParser.h" #include "util/Files.h" @@ -33,29 +33,28 @@ namespace aapt { bool DumpCompiledFile(const pb::internal::CompiledFile& pb_file, const void* data, size_t len, const Source& source, IAaptContext* context) { - std::unique_ptr<ResourceFile> file = - DeserializeCompiledFileFromPb(pb_file, source, context->GetDiagnostics()); - if (!file) { - context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file"); + ResourceFile file; + std::string error; + if (!DeserializeCompiledFileFromPb(pb_file, &file, &error)) { + context->GetDiagnostics()->Warn(DiagMessage(source) + << "failed to read compiled file: " << error); return false; } - std::cout << "Resource: " << file->name << "\n" - << "Config: " << file->config << "\n" - << "Source: " << file->source << "\n"; + std::cout << "Resource: " << file.name << "\n" + << "Config: " << file.config << "\n" + << "Source: " << file.source << "\n"; return true; } bool TryDumpFile(IAaptContext* context, const std::string& file_path) { - std::unique_ptr<ResourceTable> table; - std::string err; std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err); if (zip) { - io::IFile* file = zip->FindFile("resources.arsc.flat"); - if (file) { + ResourceTable table; + if (io::IFile* file = zip->FindFile("resources.arsc.flat")) { std::unique_ptr<io::IData> data = file->OpenAsData(); - if (!data) { + if (data == nullptr) { context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc.flat"); return false; @@ -67,83 +66,78 @@ bool TryDumpFile(IAaptContext* context, const std::string& file_path) { return false; } - table = DeserializeTableFromPb(pb_table, Source(file_path), context->GetDiagnostics()); - if (!table) { + ResourceTable table; + if (!DeserializeTableFromPb(pb_table, &table, &err)) { + context->GetDiagnostics()->Error(DiagMessage(file_path) + << "failed to parse table: " << err); + return false; + } + } else if (io::IFile* file = zip->FindFile("resources.arsc")) { + std::unique_ptr<io::IData> data = file->OpenAsData(); + if (!data) { + context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc"); return false; } - } - if (!table) { - file = zip->FindFile("resources.arsc"); - if (file) { - std::unique_ptr<io::IData> data = file->OpenAsData(); - if (!data) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to open resources.arsc"); - return false; - } - - table = util::make_unique<ResourceTable>(); - BinaryResourceParser parser(context, table.get(), Source(file_path), data->data(), - data->size()); - if (!parser.Parse()) { - return false; - } + BinaryResourceParser parser(context, &table, Source(file_path), data->data(), data->size()); + if (!parser.Parse()) { + return false; } } + + DebugPrintTableOptions options; + options.show_sources = true; + Debug::PrintTable(&table, options); + return true; } - if (!table) { - Maybe<android::FileMap> file = file::MmapPath(file_path, &err); - if (!file) { - context->GetDiagnostics()->Error(DiagMessage(file_path) << err); - return false; - } + err.clear(); - android::FileMap* file_map = &file.value(); + Maybe<android::FileMap> file = file::MmapPath(file_path, &err); + if (!file) { + context->GetDiagnostics()->Error(DiagMessage(file_path) << err); + return false; + } - // Try as a compiled table. - pb::ResourceTable pb_table; - if (pb_table.ParseFromArray(file_map->getDataPtr(), file_map->getDataLength())) { - table = DeserializeTableFromPb(pb_table, Source(file_path), context->GetDiagnostics()); + android::FileMap* file_map = &file.value(); + + // Check to see if this is a loose ResourceTable. + pb::ResourceTable pb_table; + if (pb_table.ParseFromArray(file_map->getDataPtr(), file_map->getDataLength())) { + ResourceTable table; + if (DeserializeTableFromPb(pb_table, &table, &err)) { + DebugPrintTableOptions options; + options.show_sources = true; + Debug::PrintTable(&table, options); + return true; } + } - if (!table) { - // Try as a compiled file. - CompiledFileInputStream input(file_map->getDataPtr(), file_map->getDataLength()); + // Try as a compiled file. + CompiledFileInputStream input(file_map->getDataPtr(), file_map->getDataLength()); + uint32_t num_files = 0; + if (!input.ReadLittleEndian32(&num_files)) { + return false; + } - uint32_t num_files = 0; - if (!input.ReadLittleEndian32(&num_files)) { - return false; - } + for (uint32_t i = 0; i < num_files; i++) { + pb::internal::CompiledFile compiled_file; + if (!input.ReadCompiledFile(&compiled_file)) { + context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file"); + return false; + } - for (uint32_t i = 0; i < num_files; i++) { - pb::internal::CompiledFile compiled_file; - if (!input.ReadCompiledFile(&compiled_file)) { - context->GetDiagnostics()->Warn(DiagMessage() << "failed to read compiled file"); - return false; - } - - uint64_t offset, len; - if (!input.ReadDataMetaData(&offset, &len)) { - context->GetDiagnostics()->Warn(DiagMessage() << "failed to read meta data"); - return false; - } - - const void* data = static_cast<const uint8_t*>(file_map->getDataPtr()) + offset; - if (!DumpCompiledFile(compiled_file, data, len, Source(file_path), context)) { - return false; - } - } + uint64_t offset, len; + if (!input.ReadDataMetaData(&offset, &len)) { + context->GetDiagnostics()->Warn(DiagMessage() << "failed to read meta data"); + return false; } - } - if (table) { - DebugPrintTableOptions options; - options.show_sources = true; - Debug::PrintTable(table.get(), options); + const void* data = static_cast<const uint8_t*>(file_map->getDataPtr()) + offset; + if (!DumpCompiledFile(compiled_file, data, len, Source(file_path), context)) { + return false; + } } - return true; } diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index e3ee206df8f9..f72069cc967a 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -58,6 +58,7 @@ #include "optimize/VersionCollapser.h" #include "process/IResourceTableConsumer.h" #include "process/SymbolTable.h" +#include "proto/ProtoDeserialize.h" #include "proto/ProtoSerialize.h" #include "split/TableSplitter.h" #include "unflatten/BinaryResourceParser.h" @@ -281,8 +282,10 @@ static std::unique_ptr<ResourceTable> LoadTableFromPb(const Source& source, cons return {}; } - std::unique_ptr<ResourceTable> table = DeserializeTableFromPb(pb_table, source, diag); - if (!table) { + std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); + std::string error; + if (!DeserializeTableFromPb(pb_table, table.get(), &error)) { + diag->Error(DiagMessage(source) << "invalid compiled table: " << error); return {}; } return table; @@ -917,8 +920,9 @@ class LinkCommand { } bool FlattenTableToPb(ResourceTable* table, IArchiveWriter* writer) { - std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(table); - return io::CopyProtoToArchive(context_, pb_table.get(), "resources.arsc.flat", 0, writer); + pb::ResourceTable pb_table; + SerializeTableToPb(*table, &pb_table); + return io::CopyProtoToArchive(context_, &pb_table, "resources.arsc.flat", 0, writer); } bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate, @@ -1397,14 +1401,15 @@ class LinkCommand { return false; } - std::unique_ptr<ResourceFile> resource_file = DeserializeCompiledFileFromPb( - compiled_file, file->GetSource(), context_->GetDiagnostics()); - if (!resource_file) { + ResourceFile resource_file; + std::string error; + if (!DeserializeCompiledFileFromPb(compiled_file, &resource_file, &error)) { + context_->GetDiagnostics()->Error(DiagMessage(src) + << "failed to read compiled header: " << error); return false; } - if (!MergeCompiledFile(file->CreateFileSegment(offset, len), resource_file.get(), - override)) { + if (!MergeCompiledFile(file->CreateFileSegment(offset, len), &resource_file, override)) { return false; } } diff --git a/tools/aapt2/proto/ProtoDeserialize.cpp b/tools/aapt2/proto/ProtoDeserialize.cpp new file mode 100644 index 000000000000..dc138818fcc5 --- /dev/null +++ b/tools/aapt2/proto/ProtoDeserialize.cpp @@ -0,0 +1,918 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "proto/ProtoDeserialize.h" + +#include "android-base/logging.h" +#include "android-base/macros.h" +#include "androidfw/ResourceTypes.h" + +#include "Locale.h" +#include "ResourceTable.h" +#include "ResourceUtils.h" +#include "ValueVisitor.h" + +using ::android::ResStringPool; +using ::google::protobuf::io::CodedInputStream; + +namespace aapt { + +namespace { + +class ReferenceIdToNameVisitor : public DescendingValueVisitor { + public: + using DescendingValueVisitor::Visit; + + explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping) + : mapping_(mapping) { + CHECK(mapping_ != nullptr); + } + + void Visit(Reference* reference) override { + if (!reference->id || !reference->id.value().is_valid()) { + return; + } + + ResourceId id = reference->id.value(); + auto cache_iter = mapping_->find(id); + if (cache_iter != mapping_->end()) { + reference->name = cache_iter->second.ToResourceName(); + } + } + + private: + DISALLOW_COPY_AND_ASSIGN(ReferenceIdToNameVisitor); + + const std::map<ResourceId, ResourceNameRef>* mapping_; +}; + +} // namespace + +bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config, + std::string* out_error) { + out_config->mcc = static_cast<uint16_t>(pb_config.mcc()); + out_config->mnc = static_cast<uint16_t>(pb_config.mnc()); + + if (!pb_config.locale().empty()) { + LocaleValue lv; + if (!lv.InitFromBcp47Tag(pb_config.locale())) { + std::ostringstream error; + error << "configuration has invalid locale '" << pb_config.locale() << "'"; + *out_error = error.str(); + return false; + } + lv.WriteTo(out_config); + } + + switch (pb_config.layout_direction()) { + case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) | + ConfigDescription::LAYOUTDIR_LTR; + break; + + case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) | + ConfigDescription::LAYOUTDIR_RTL; + break; + + default: + break; + } + + out_config->smallestScreenWidthDp = static_cast<uint16_t>(pb_config.smallest_screen_width_dp()); + out_config->screenWidthDp = static_cast<uint16_t>(pb_config.screen_width_dp()); + out_config->screenHeightDp = static_cast<uint16_t>(pb_config.screen_height_dp()); + + switch (pb_config.screen_layout_size()) { + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_SMALL; + break; + + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_NORMAL; + break; + + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_LARGE; + break; + + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_XLARGE; + break; + + default: + break; + } + + switch (pb_config.screen_layout_long()) { + case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) | + ConfigDescription::SCREENLONG_YES; + break; + + case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) | + ConfigDescription::SCREENLONG_NO; + break; + + default: + break; + } + + switch (pb_config.screen_round()) { + case pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND: + out_config->screenLayout2 = + (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) | + ConfigDescription::SCREENROUND_YES; + break; + + case pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND: + out_config->screenLayout2 = + (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) | + ConfigDescription::SCREENROUND_NO; + break; + + default: + break; + } + + switch (pb_config.wide_color_gamut()) { + case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG: + out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) | + ConfigDescription::WIDE_COLOR_GAMUT_YES; + break; + + case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG: + out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) | + ConfigDescription::WIDE_COLOR_GAMUT_NO; + break; + + default: + break; + } + + switch (pb_config.hdr()) { + case pb::Configuration_Hdr_HDR_HIGHDR: + out_config->colorMode = + (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_YES; + break; + + case pb::Configuration_Hdr_HDR_LOWDR: + out_config->colorMode = + (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_NO; + break; + + default: + break; + } + + switch (pb_config.orientation()) { + case pb::Configuration_Orientation_ORIENTATION_PORT: + out_config->orientation = ConfigDescription::ORIENTATION_PORT; + break; + + case pb::Configuration_Orientation_ORIENTATION_LAND: + out_config->orientation = ConfigDescription::ORIENTATION_LAND; + break; + + case pb::Configuration_Orientation_ORIENTATION_SQUARE: + out_config->orientation = ConfigDescription::ORIENTATION_SQUARE; + break; + + default: + break; + } + + switch (pb_config.ui_mode_type()) { + case pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_NORMAL; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_DESK: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_DESK; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_CAR: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_CAR; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_TELEVISION; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_APPLIANCE; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_WATCH; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_VR_HEADSET; + break; + + default: + break; + } + + switch (pb_config.ui_mode_night()) { + case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) | + ConfigDescription::UI_MODE_NIGHT_YES; + break; + + case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) | + ConfigDescription::UI_MODE_NIGHT_NO; + break; + + default: + break; + } + + out_config->density = static_cast<uint16_t>(pb_config.density()); + + switch (pb_config.touchscreen()) { + case pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH: + out_config->touchscreen = ConfigDescription::TOUCHSCREEN_NOTOUCH; + break; + + case pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS: + out_config->touchscreen = ConfigDescription::TOUCHSCREEN_STYLUS; + break; + + case pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER: + out_config->touchscreen = ConfigDescription::TOUCHSCREEN_FINGER; + break; + + default: + break; + } + + switch (pb_config.keys_hidden()) { + case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | + ConfigDescription::KEYSHIDDEN_NO; + break; + + case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | + ConfigDescription::KEYSHIDDEN_YES; + break; + + case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | + ConfigDescription::KEYSHIDDEN_SOFT; + break; + + default: + break; + } + + switch (pb_config.keyboard()) { + case pb::Configuration_Keyboard_KEYBOARD_NOKEYS: + out_config->keyboard = ConfigDescription::KEYBOARD_NOKEYS; + break; + + case pb::Configuration_Keyboard_KEYBOARD_QWERTY: + out_config->keyboard = ConfigDescription::KEYBOARD_QWERTY; + break; + + case pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY: + out_config->keyboard = ConfigDescription::KEYBOARD_12KEY; + break; + + default: + break; + } + + switch (pb_config.nav_hidden()) { + case pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) | + ConfigDescription::NAVHIDDEN_NO; + break; + + case pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) | + ConfigDescription::NAVHIDDEN_YES; + break; + + default: + break; + } + + switch (pb_config.navigation()) { + case pb::Configuration_Navigation_NAVIGATION_NONAV: + out_config->navigation = ConfigDescription::NAVIGATION_NONAV; + break; + + case pb::Configuration_Navigation_NAVIGATION_DPAD: + out_config->navigation = ConfigDescription::NAVIGATION_DPAD; + break; + + case pb::Configuration_Navigation_NAVIGATION_TRACKBALL: + out_config->navigation = ConfigDescription::NAVIGATION_TRACKBALL; + break; + + case pb::Configuration_Navigation_NAVIGATION_WHEEL: + out_config->navigation = ConfigDescription::NAVIGATION_WHEEL; + break; + + default: + break; + } + + out_config->screenWidth = static_cast<uint16_t>(pb_config.screen_width()); + out_config->screenHeight = static_cast<uint16_t>(pb_config.screen_height()); + out_config->sdkVersion = static_cast<uint16_t>(pb_config.sdk_version()); + return true; +} + +static void DeserializeSourceFromPb(const pb::Source& pb_source, const ResStringPool& src_pool, + Source* out_source) { + out_source->path = util::GetString(src_pool, pb_source.path_idx()); + out_source->line = static_cast<size_t>(pb_source.position().line_number()); +} + +static SymbolState DeserializeVisibilityFromPb(const pb::SymbolStatus_Visibility& pb_visibility) { + switch (pb_visibility) { + case pb::SymbolStatus_Visibility_PRIVATE: + return SymbolState::kPrivate; + case pb::SymbolStatus_Visibility_PUBLIC: + return SymbolState::kPublic; + default: + break; + } + return SymbolState::kUndefined; +} + +static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStringPool& src_pool, + ResourceTable* out_table, std::string* out_error) { + Maybe<uint8_t> id; + if (pb_package.has_package_id()) { + id = static_cast<uint8_t>(pb_package.package_id().id()); + } + + std::map<ResourceId, ResourceNameRef> id_index; + + ResourceTablePackage* pkg = out_table->CreatePackage(pb_package.package_name(), id); + for (const pb::Type& pb_type : pb_package.type()) { + const ResourceType* res_type = ParseResourceType(pb_type.name()); + if (res_type == nullptr) { + std::ostringstream error; + error << "unknown type '" << pb_type.name() << "'"; + *out_error = error.str(); + return false; + } + + ResourceTableType* type = pkg->FindOrCreateType(*res_type); + for (const pb::Entry& pb_entry : pb_type.entry()) { + ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name()); + + // Deserialize the symbol status (public/private with source and comments). + if (pb_entry.has_symbol_status()) { + const pb::SymbolStatus& pb_status = pb_entry.symbol_status(); + if (pb_status.has_source()) { + DeserializeSourceFromPb(pb_status.source(), src_pool, &entry->symbol_status.source); + } + + entry->symbol_status.comment = pb_status.comment(); + entry->symbol_status.allow_new = pb_status.allow_new(); + + const SymbolState visibility = DeserializeVisibilityFromPb(pb_status.visibility()); + entry->symbol_status.state = visibility; + + if (visibility == SymbolState::kPublic) { + // This is a public symbol, we must encode the ID now if there is one. + if (pb_entry.has_entry_id()) { + entry->id = static_cast<uint16_t>(pb_entry.entry_id().id()); + } + + if (type->symbol_status.state != SymbolState::kPublic) { + // If the type has not been made public, do so now. + type->symbol_status.state = SymbolState::kPublic; + if (pb_type.has_type_id()) { + type->id = static_cast<uint8_t>(pb_type.type_id().id()); + } + } + } else if (visibility == SymbolState::kPrivate) { + if (type->symbol_status.state == SymbolState::kUndefined) { + type->symbol_status.state = SymbolState::kPrivate; + } + } + } + + ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(), + pb_entry.entry_id().id()); + if (resid.is_valid()) { + id_index[resid] = ResourceNameRef(pkg->name, type->type, entry->name); + } + + for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) { + const pb::Configuration& pb_config = pb_config_value.config(); + + ConfigDescription config; + if (!DeserializeConfigFromPb(pb_config, &config, out_error)) { + return false; + } + + ResourceConfigValue* config_value = entry->FindOrCreateValue(config, pb_config.product()); + if (config_value->value != nullptr) { + *out_error = "duplicate configuration in resource table"; + return false; + } + + config_value->value = DeserializeValueFromPb(pb_config_value.value(), src_pool, config, + &out_table->string_pool, out_error); + if (config_value->value == nullptr) { + return false; + } + } + } + } + + ReferenceIdToNameVisitor visitor(&id_index); + VisitAllValuesInPackage(pkg, &visitor); + return true; +} + +bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* out_table, + std::string* out_error) { + // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which + // causes errors when qualifying it with android:: + using namespace android; + + ResStringPool source_pool; + if (pb_table.has_source_pool()) { + status_t result = source_pool.setTo(pb_table.source_pool().data().data(), + pb_table.source_pool().data().size()); + if (result != NO_ERROR) { + *out_error = "invalid source pool"; + return false; + } + } + + for (const pb::Package& pb_package : pb_table.package()) { + if (!DeserializePackageFromPb(pb_package, source_pool, out_table, out_error)) { + return false; + } + } + return true; +} + +bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file, + ResourceFile* out_file, std::string* out_error) { + ResourceNameRef name_ref; + if (!ResourceUtils::ParseResourceName(pb_file.resource_name(), &name_ref)) { + std::ostringstream error; + error << "invalid resource name in compiled file header: " << pb_file.resource_name(); + *out_error = error.str(); + return false; + } + + out_file->name = name_ref.ToResourceName(); + out_file->source.path = pb_file.source_path(); + + std::string config_error; + if (!DeserializeConfigFromPb(pb_file.config(), &out_file->config, &config_error)) { + std::ostringstream error; + error << "invalid resource configuration in compiled file header: " << config_error; + *out_error = error.str(); + return false; + } + + for (const pb::internal::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbol()) { + if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), &name_ref)) { + std::ostringstream error; + error << "invalid resource name for exported symbol in compiled file header: " + << pb_file.resource_name(); + *out_error = error.str(); + return false; + } + + size_t line = 0u; + if (pb_symbol.has_source()) { + line = pb_symbol.source().line_number(); + } + out_file->exported_symbols.push_back(SourcedResourceName{name_ref.ToResourceName(), line}); + } + return true; +} + +static Reference::Type DeserializeReferenceTypeFromPb(const pb::Reference_Type& pb_type) { + switch (pb_type) { + case pb::Reference_Type_REFERENCE: + return Reference::Type::kResource; + case pb::Reference_Type_ATTRIBUTE: + return Reference::Type::kAttribute; + default: + break; + } + return Reference::Type::kResource; +} + +static bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref, + std::string* out_error) { + out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type()); + out_ref->private_reference = pb_ref.private_(); + + if (pb_ref.id() != 0) { + out_ref->id = ResourceId(pb_ref.id()); + } + + if (!pb_ref.name().empty()) { + ResourceNameRef name_ref; + if (!ResourceUtils::ParseResourceName(pb_ref.name(), &name_ref, nullptr)) { + std::ostringstream error; + error << "reference has invalid resource name '" << pb_ref.name() << "'"; + *out_error = error.str(); + return false; + } + out_ref->name = name_ref.ToResourceName(); + } + return true; +} + +template <typename T> +static void DeserializeItemMetaDataFromPb(const T& pb_item, const android::ResStringPool& src_pool, + Value* out_value) { + if (pb_item.has_source()) { + Source source; + DeserializeSourceFromPb(pb_item.source(), src_pool, &source); + out_value->SetSource(std::move(source)); + } + out_value->SetComment(pb_item.comment()); +} + +static size_t DeserializePluralEnumFromPb(const pb::Plural_Arity& arity) { + switch (arity) { + case pb::Plural_Arity_ZERO: + return Plural::Zero; + case pb::Plural_Arity_ONE: + return Plural::One; + case pb::Plural_Arity_TWO: + return Plural::Two; + case pb::Plural_Arity_FEW: + return Plural::Few; + case pb::Plural_Arity_MANY: + return Plural::Many; + default: + break; + } + return Plural::Other; +} + +std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value, + const android::ResStringPool& src_pool, + const ConfigDescription& config, + StringPool* value_pool, std::string* out_error) { + std::unique_ptr<Value> value; + if (pb_value.has_item()) { + value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, out_error); + if (value == nullptr) { + return {}; + } + + } else if (pb_value.has_compound_value()) { + const pb::CompoundValue& pb_compound_value = pb_value.compound_value(); + switch (pb_compound_value.value_case()) { + case pb::CompoundValue::kAttr: { + const pb::Attribute& pb_attr = pb_compound_value.attr(); + std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(); + attr->type_mask = pb_attr.format_flags(); + attr->min_int = pb_attr.min_int(); + attr->max_int = pb_attr.max_int(); + for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbol()) { + Attribute::Symbol symbol; + DeserializeItemMetaDataFromPb(pb_symbol, src_pool, &symbol.symbol); + if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol, out_error)) { + return {}; + } + symbol.value = pb_symbol.value(); + attr->symbols.push_back(std::move(symbol)); + } + value = std::move(attr); + } break; + + case pb::CompoundValue::kStyle: { + const pb::Style& pb_style = pb_compound_value.style(); + std::unique_ptr<Style> style = util::make_unique<Style>(); + if (pb_style.has_parent()) { + style->parent = Reference(); + if (!DeserializeReferenceFromPb(pb_style.parent(), &style->parent.value(), out_error)) { + return {}; + } + + if (pb_style.has_parent_source()) { + Source parent_source; + DeserializeSourceFromPb(pb_style.parent_source(), src_pool, &parent_source); + style->parent.value().SetSource(std::move(parent_source)); + } + } + + for (const pb::Style_Entry& pb_entry : pb_style.entry()) { + Style::Entry entry; + if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key, out_error)) { + return {}; + } + DeserializeItemMetaDataFromPb(pb_entry, src_pool, &entry.key); + entry.value = + DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error); + if (entry.value == nullptr) { + return {}; + } + + // Copy the meta-data into the value as well. + DeserializeItemMetaDataFromPb(pb_entry, src_pool, entry.value.get()); + style->entries.push_back(std::move(entry)); + } + value = std::move(style); + } break; + + case pb::CompoundValue::kStyleable: { + const pb::Styleable& pb_styleable = pb_compound_value.styleable(); + std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); + for (const pb::Styleable_Entry& pb_entry : pb_styleable.entry()) { + Reference attr_ref; + DeserializeItemMetaDataFromPb(pb_entry, src_pool, &attr_ref); + DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref, out_error); + styleable->entries.push_back(std::move(attr_ref)); + } + value = std::move(styleable); + } break; + + case pb::CompoundValue::kArray: { + const pb::Array& pb_array = pb_compound_value.array(); + std::unique_ptr<Array> array = util::make_unique<Array>(); + for (const pb::Array_Element& pb_entry : pb_array.element()) { + std::unique_ptr<Item> item = + DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error); + if (item == nullptr) { + return {}; + } + + DeserializeItemMetaDataFromPb(pb_entry, src_pool, item.get()); + array->elements.push_back(std::move(item)); + } + value = std::move(array); + } break; + + case pb::CompoundValue::kPlural: { + const pb::Plural& pb_plural = pb_compound_value.plural(); + std::unique_ptr<Plural> plural = util::make_unique<Plural>(); + for (const pb::Plural_Entry& pb_entry : pb_plural.entry()) { + size_t plural_idx = DeserializePluralEnumFromPb(pb_entry.arity()); + plural->values[plural_idx] = + DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error); + if (!plural->values[plural_idx]) { + return {}; + } + + DeserializeItemMetaDataFromPb(pb_entry, src_pool, plural->values[plural_idx].get()); + } + value = std::move(plural); + } break; + + default: + LOG(FATAL) << "unknown compound value: " << (int) pb_compound_value.value_case(); + break; + } + } else { + LOG(FATAL) << "unknown value: " << (int) pb_value.value_case(); + return {}; + } + + CHECK(value) << "forgot to set value"; + + value->SetWeak(pb_value.weak()); + DeserializeItemMetaDataFromPb(pb_value, src_pool, value.get()); + return value; +} + +std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item, + const android::ResStringPool& src_pool, + const ConfigDescription& config, StringPool* value_pool, + std::string* out_error) { + switch (pb_item.value_case()) { + case pb::Item::kRef: { + const pb::Reference& pb_ref = pb_item.ref(); + std::unique_ptr<Reference> ref = util::make_unique<Reference>(); + if (!DeserializeReferenceFromPb(pb_ref, ref.get(), out_error)) { + return {}; + } + return std::move(ref); + } break; + + case pb::Item::kPrim: { + const pb::Primitive& pb_prim = pb_item.prim(); + return util::make_unique<BinaryPrimitive>(static_cast<uint8_t>(pb_prim.type()), + pb_prim.data()); + } break; + + case pb::Item::kId: { + return util::make_unique<Id>(); + } break; + + case pb::Item::kStr: { + return util::make_unique<String>( + value_pool->MakeRef(pb_item.str().value(), StringPool::Context(config))); + } break; + + case pb::Item::kRawStr: { + return util::make_unique<RawString>( + value_pool->MakeRef(pb_item.raw_str().value(), StringPool::Context(config))); + } break; + + case pb::Item::kStyledStr: { + const pb::StyledString& pb_str = pb_item.styled_str(); + StyleString style_str{pb_str.value()}; + for (const pb::StyledString::Span& pb_span : pb_str.span()) { + style_str.spans.push_back(Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()}); + } + return util::make_unique<StyledString>(value_pool->MakeRef( + style_str, StringPool::Context(StringPool::Context::kNormalPriority, config))); + } break; + + case pb::Item::kFile: { + return util::make_unique<FileReference>(value_pool->MakeRef( + pb_item.file().path(), StringPool::Context(StringPool::Context::kHighPriority, config))); + } break; + + default: + LOG(FATAL) << "unknown item: " << (int) pb_item.value_case(); + break; + } + return {}; +} + +std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node, + std::string* out_error) { + if (!pb_node.has_element()) { + return {}; + } + + std::unique_ptr<xml::XmlResource> resource = util::make_unique<xml::XmlResource>(); + resource->root = util::make_unique<xml::Element>(); + if (!DeserializeXmlFromPb(pb_node, resource->root.get(), &resource->string_pool, out_error)) { + return {}; + } + return resource; +} + +bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool, + std::string* out_error) { + const pb::XmlElement& pb_el = pb_node.element(); + out_el->name = pb_el.name(); + out_el->namespace_uri = pb_el.namespace_uri(); + out_el->line_number = pb_node.source().line_number(); + out_el->column_number = pb_node.source().column_number(); + + for (const pb::XmlNamespace& pb_ns : pb_el.namespace_declaration()) { + xml::NamespaceDecl decl; + decl.uri = pb_ns.uri(); + decl.prefix = pb_ns.prefix(); + decl.line_number = pb_ns.source().line_number(); + decl.column_number = pb_ns.source().column_number(); + out_el->namespace_decls.push_back(std::move(decl)); + } + + for (const pb::XmlAttribute& pb_attr : pb_el.attribute()) { + xml::Attribute attr; + attr.name = pb_attr.name(); + attr.namespace_uri = pb_attr.namespace_uri(); + attr.value = pb_attr.value(); + if (pb_attr.resource_id() != 0u) { + attr.compiled_attribute = xml::AaptAttribute{Attribute(), ResourceId(pb_attr.resource_id())}; + } + if (pb_attr.has_compiled_item()) { + attr.compiled_value = + DeserializeItemFromPb(pb_attr.compiled_item(), {}, {}, value_pool, out_error); + if (attr.compiled_value == nullptr) { + return {}; + } + attr.compiled_value->SetSource(Source().WithLine(pb_attr.source().line_number())); + } + out_el->attributes.push_back(std::move(attr)); + } + + // Deserialize the children. + for (const pb::XmlNode& pb_child : pb_el.child()) { + switch (pb_child.node_case()) { + case pb::XmlNode::NodeCase::kText: { + std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>(); + text->line_number = pb_child.source().line_number(); + text->column_number = pb_child.source().column_number(); + text->text = pb_child.text(); + out_el->AppendChild(std::move(text)); + } break; + + case pb::XmlNode::NodeCase::kElement: { + std::unique_ptr<xml::Element> child_el = util::make_unique<xml::Element>(); + if (!DeserializeXmlFromPb(pb_child, child_el.get(), value_pool, out_error)) { + return false; + } + out_el->AppendChild(std::move(child_el)); + } break; + + default: + LOG(FATAL) << "unknown XmlNode " << (int) pb_child.node_case(); + break; + } + } + return true; +} + +CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) + : in_(static_cast<const uint8_t*>(data), size) { +} + +void CompiledFileInputStream::EnsureAlignedRead() { + const int overflow = in_.CurrentPosition() % 4; + if (overflow > 0) { + // Reads are always 4 byte aligned. + in_.Skip(4 - overflow); + } +} + +bool CompiledFileInputStream::ReadLittleEndian32(uint32_t* out_val) { + EnsureAlignedRead(); + return in_.ReadLittleEndian32(out_val); +} + +bool CompiledFileInputStream::ReadCompiledFile(pb::internal::CompiledFile* out_val) { + EnsureAlignedRead(); + + google::protobuf::uint64 pb_size = 0u; + if (!in_.ReadLittleEndian64(&pb_size)) { + return false; + } + + CodedInputStream::Limit l = in_.PushLimit(static_cast<int>(pb_size)); + + // Check that we haven't tried to read past the end. + if (static_cast<uint64_t>(in_.BytesUntilLimit()) != pb_size) { + in_.PopLimit(l); + in_.PushLimit(0); + return false; + } + + if (!out_val->ParsePartialFromCodedStream(&in_)) { + in_.PopLimit(l); + in_.PushLimit(0); + return false; + } + + in_.PopLimit(l); + return true; +} + +bool CompiledFileInputStream::ReadDataMetaData(uint64_t* out_offset, uint64_t* out_len) { + EnsureAlignedRead(); + + google::protobuf::uint64 pb_size = 0u; + if (!in_.ReadLittleEndian64(&pb_size)) { + return false; + } + + // Check that we aren't trying to read past the end. + if (pb_size > static_cast<uint64_t>(in_.BytesUntilLimit())) { + in_.PushLimit(0); + return false; + } + + uint64_t offset = static_cast<uint64_t>(in_.CurrentPosition()); + if (!in_.Skip(pb_size)) { + return false; + } + + *out_offset = offset; + *out_len = pb_size; + return true; +} + +} // namespace aapt diff --git a/tools/aapt2/proto/ProtoDeserialize.h b/tools/aapt2/proto/ProtoDeserialize.h new file mode 100644 index 000000000000..3d76ea4ba0aa --- /dev/null +++ b/tools/aapt2/proto/ProtoDeserialize.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AAPT_PROTO_PROTODESERIALIZE_H +#define AAPT_PROTO_PROTODESERIALIZE_H + +#include "android-base/macros.h" +#include "androidfw/ResourceTypes.h" +#include "google/protobuf/io/coded_stream.h" + +#include "ConfigDescription.h" +#include "Configuration.pb.h" +#include "ResourceTable.h" +#include "ResourceValues.h" +#include "Resources.pb.h" +#include "ResourcesInternal.pb.h" +#include "StringPool.h" +#include "xml/XmlDom.h" + +namespace aapt { + +std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value, + const android::ResStringPool& src_pool, + const ConfigDescription& config, + StringPool* value_pool, std::string* out_error); + +std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item, + const android::ResStringPool& src_pool, + const ConfigDescription& config, StringPool* value_pool, + std::string* out_error); + +std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node, + std::string* out_error); + +bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool, + std::string* out_error); + +bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config, + std::string* out_error); + +bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* out_table, + std::string* out_error); + +bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file, + ResourceFile* out_file, std::string* out_error); + +class CompiledFileInputStream { + public: + explicit CompiledFileInputStream(const void* data, size_t size); + + bool ReadLittleEndian32(uint32_t* outVal); + bool ReadCompiledFile(pb::internal::CompiledFile* outVal); + bool ReadDataMetaData(uint64_t* outOffset, uint64_t* outLen); + + private: + DISALLOW_COPY_AND_ASSIGN(CompiledFileInputStream); + + void EnsureAlignedRead(); + + ::google::protobuf::io::CodedInputStream in_; +}; + +} // namespace aapt + +#endif /* AAPT_PROTO_PROTODESERIALIZE_H */ diff --git a/tools/aapt2/proto/ProtoHelpers.cpp b/tools/aapt2/proto/ProtoHelpers.cpp deleted file mode 100644 index 18f7e1d2ff7d..000000000000 --- a/tools/aapt2/proto/ProtoHelpers.cpp +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "proto/ProtoHelpers.h" - -#include "Locale.h" - -namespace aapt { - -void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool) { - BigBuffer buffer(1024); - StringPool::FlattenUtf8(&buffer, pool); - - std::string* data = out_pb_pool->mutable_data(); - data->reserve(buffer.size()); - - size_t offset = 0; - for (const BigBuffer::Block& block : buffer) { - data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size); - offset += block.size; - } -} - -void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source) { - StringPool::Ref ref = src_pool->MakeRef(source.path); - out_pb_source->set_path_idx(static_cast<uint32_t>(ref.index())); - if (source.line) { - out_pb_source->mutable_position()->set_line_number(static_cast<uint32_t>(source.line.value())); - } -} - -void DeserializeSourceFromPb(const pb::Source& pb_source, const android::ResStringPool& src_pool, - Source* out_source) { - out_source->path = util::GetString(src_pool, pb_source.path_idx()); - out_source->line = static_cast<size_t>(pb_source.position().line_number()); -} - -pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state) { - switch (state) { - case SymbolState::kPrivate: - return pb::SymbolStatus_Visibility_PRIVATE; - case SymbolState::kPublic: - return pb::SymbolStatus_Visibility_PUBLIC; - default: - break; - } - return pb::SymbolStatus_Visibility_UNKNOWN; -} - -SymbolState DeserializeVisibilityFromPb(pb::SymbolStatus_Visibility pb_visibility) { - switch (pb_visibility) { - case pb::SymbolStatus_Visibility_PRIVATE: - return SymbolState::kPrivate; - case pb::SymbolStatus_Visibility_PUBLIC: - return SymbolState::kPublic; - default: - break; - } - return SymbolState::kUndefined; -} - -void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config) { - out_pb_config->set_mcc(config.mcc); - out_pb_config->set_mnc(config.mnc); - out_pb_config->set_locale(config.GetBcp47LanguageTag()); - - switch (config.screenLayout & ConfigDescription::MASK_LAYOUTDIR) { - case ConfigDescription::LAYOUTDIR_LTR: - out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR); - break; - - case ConfigDescription::LAYOUTDIR_RTL: - out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL); - break; - } - - out_pb_config->set_screen_width(config.screenWidth); - out_pb_config->set_screen_height(config.screenHeight); - out_pb_config->set_screen_width_dp(config.screenWidthDp); - out_pb_config->set_screen_height_dp(config.screenHeightDp); - out_pb_config->set_smallest_screen_width_dp(config.smallestScreenWidthDp); - - switch (config.screenLayout & ConfigDescription::MASK_SCREENSIZE) { - case ConfigDescription::SCREENSIZE_SMALL: - out_pb_config->set_screen_layout_size( - pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL); - break; - - case ConfigDescription::SCREENSIZE_NORMAL: - out_pb_config->set_screen_layout_size( - pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL); - break; - - case ConfigDescription::SCREENSIZE_LARGE: - out_pb_config->set_screen_layout_size( - pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE); - break; - - case ConfigDescription::SCREENSIZE_XLARGE: - out_pb_config->set_screen_layout_size( - pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE); - break; - } - - switch (config.screenLayout & ConfigDescription::MASK_SCREENLONG) { - case ConfigDescription::SCREENLONG_YES: - out_pb_config->set_screen_layout_long( - pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG); - break; - - case ConfigDescription::SCREENLONG_NO: - out_pb_config->set_screen_layout_long( - pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG); - break; - } - - switch (config.screenLayout2 & ConfigDescription::MASK_SCREENROUND) { - case ConfigDescription::SCREENROUND_YES: - out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND); - break; - - case ConfigDescription::SCREENROUND_NO: - out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND); - break; - } - - switch (config.colorMode & ConfigDescription::MASK_WIDE_COLOR_GAMUT) { - case ConfigDescription::WIDE_COLOR_GAMUT_YES: - out_pb_config->set_wide_color_gamut(pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG); - break; - - case ConfigDescription::WIDE_COLOR_GAMUT_NO: - out_pb_config->set_wide_color_gamut( - pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG); - break; - } - - switch (config.colorMode & ConfigDescription::MASK_HDR) { - case ConfigDescription::HDR_YES: - out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_HIGHDR); - break; - - case ConfigDescription::HDR_NO: - out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_LOWDR); - break; - } - - switch (config.orientation) { - case ConfigDescription::ORIENTATION_PORT: - out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_PORT); - break; - - case ConfigDescription::ORIENTATION_LAND: - out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_LAND); - break; - - case ConfigDescription::ORIENTATION_SQUARE: - out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_SQUARE); - break; - } - - switch (config.uiMode & ConfigDescription::MASK_UI_MODE_TYPE) { - case ConfigDescription::UI_MODE_TYPE_NORMAL: - out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL); - break; - - case ConfigDescription::UI_MODE_TYPE_DESK: - out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_DESK); - break; - - case ConfigDescription::UI_MODE_TYPE_CAR: - out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_CAR); - break; - - case ConfigDescription::UI_MODE_TYPE_TELEVISION: - out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION); - break; - - case ConfigDescription::UI_MODE_TYPE_APPLIANCE: - out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE); - break; - - case ConfigDescription::UI_MODE_TYPE_WATCH: - out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH); - break; - - case ConfigDescription::UI_MODE_TYPE_VR_HEADSET: - out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET); - break; - } - - switch (config.uiMode & ConfigDescription::MASK_UI_MODE_NIGHT) { - case ConfigDescription::UI_MODE_NIGHT_YES: - out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT); - break; - - case ConfigDescription::UI_MODE_NIGHT_NO: - out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT); - break; - } - - out_pb_config->set_density(config.density); - - switch (config.touchscreen) { - case ConfigDescription::TOUCHSCREEN_NOTOUCH: - out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH); - break; - - case ConfigDescription::TOUCHSCREEN_STYLUS: - out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS); - break; - - case ConfigDescription::TOUCHSCREEN_FINGER: - out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER); - break; - } - - switch (config.inputFlags & ConfigDescription::MASK_KEYSHIDDEN) { - case ConfigDescription::KEYSHIDDEN_NO: - out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED); - break; - - case ConfigDescription::KEYSHIDDEN_YES: - out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN); - break; - - case ConfigDescription::KEYSHIDDEN_SOFT: - out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT); - break; - } - - switch (config.keyboard) { - case ConfigDescription::KEYBOARD_NOKEYS: - out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_NOKEYS); - break; - - case ConfigDescription::KEYBOARD_QWERTY: - out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_QWERTY); - break; - - case ConfigDescription::KEYBOARD_12KEY: - out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY); - break; - } - - switch (config.inputFlags & ConfigDescription::MASK_NAVHIDDEN) { - case ConfigDescription::NAVHIDDEN_NO: - out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED); - break; - - case ConfigDescription::NAVHIDDEN_YES: - out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN); - break; - } - - switch (config.navigation) { - case ConfigDescription::NAVIGATION_NONAV: - out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_NONAV); - break; - - case ConfigDescription::NAVIGATION_DPAD: - out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_DPAD); - break; - - case ConfigDescription::NAVIGATION_TRACKBALL: - out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_TRACKBALL); - break; - - case ConfigDescription::NAVIGATION_WHEEL: - out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_WHEEL); - break; - } - - out_pb_config->set_sdk_version(config.sdkVersion); -} - -bool DeserializeConfigDescriptionFromPb(const pb::Configuration& pb_config, - ConfigDescription* out_config) { - out_config->mcc = static_cast<uint16_t>(pb_config.mcc()); - out_config->mnc = static_cast<uint16_t>(pb_config.mnc()); - - if (!pb_config.locale().empty()) { - LocaleValue lv; - if (!lv.InitFromBcp47Tag(pb_config.locale())) { - return false; - } - lv.WriteTo(out_config); - } - - switch (pb_config.layout_direction()) { - case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR: - out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) | - ConfigDescription::LAYOUTDIR_LTR; - break; - - case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL: - out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) | - ConfigDescription::LAYOUTDIR_RTL; - break; - - default: - break; - } - - out_config->smallestScreenWidthDp = static_cast<uint16_t>(pb_config.smallest_screen_width_dp()); - out_config->screenWidthDp = static_cast<uint16_t>(pb_config.screen_width_dp()); - out_config->screenHeightDp = static_cast<uint16_t>(pb_config.screen_height_dp()); - - switch (pb_config.screen_layout_size()) { - case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL: - out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | - ConfigDescription::SCREENSIZE_SMALL; - break; - - case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL: - out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | - ConfigDescription::SCREENSIZE_NORMAL; - break; - - case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE: - out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | - ConfigDescription::SCREENSIZE_LARGE; - break; - - case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE: - out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | - ConfigDescription::SCREENSIZE_XLARGE; - break; - - default: - break; - } - - switch (pb_config.screen_layout_long()) { - case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG: - out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) | - ConfigDescription::SCREENLONG_YES; - break; - - case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG: - out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) | - ConfigDescription::SCREENLONG_NO; - break; - - default: - break; - } - - switch (pb_config.screen_round()) { - case pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND: - out_config->screenLayout2 = - (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) | - ConfigDescription::SCREENROUND_YES; - break; - - case pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND: - out_config->screenLayout2 = - (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) | - ConfigDescription::SCREENROUND_NO; - break; - - default: - break; - } - - switch (pb_config.wide_color_gamut()) { - case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG: - out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) | - ConfigDescription::WIDE_COLOR_GAMUT_YES; - break; - - case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG: - out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) | - ConfigDescription::WIDE_COLOR_GAMUT_NO; - break; - - default: - break; - } - - switch (pb_config.hdr()) { - case pb::Configuration_Hdr_HDR_HIGHDR: - out_config->colorMode = - (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_YES; - break; - - case pb::Configuration_Hdr_HDR_LOWDR: - out_config->colorMode = - (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_NO; - break; - - default: - break; - } - - switch (pb_config.orientation()) { - case pb::Configuration_Orientation_ORIENTATION_PORT: - out_config->orientation = ConfigDescription::ORIENTATION_PORT; - break; - - case pb::Configuration_Orientation_ORIENTATION_LAND: - out_config->orientation = ConfigDescription::ORIENTATION_LAND; - break; - - case pb::Configuration_Orientation_ORIENTATION_SQUARE: - out_config->orientation = ConfigDescription::ORIENTATION_SQUARE; - break; - - default: - break; - } - - switch (pb_config.ui_mode_type()) { - case pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL: - out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | - ConfigDescription::UI_MODE_TYPE_NORMAL; - break; - - case pb::Configuration_UiModeType_UI_MODE_TYPE_DESK: - out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | - ConfigDescription::UI_MODE_TYPE_DESK; - break; - - case pb::Configuration_UiModeType_UI_MODE_TYPE_CAR: - out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | - ConfigDescription::UI_MODE_TYPE_CAR; - break; - - case pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION: - out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | - ConfigDescription::UI_MODE_TYPE_TELEVISION; - break; - - case pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE: - out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | - ConfigDescription::UI_MODE_TYPE_APPLIANCE; - break; - - case pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH: - out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | - ConfigDescription::UI_MODE_TYPE_WATCH; - break; - - case pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET: - out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | - ConfigDescription::UI_MODE_TYPE_VR_HEADSET; - break; - - default: - break; - } - - switch (pb_config.ui_mode_night()) { - case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT: - out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) | - ConfigDescription::UI_MODE_NIGHT_YES; - break; - - case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT: - out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) | - ConfigDescription::UI_MODE_NIGHT_NO; - break; - - default: - break; - } - - out_config->density = static_cast<uint16_t>(pb_config.density()); - - switch (pb_config.touchscreen()) { - case pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH: - out_config->touchscreen = ConfigDescription::TOUCHSCREEN_NOTOUCH; - break; - - case pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS: - out_config->touchscreen = ConfigDescription::TOUCHSCREEN_STYLUS; - break; - - case pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER: - out_config->touchscreen = ConfigDescription::TOUCHSCREEN_FINGER; - break; - - default: - break; - } - - switch (pb_config.keys_hidden()) { - case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED: - out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | - ConfigDescription::KEYSHIDDEN_NO; - break; - - case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN: - out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | - ConfigDescription::KEYSHIDDEN_YES; - break; - - case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT: - out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | - ConfigDescription::KEYSHIDDEN_SOFT; - break; - - default: - break; - } - - switch (pb_config.keyboard()) { - case pb::Configuration_Keyboard_KEYBOARD_NOKEYS: - out_config->keyboard = ConfigDescription::KEYBOARD_NOKEYS; - break; - - case pb::Configuration_Keyboard_KEYBOARD_QWERTY: - out_config->keyboard = ConfigDescription::KEYBOARD_QWERTY; - break; - - case pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY: - out_config->keyboard = ConfigDescription::KEYBOARD_12KEY; - break; - - default: - break; - } - - switch (pb_config.nav_hidden()) { - case pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED: - out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) | - ConfigDescription::NAVHIDDEN_NO; - break; - - case pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN: - out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) | - ConfigDescription::NAVHIDDEN_YES; - break; - - default: - break; - } - - switch (pb_config.navigation()) { - case pb::Configuration_Navigation_NAVIGATION_NONAV: - out_config->navigation = ConfigDescription::NAVIGATION_NONAV; - break; - - case pb::Configuration_Navigation_NAVIGATION_DPAD: - out_config->navigation = ConfigDescription::NAVIGATION_DPAD; - break; - - case pb::Configuration_Navigation_NAVIGATION_TRACKBALL: - out_config->navigation = ConfigDescription::NAVIGATION_TRACKBALL; - break; - - case pb::Configuration_Navigation_NAVIGATION_WHEEL: - out_config->navigation = ConfigDescription::NAVIGATION_WHEEL; - break; - - default: - break; - } - - out_config->screenWidth = static_cast<uint16_t>(pb_config.screen_width()); - out_config->screenHeight = static_cast<uint16_t>(pb_config.screen_height()); - out_config->sdkVersion = static_cast<uint16_t>(pb_config.sdk_version()); - return true; -} - -pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) { - switch (type) { - case Reference::Type::kResource: - return pb::Reference_Type_REFERENCE; - case Reference::Type::kAttribute: - return pb::Reference_Type_ATTRIBUTE; - default: - break; - } - return pb::Reference_Type_REFERENCE; -} - -Reference::Type DeserializeReferenceTypeFromPb(pb::Reference_Type pb_type) { - switch (pb_type) { - case pb::Reference_Type_REFERENCE: - return Reference::Type::kResource; - case pb::Reference_Type_ATTRIBUTE: - return Reference::Type::kAttribute; - default: - break; - } - return Reference::Type::kResource; -} - -pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx) { - switch (plural_idx) { - case Plural::Zero: - return pb::Plural_Arity_ZERO; - case Plural::One: - return pb::Plural_Arity_ONE; - case Plural::Two: - return pb::Plural_Arity_TWO; - case Plural::Few: - return pb::Plural_Arity_FEW; - case Plural::Many: - return pb::Plural_Arity_MANY; - default: - break; - } - return pb::Plural_Arity_OTHER; -} - -size_t DeserializePluralEnumFromPb(pb::Plural_Arity arity) { - switch (arity) { - case pb::Plural_Arity_ZERO: - return Plural::Zero; - case pb::Plural_Arity_ONE: - return Plural::One; - case pb::Plural_Arity_TWO: - return Plural::Two; - case pb::Plural_Arity_FEW: - return Plural::Few; - case pb::Plural_Arity_MANY: - return Plural::Many; - default: - break; - } - return Plural::Other; -} - -} // namespace aapt diff --git a/tools/aapt2/proto/ProtoHelpers.h b/tools/aapt2/proto/ProtoHelpers.h deleted file mode 100644 index 714a2b27bf7f..000000000000 --- a/tools/aapt2/proto/ProtoHelpers.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AAPT_PROTO_PROTOHELPERS_H -#define AAPT_PROTO_PROTOHELPERS_H - -#include "androidfw/ResourceTypes.h" - -#include "ConfigDescription.h" -#include "Configuration.pb.h" -#include "ResourceTable.h" -#include "Resources.pb.h" -#include "ResourcesInternal.pb.h" -#include "Source.h" -#include "StringPool.h" - -namespace aapt { - -void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool); - -void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source); - -void DeserializeSourceFromPb(const pb::Source& pb_source, const android::ResStringPool& src_pool, - Source* out_source); - -pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state); - -SymbolState DeserializeVisibilityFromPb(pb::SymbolStatus_Visibility pb_visibility); - -void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config); - -bool DeserializeConfigDescriptionFromPb(const pb::Configuration& pb_config, - ConfigDescription* out_config); - -pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type); - -Reference::Type DeserializeReferenceTypeFromPb(pb::Reference_Type pb_type); - -pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx); - -size_t DeserializePluralEnumFromPb(pb::Plural_Arity arity); - -} // namespace aapt - -#endif /* AAPT_PROTO_PROTOHELPERS_H */ diff --git a/tools/aapt2/proto/ProtoSerialize.cpp b/tools/aapt2/proto/ProtoSerialize.cpp new file mode 100644 index 000000000000..d36d6680a7df --- /dev/null +++ b/tools/aapt2/proto/ProtoSerialize.cpp @@ -0,0 +1,622 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "proto/ProtoSerialize.h" + +#include "google/protobuf/io/zero_copy_stream_impl_lite.h" + +#include "ValueVisitor.h" +#include "util/BigBuffer.h" + +using ::google::protobuf::io::CodedOutputStream; +using ::google::protobuf::io::ZeroCopyOutputStream; + +namespace aapt { + +void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool) { + BigBuffer buffer(1024); + StringPool::FlattenUtf8(&buffer, pool); + + std::string* data = out_pb_pool->mutable_data(); + data->reserve(buffer.size()); + + size_t offset = 0; + for (const BigBuffer::Block& block : buffer) { + data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size); + offset += block.size; + } +} + +void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source) { + StringPool::Ref ref = src_pool->MakeRef(source.path); + out_pb_source->set_path_idx(static_cast<uint32_t>(ref.index())); + if (source.line) { + out_pb_source->mutable_position()->set_line_number(static_cast<uint32_t>(source.line.value())); + } +} + +static pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state) { + switch (state) { + case SymbolState::kPrivate: + return pb::SymbolStatus_Visibility_PRIVATE; + case SymbolState::kPublic: + return pb::SymbolStatus_Visibility_PUBLIC; + default: + break; + } + return pb::SymbolStatus_Visibility_UNKNOWN; +} + +void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config) { + out_pb_config->set_mcc(config.mcc); + out_pb_config->set_mnc(config.mnc); + out_pb_config->set_locale(config.GetBcp47LanguageTag()); + + switch (config.screenLayout & ConfigDescription::MASK_LAYOUTDIR) { + case ConfigDescription::LAYOUTDIR_LTR: + out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR); + break; + + case ConfigDescription::LAYOUTDIR_RTL: + out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL); + break; + } + + out_pb_config->set_screen_width(config.screenWidth); + out_pb_config->set_screen_height(config.screenHeight); + out_pb_config->set_screen_width_dp(config.screenWidthDp); + out_pb_config->set_screen_height_dp(config.screenHeightDp); + out_pb_config->set_smallest_screen_width_dp(config.smallestScreenWidthDp); + + switch (config.screenLayout & ConfigDescription::MASK_SCREENSIZE) { + case ConfigDescription::SCREENSIZE_SMALL: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL); + break; + + case ConfigDescription::SCREENSIZE_NORMAL: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL); + break; + + case ConfigDescription::SCREENSIZE_LARGE: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE); + break; + + case ConfigDescription::SCREENSIZE_XLARGE: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE); + break; + } + + switch (config.screenLayout & ConfigDescription::MASK_SCREENLONG) { + case ConfigDescription::SCREENLONG_YES: + out_pb_config->set_screen_layout_long( + pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG); + break; + + case ConfigDescription::SCREENLONG_NO: + out_pb_config->set_screen_layout_long( + pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG); + break; + } + + switch (config.screenLayout2 & ConfigDescription::MASK_SCREENROUND) { + case ConfigDescription::SCREENROUND_YES: + out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND); + break; + + case ConfigDescription::SCREENROUND_NO: + out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND); + break; + } + + switch (config.colorMode & ConfigDescription::MASK_WIDE_COLOR_GAMUT) { + case ConfigDescription::WIDE_COLOR_GAMUT_YES: + out_pb_config->set_wide_color_gamut(pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG); + break; + + case ConfigDescription::WIDE_COLOR_GAMUT_NO: + out_pb_config->set_wide_color_gamut( + pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG); + break; + } + + switch (config.colorMode & ConfigDescription::MASK_HDR) { + case ConfigDescription::HDR_YES: + out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_HIGHDR); + break; + + case ConfigDescription::HDR_NO: + out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_LOWDR); + break; + } + + switch (config.orientation) { + case ConfigDescription::ORIENTATION_PORT: + out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_PORT); + break; + + case ConfigDescription::ORIENTATION_LAND: + out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_LAND); + break; + + case ConfigDescription::ORIENTATION_SQUARE: + out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_SQUARE); + break; + } + + switch (config.uiMode & ConfigDescription::MASK_UI_MODE_TYPE) { + case ConfigDescription::UI_MODE_TYPE_NORMAL: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL); + break; + + case ConfigDescription::UI_MODE_TYPE_DESK: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_DESK); + break; + + case ConfigDescription::UI_MODE_TYPE_CAR: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_CAR); + break; + + case ConfigDescription::UI_MODE_TYPE_TELEVISION: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION); + break; + + case ConfigDescription::UI_MODE_TYPE_APPLIANCE: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE); + break; + + case ConfigDescription::UI_MODE_TYPE_WATCH: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH); + break; + + case ConfigDescription::UI_MODE_TYPE_VR_HEADSET: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET); + break; + } + + switch (config.uiMode & ConfigDescription::MASK_UI_MODE_NIGHT) { + case ConfigDescription::UI_MODE_NIGHT_YES: + out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT); + break; + + case ConfigDescription::UI_MODE_NIGHT_NO: + out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT); + break; + } + + out_pb_config->set_density(config.density); + + switch (config.touchscreen) { + case ConfigDescription::TOUCHSCREEN_NOTOUCH: + out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH); + break; + + case ConfigDescription::TOUCHSCREEN_STYLUS: + out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS); + break; + + case ConfigDescription::TOUCHSCREEN_FINGER: + out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER); + break; + } + + switch (config.inputFlags & ConfigDescription::MASK_KEYSHIDDEN) { + case ConfigDescription::KEYSHIDDEN_NO: + out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED); + break; + + case ConfigDescription::KEYSHIDDEN_YES: + out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN); + break; + + case ConfigDescription::KEYSHIDDEN_SOFT: + out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT); + break; + } + + switch (config.keyboard) { + case ConfigDescription::KEYBOARD_NOKEYS: + out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_NOKEYS); + break; + + case ConfigDescription::KEYBOARD_QWERTY: + out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_QWERTY); + break; + + case ConfigDescription::KEYBOARD_12KEY: + out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY); + break; + } + + switch (config.inputFlags & ConfigDescription::MASK_NAVHIDDEN) { + case ConfigDescription::NAVHIDDEN_NO: + out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED); + break; + + case ConfigDescription::NAVHIDDEN_YES: + out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN); + break; + } + + switch (config.navigation) { + case ConfigDescription::NAVIGATION_NONAV: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_NONAV); + break; + + case ConfigDescription::NAVIGATION_DPAD: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_DPAD); + break; + + case ConfigDescription::NAVIGATION_TRACKBALL: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_TRACKBALL); + break; + + case ConfigDescription::NAVIGATION_WHEEL: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_WHEEL); + break; + } + + out_pb_config->set_sdk_version(config.sdkVersion); +} + +void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table) { + StringPool source_pool; + for (const std::unique_ptr<ResourceTablePackage>& package : table.packages) { + pb::Package* pb_package = out_table->add_package(); + if (package->id) { + pb_package->mutable_package_id()->set_id(package->id.value()); + } + pb_package->set_package_name(package->name); + + for (const std::unique_ptr<ResourceTableType>& type : package->types) { + pb::Type* pb_type = pb_package->add_type(); + if (type->id) { + pb_type->mutable_type_id()->set_id(type->id.value()); + } + pb_type->set_name(ToString(type->type).to_string()); + + for (const std::unique_ptr<ResourceEntry>& entry : type->entries) { + pb::Entry* pb_entry = pb_type->add_entry(); + if (entry->id) { + pb_entry->mutable_entry_id()->set_id(entry->id.value()); + } + pb_entry->set_name(entry->name); + + // Write the SymbolStatus struct. + pb::SymbolStatus* pb_status = pb_entry->mutable_symbol_status(); + pb_status->set_visibility(SerializeVisibilityToPb(entry->symbol_status.state)); + SerializeSourceToPb(entry->symbol_status.source, &source_pool, pb_status->mutable_source()); + pb_status->set_comment(entry->symbol_status.comment); + pb_status->set_allow_new(entry->symbol_status.allow_new); + + for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) { + pb::ConfigValue* pb_config_value = pb_entry->add_config_value(); + SerializeConfig(config_value->config, pb_config_value->mutable_config()); + pb_config_value->mutable_config()->set_product(config_value->product); + SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(), &source_pool); + } + } + } + } + SerializeStringPoolToPb(source_pool, out_table->mutable_source_pool()); +} + +static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) { + switch (type) { + case Reference::Type::kResource: + return pb::Reference_Type_REFERENCE; + case Reference::Type::kAttribute: + return pb::Reference_Type_ATTRIBUTE; + default: + break; + } + return pb::Reference_Type_REFERENCE; +} + +static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) { + pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id); + + if (ref.name) { + pb_ref->set_name(ref.name.value().ToString()); + } + + pb_ref->set_private_(ref.private_reference); + pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type)); +} + +template <typename T> +static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, StringPool* src_pool) { + if (src_pool != nullptr) { + SerializeSourceToPb(item.GetSource(), src_pool, pb_item->mutable_source()); + } + pb_item->set_comment(item.GetComment()); +} + +static pb::Plural_Arity SerializePluralEnumToPb(size_t plural_idx) { + switch (plural_idx) { + case Plural::Zero: + return pb::Plural_Arity_ZERO; + case Plural::One: + return pb::Plural_Arity_ONE; + case Plural::Two: + return pb::Plural_Arity_TWO; + case Plural::Few: + return pb::Plural_Arity_FEW; + case Plural::Many: + return pb::Plural_Arity_MANY; + default: + break; + } + return pb::Plural_Arity_OTHER; +} + +namespace { + +class ValueSerializer : public ConstValueVisitor { + public: + using ConstValueVisitor::Visit; + + ValueSerializer(pb::Value* out_value, StringPool* src_pool) + : out_value_(out_value), src_pool_(src_pool) { + } + + void Visit(const Reference* ref) override { + SerializeReferenceToPb(*ref, out_value_->mutable_item()->mutable_ref()); + } + + void Visit(const String* str) override { + out_value_->mutable_item()->mutable_str()->set_value(*str->value); + } + + void Visit(const RawString* str) override { + out_value_->mutable_item()->mutable_raw_str()->set_value(*str->value); + } + + void Visit(const StyledString* str) override { + pb::StyledString* pb_str = out_value_->mutable_item()->mutable_styled_str(); + pb_str->set_value(str->value->value); + for (const StringPool::Span& span : str->value->spans) { + pb::StyledString::Span* pb_span = pb_str->add_span(); + pb_span->set_tag(*span.name); + pb_span->set_first_char(span.first_char); + pb_span->set_last_char(span.last_char); + } + } + + void Visit(const FileReference* file) override { + out_value_->mutable_item()->mutable_file()->set_path(*file->path); + } + + void Visit(const Id* /*id*/) override { + out_value_->mutable_item()->mutable_id(); + } + + void Visit(const BinaryPrimitive* prim) override { + android::Res_value val = {}; + prim->Flatten(&val); + + pb::Primitive* pb_prim = out_value_->mutable_item()->mutable_prim(); + pb_prim->set_type(val.dataType); + pb_prim->set_data(val.data); + } + + void Visit(const Attribute* attr) override { + pb::Attribute* pb_attr = out_value_->mutable_compound_value()->mutable_attr(); + pb_attr->set_format_flags(attr->type_mask); + pb_attr->set_min_int(attr->min_int); + pb_attr->set_max_int(attr->max_int); + + for (auto& symbol : attr->symbols) { + pb::Attribute_Symbol* pb_symbol = pb_attr->add_symbol(); + SerializeItemMetaDataToPb(symbol.symbol, pb_symbol, src_pool_); + SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name()); + pb_symbol->set_value(symbol.value); + } + } + + void Visit(const Style* style) override { + pb::Style* pb_style = out_value_->mutable_compound_value()->mutable_style(); + if (style->parent) { + const Reference& parent = style->parent.value(); + SerializeReferenceToPb(parent, pb_style->mutable_parent()); + if (src_pool_ != nullptr) { + SerializeSourceToPb(parent.GetSource(), src_pool_, pb_style->mutable_parent_source()); + } + } + + for (const Style::Entry& entry : style->entries) { + pb::Style_Entry* pb_entry = pb_style->add_entry(); + SerializeReferenceToPb(entry.key, pb_entry->mutable_key()); + SerializeItemMetaDataToPb(entry.key, pb_entry, src_pool_); + SerializeItemToPb(*entry.value, pb_entry->mutable_item()); + } + } + + void Visit(const Styleable* styleable) override { + pb::Styleable* pb_styleable = out_value_->mutable_compound_value()->mutable_styleable(); + for (const Reference& entry : styleable->entries) { + pb::Styleable_Entry* pb_entry = pb_styleable->add_entry(); + SerializeItemMetaDataToPb(entry, pb_entry, src_pool_); + SerializeReferenceToPb(entry, pb_entry->mutable_attr()); + } + } + + void Visit(const Array* array) override { + pb::Array* pb_array = out_value_->mutable_compound_value()->mutable_array(); + for (const std::unique_ptr<Item>& element : array->elements) { + pb::Array_Element* pb_element = pb_array->add_element(); + SerializeItemMetaDataToPb(*element, pb_element, src_pool_); + SerializeItemToPb(*element, pb_element->mutable_item()); + } + } + + void Visit(const Plural* plural) override { + pb::Plural* pb_plural = out_value_->mutable_compound_value()->mutable_plural(); + const size_t count = plural->values.size(); + for (size_t i = 0; i < count; i++) { + if (!plural->values[i]) { + // No plural value set here. + continue; + } + + pb::Plural_Entry* pb_entry = pb_plural->add_entry(); + pb_entry->set_arity(SerializePluralEnumToPb(i)); + SerializeItemMetaDataToPb(*plural->values[i], pb_entry, src_pool_); + SerializeItemToPb(*plural->values[i], pb_entry->mutable_item()); + } + } + + void VisitAny(const Value* unknown) override { + LOG(FATAL) << "unimplemented value: " << *unknown; + } + + private: + pb::Value* out_value_; + StringPool* src_pool_; +}; + +} // namespace + +void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool) { + ValueSerializer serializer(out_value, src_pool); + value.Accept(&serializer); + + // Serialize the meta-data of the Value. + out_value->set_comment(value.GetComment()); + out_value->set_weak(value.IsWeak()); + if (src_pool != nullptr) { + SerializeSourceToPb(value.GetSource(), src_pool, out_value->mutable_source()); + } +} + +void SerializeItemToPb(const Item& item, pb::Item* out_item) { + pb::Value value; + ValueSerializer serializer(&value, nullptr); + item.Accept(&serializer); + out_item->MergeFrom(value.item()); +} + +void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) { + out_file->set_resource_name(file.name.ToString()); + out_file->set_source_path(file.source.path); + SerializeConfig(file.config, out_file->mutable_config()); + + for (const SourcedResourceName& exported : file.exported_symbols) { + pb::internal::CompiledFile_Symbol* pb_symbol = out_file->add_exported_symbol(); + pb_symbol->set_resource_name(exported.name.ToString()); + pb_symbol->mutable_source()->set_line_number(exported.line); + } +} + +static void SerializeXmlCommon(const xml::Node& node, pb::XmlNode* out_node) { + pb::SourcePosition* pb_src = out_node->mutable_source(); + pb_src->set_line_number(node.line_number); + pb_src->set_column_number(node.column_number); +} + +void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node) { + SerializeXmlCommon(el, out_node); + + pb::XmlElement* pb_element = out_node->mutable_element(); + pb_element->set_name(el.name); + pb_element->set_namespace_uri(el.namespace_uri); + + for (const xml::NamespaceDecl& ns : el.namespace_decls) { + pb::XmlNamespace* pb_ns = pb_element->add_namespace_declaration(); + pb_ns->set_prefix(ns.prefix); + pb_ns->set_uri(ns.uri); + pb::SourcePosition* pb_src = pb_ns->mutable_source(); + pb_src->set_line_number(ns.line_number); + pb_src->set_column_number(ns.column_number); + } + + for (const xml::Attribute& attr : el.attributes) { + pb::XmlAttribute* pb_attr = pb_element->add_attribute(); + pb_attr->set_name(attr.name); + pb_attr->set_namespace_uri(attr.namespace_uri); + pb_attr->set_value(attr.value); + if (attr.compiled_attribute) { + const ResourceId attr_id = attr.compiled_attribute.value().id.value_or_default({}); + pb_attr->set_resource_id(attr_id.id); + } + if (attr.compiled_value != nullptr) { + SerializeItemToPb(*attr.compiled_value, pb_attr->mutable_compiled_item()); + pb::SourcePosition* pb_src = pb_attr->mutable_source(); + pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or_default(0)); + } + } + + for (const std::unique_ptr<xml::Node>& child : el.children) { + if (const xml::Element* child_el = xml::NodeCast<xml::Element>(child.get())) { + SerializeXmlToPb(*child_el, pb_element->add_child()); + } else if (const xml::Text* text_el = xml::NodeCast<xml::Text>(child.get())) { + pb::XmlNode* pb_child_node = pb_element->add_child(); + SerializeXmlCommon(*text_el, pb_child_node); + pb_child_node->set_text(text_el->text); + } else { + LOG(FATAL) << "unhandled XmlNode type"; + } + } +} + +void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node) { + SerializeXmlToPb(*resource.root, out_node); +} + +CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : out_(out) { +} + +void CompiledFileOutputStream::EnsureAlignedWrite() { + const int overflow = out_.ByteCount() % 4; + if (overflow > 0) { + uint32_t zero = 0u; + out_.WriteRaw(&zero, 4 - overflow); + } +} + +void CompiledFileOutputStream::WriteLittleEndian32(uint32_t val) { + EnsureAlignedWrite(); + out_.WriteLittleEndian32(val); +} + +void CompiledFileOutputStream::WriteCompiledFile(const pb::internal::CompiledFile& compiled_file) { + EnsureAlignedWrite(); + out_.WriteLittleEndian64(static_cast<uint64_t>(compiled_file.ByteSize())); + compiled_file.SerializeWithCachedSizes(&out_); +} + +void CompiledFileOutputStream::WriteData(const BigBuffer& buffer) { + EnsureAlignedWrite(); + out_.WriteLittleEndian64(static_cast<uint64_t>(buffer.size())); + for (const BigBuffer::Block& block : buffer) { + out_.WriteRaw(block.buffer.get(), block.size); + } +} + +void CompiledFileOutputStream::WriteData(const void* data, size_t len) { + EnsureAlignedWrite(); + out_.WriteLittleEndian64(static_cast<uint64_t>(len)); + out_.WriteRaw(data, len); +} + +bool CompiledFileOutputStream::HadError() { + return out_.HadError(); +} + +} // namespace aapt diff --git a/tools/aapt2/proto/ProtoSerialize.h b/tools/aapt2/proto/ProtoSerialize.h index 8c46642e9090..4bf7e1c2a26d 100644 --- a/tools/aapt2/proto/ProtoSerialize.h +++ b/tools/aapt2/proto/ProtoSerialize.h @@ -19,22 +19,60 @@ #include "android-base/macros.h" #include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/io/zero_copy_stream_impl_lite.h" -#include "Diagnostics.h" +#include "ConfigDescription.h" +#include "Configuration.pb.h" #include "ResourceTable.h" -#include "Source.h" -#include "proto/ProtoHelpers.h" +#include "ResourceValues.h" +#include "Resources.pb.h" +#include "ResourcesInternal.pb.h" +#include "StringPool.h" +#include "xml/XmlDom.h" + +namespace google { +namespace protobuf { +namespace io { +class ZeroCopyOutputStream; +} // namespace io +} // namespace protobuf +} // namespace google namespace aapt { +// Serializes a Value to its protobuf representation. An optional StringPool will hold the +// source path string. +void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool = nullptr); + +// Serialize an Item into its protobuf representation. pb::Item does not store the source path nor +// comments of an Item. +void SerializeItemToPb(const Item& item, pb::Item* out_item); + +// Serializes an XML element into its protobuf representation. +void SerializeXmlToPb(const xml::Element& el, pb::XmlNode* out_node); + +// Serializes an XmlResource into its protobuf representation. The ResourceFile is NOT serialized. +void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out_node); + +// Serializes a StringPool into its protobuf representation, which is really just the binary +// ResStringPool representation stuffed into a bytes field. +void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool); + +// Serializes a ConfigDescription into its protobuf representation. +void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config); + +// Serializes a ResourceTable into its protobuf representation. +void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table); + +// Serializes a ResourceFile into its protobuf representation. +void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file); + class CompiledFileOutputStream { public: - explicit CompiledFileOutputStream(google::protobuf::io::ZeroCopyOutputStream* out); + explicit CompiledFileOutputStream(::google::protobuf::io::ZeroCopyOutputStream* out); void WriteLittleEndian32(uint32_t value); - void WriteCompiledFile(const pb::internal::CompiledFile* compiledFile); - void WriteData(const BigBuffer* buffer); + void WriteCompiledFile(const pb::internal::CompiledFile& compiledFile); + void WriteData(const BigBuffer& buffer); void WriteData(const void* data, size_t len); bool HadError(); @@ -43,33 +81,9 @@ class CompiledFileOutputStream { void EnsureAlignedWrite(); - google::protobuf::io::CodedOutputStream out_; -}; - -class CompiledFileInputStream { - public: - explicit CompiledFileInputStream(const void* data, size_t size); - - bool ReadLittleEndian32(uint32_t* outVal); - bool ReadCompiledFile(pb::internal::CompiledFile* outVal); - bool ReadDataMetaData(uint64_t* outOffset, uint64_t* outLen); - - private: - DISALLOW_COPY_AND_ASSIGN(CompiledFileInputStream); - - void EnsureAlignedRead(); - - google::protobuf::io::CodedInputStream in_; + ::google::protobuf::io::CodedOutputStream out_; }; -std::unique_ptr<pb::ResourceTable> SerializeTableToPb(ResourceTable* table); -std::unique_ptr<ResourceTable> DeserializeTableFromPb(const pb::ResourceTable& pbTable, - const Source& source, IDiagnostics* diag); - -std::unique_ptr<pb::internal::CompiledFile> SerializeCompiledFileToPb(const ResourceFile& file); -std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb( - const pb::internal::CompiledFile& pbFile, const Source& source, IDiagnostics* diag); - } // namespace aapt #endif /* AAPT_FLATTEN_TABLEPROTOSERIALIZER_H */ diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/ProtoSerialize_test.cpp index 8f6414c68a43..b263aff41db0 100644 --- a/tools/aapt2/proto/TableProtoSerializer_test.cpp +++ b/tools/aapt2/proto/ProtoSerialize_test.cpp @@ -16,18 +16,23 @@ #include "proto/ProtoSerialize.h" -#include "ResourceTable.h" +#include "google/protobuf/io/zero_copy_stream_impl_lite.h" + +#include "ResourceUtils.h" +#include "proto/ProtoDeserialize.h" #include "test/Test.h" using ::android::StringPiece; using ::google::protobuf::io::StringOutputStream; using ::testing::Eq; +using ::testing::IsEmpty; using ::testing::NotNull; using ::testing::SizeIs; +using ::testing::StrEq; namespace aapt { -TEST(TableProtoSerializer, SerializeSinglePackage) { +TEST(ProtoSerializeTest, SerializeSinglePackage) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() @@ -51,9 +56,8 @@ TEST(TableProtoSerializer, SerializeSinglePackage) { // Make a plural. std::unique_ptr<Plural> plural = util::make_unique<Plural>(); plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one")); - ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"), - ConfigDescription{}, {}, std::move(plural), - context->GetDiagnostics())); + ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"), ConfigDescription{}, + {}, std::move(plural), context->GetDiagnostics())); // Make a styled string. StyleString style_string; @@ -66,15 +70,11 @@ TEST(TableProtoSerializer, SerializeSinglePackage) { // Make a resource with different products. ASSERT_TRUE(table->AddResource( - test::ParseNameOrDie("com.app.a:integer/one"), - test::ParseConfigOrDie("land"), {}, - test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), - context->GetDiagnostics())); + test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), {}, + test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics())); ASSERT_TRUE(table->AddResource( - test::ParseNameOrDie("com.app.a:integer/one"), - test::ParseConfigOrDie("land"), "tablet", - test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), - context->GetDiagnostics())); + test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet", + test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), context->GetDiagnostics())); // Make a reference with both resource name and resource ID. // The reference should point to a resource outside of this table to test that both name and id @@ -82,53 +82,53 @@ TEST(TableProtoSerializer, SerializeSinglePackage) { Reference expected_ref; expected_ref.name = test::ParseNameOrDie("android:layout/main"); expected_ref.id = ResourceId(0x01020000); - ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:layout/abc"), - ConfigDescription::DefaultConfig(), {}, - util::make_unique<Reference>(expected_ref), - context->GetDiagnostics())); + ASSERT_TRUE(table->AddResource( + test::ParseNameOrDie("com.app.a:layout/abc"), ConfigDescription::DefaultConfig(), {}, + util::make_unique<Reference>(expected_ref), context->GetDiagnostics())); - std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(table.get()); - ASSERT_THAT(pb_table, NotNull()); + pb::ResourceTable pb_table; + SerializeTableToPb(*table, &pb_table); - std::unique_ptr<ResourceTable> new_table = DeserializeTableFromPb( - *pb_table, Source{"test"}, context->GetDiagnostics()); - ASSERT_THAT(new_table, NotNull()); + ResourceTable new_table; + std::string error; + ASSERT_TRUE(DeserializeTableFromPb(pb_table, &new_table, &error)); + EXPECT_THAT(error, IsEmpty()); - Id* new_id = test::GetValue<Id>(new_table.get(), "com.app.a:id/foo"); + Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo"); ASSERT_THAT(new_id, NotNull()); EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak())); Maybe<ResourceTable::SearchResult> result = - new_table->FindResource(test::ParseNameOrDie("com.app.a:layout/main")); + new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main")); ASSERT_TRUE(result); EXPECT_THAT(result.value().type->symbol_status.state, Eq(SymbolState::kPublic)); EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic)); - result = new_table->FindResource(test::ParseNameOrDie("com.app.a:bool/foo")); + result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo")); ASSERT_TRUE(result); EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kUndefined)); EXPECT_TRUE(result.value().entry->symbol_status.allow_new); // Find the product-dependent values BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>( - new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"), ""); + &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), ""); ASSERT_THAT(prim, NotNull()); EXPECT_THAT(prim->value.data, Eq(123u)); prim = test::GetValueForConfigAndProduct<BinaryPrimitive>( - new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet"); + &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet"); ASSERT_THAT(prim, NotNull()); EXPECT_THAT(prim->value.data, Eq(321u)); - Reference* actual_ref = test::GetValue<Reference>(new_table.get(), "com.app.a:layout/abc"); + Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc"); ASSERT_THAT(actual_ref, NotNull()); ASSERT_TRUE(actual_ref->name); ASSERT_TRUE(actual_ref->id); EXPECT_THAT(*actual_ref, Eq(expected_ref)); StyledString* actual_styled_str = - test::GetValue<StyledString>(new_table.get(), "com.app.a:string/styled"); + test::GetValue<StyledString>(&new_table, "com.app.a:string/styled"); ASSERT_THAT(actual_styled_str, NotNull()); EXPECT_THAT(actual_styled_str->value->value, Eq("hello")); ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u)); @@ -137,32 +137,32 @@ TEST(TableProtoSerializer, SerializeSinglePackage) { EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u)); } -TEST(TableProtoSerializer, SerializeFileHeader) { +TEST(ProtoSerializeTest, SerializeFileHeader) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); ResourceFile f; f.config = test::ParseConfigOrDie("hdpi-v9"); f.name = test::ParseNameOrDie("com.app.a:layout/main"); f.source.path = "res/layout-hdpi-v9/main.xml"; - f.exported_symbols.push_back( - SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u}); + f.exported_symbols.push_back(SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u}); const std::string expected_data1 = "123"; const std::string expected_data2 = "1234"; std::string output_str; { - std::unique_ptr<pb::internal::CompiledFile> pb_file1 = SerializeCompiledFileToPb(f); + pb::internal::CompiledFile pb_f1, pb_f2; + SerializeCompiledFileToPb(f, &pb_f1); f.name.entry = "__" + f.name.entry + "$0"; - std::unique_ptr<pb::internal::CompiledFile> pb_file2 = SerializeCompiledFileToPb(f); + SerializeCompiledFileToPb(f, &pb_f2); StringOutputStream out_stream(&output_str); CompiledFileOutputStream out_file_stream(&out_stream); out_file_stream.WriteLittleEndian32(2); - out_file_stream.WriteCompiledFile(pb_file1.get()); + out_file_stream.WriteCompiledFile(pb_f1); out_file_stream.WriteData(expected_data1.data(), expected_data1.size()); - out_file_stream.WriteCompiledFile(pb_file2.get()); + out_file_stream.WriteCompiledFile(pb_f2); out_file_stream.WriteData(expected_data2.data(), expected_data2.size()); ASSERT_FALSE(out_file_stream.HadError()); } @@ -174,12 +174,13 @@ TEST(TableProtoSerializer, SerializeFileHeader) { // Read the first compiled file. - pb::internal::CompiledFile new_pb_file; - ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file)); + pb::internal::CompiledFile new_pb_f1; + ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f1)); - std::unique_ptr<ResourceFile> file = DeserializeCompiledFileFromPb( - new_pb_file, Source("test"), context->GetDiagnostics()); - ASSERT_THAT(file, NotNull()); + ResourceFile new_f1; + std::string error; + ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f1, &new_f1, &error)); + EXPECT_THAT(error, IsEmpty()); uint64_t offset, len; ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len)); @@ -190,15 +191,17 @@ TEST(TableProtoSerializer, SerializeFileHeader) { // Expect the data to be aligned. EXPECT_EQ(0u, offset & 0x03); - ASSERT_EQ(1u, file->exported_symbols.size()); - EXPECT_EQ(test::ParseNameOrDie("id/unchecked"), file->exported_symbols[0].name); + ASSERT_EQ(1u, new_f1.exported_symbols.size()); + EXPECT_EQ(test::ParseNameOrDie("id/unchecked"), new_f1.exported_symbols[0].name); // Read the second compiled file. - ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file)); + pb::internal::CompiledFile new_pb_f2; + ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f2)); - file = DeserializeCompiledFileFromPb(new_pb_file, Source("test"), context->GetDiagnostics()); - ASSERT_THAT(file, NotNull()); + ResourceFile new_f2; + ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f2, &new_f2, &error)); + EXPECT_THAT(error, IsEmpty()); ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len)); @@ -209,9 +212,10 @@ TEST(TableProtoSerializer, SerializeFileHeader) { EXPECT_EQ(0u, offset & 0x03); } -TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) { +TEST(ProtoSerializeTest, DeserializeCorruptHeaderSafely) { ResourceFile f; - std::unique_ptr<pb::internal::CompiledFile> pb_file = SerializeCompiledFileToPb(f); + pb::internal::CompiledFile pb_file; + SerializeCompiledFileToPb(f, &pb_file); const std::string expected_data = "1234"; @@ -220,7 +224,7 @@ TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) { StringOutputStream out_stream(&output_str); CompiledFileOutputStream out_file_stream(&out_stream); out_file_stream.WriteLittleEndian32(1); - out_file_stream.WriteCompiledFile(pb_file.get()); + out_file_stream.WriteCompiledFile(pb_file); out_file_stream.WriteData(expected_data.data(), expected_data.size()); ASSERT_FALSE(out_file_stream.HadError()); } @@ -240,17 +244,112 @@ TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) { EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len)); } +TEST(ProtoSerializeTest, SerializeAndDeserializeXml) { + xml::Element element; + element.line_number = 22; + element.column_number = 23; + element.name = "element"; + element.namespace_uri = "uri://"; + + xml::NamespaceDecl decl; + decl.prefix = "android"; + decl.uri = xml::kSchemaAndroid; + decl.line_number = 21; + decl.column_number = 24; + + element.namespace_decls.push_back(decl); + + xml::Attribute attr; + attr.name = "name"; + attr.namespace_uri = xml::kSchemaAndroid; + attr.value = "23dp"; + attr.compiled_attribute = xml::AaptAttribute({}, ResourceId(0x01010000)); + attr.compiled_value = + ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION); + attr.compiled_value->SetSource(Source().WithLine(25)); + element.attributes.push_back(std::move(attr)); + + std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>(); + text->line_number = 25; + text->column_number = 3; + text->text = "hey there"; + element.AppendChild(std::move(text)); + + std::unique_ptr<xml::Element> child = util::make_unique<xml::Element>(); + child->name = "child"; + + text = util::make_unique<xml::Text>(); + text->text = "woah there"; + child->AppendChild(std::move(text)); + + element.AppendChild(std::move(child)); + + pb::XmlNode pb_xml; + SerializeXmlToPb(element, &pb_xml); + + StringPool pool; + xml::Element actual_el; + std::string error; + ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error)); + ASSERT_THAT(error, IsEmpty()); + + EXPECT_THAT(actual_el.name, StrEq("element")); + EXPECT_THAT(actual_el.namespace_uri, StrEq("uri://")); + EXPECT_THAT(actual_el.line_number, Eq(22u)); + EXPECT_THAT(actual_el.column_number, Eq(23u)); + + ASSERT_THAT(actual_el.namespace_decls, SizeIs(1u)); + const xml::NamespaceDecl& actual_decl = actual_el.namespace_decls[0]; + EXPECT_THAT(actual_decl.prefix, StrEq("android")); + EXPECT_THAT(actual_decl.uri, StrEq(xml::kSchemaAndroid)); + EXPECT_THAT(actual_decl.line_number, Eq(21u)); + EXPECT_THAT(actual_decl.column_number, Eq(24u)); + + ASSERT_THAT(actual_el.attributes, SizeIs(1u)); + const xml::Attribute& actual_attr = actual_el.attributes[0]; + EXPECT_THAT(actual_attr.name, StrEq("name")); + EXPECT_THAT(actual_attr.namespace_uri, StrEq(xml::kSchemaAndroid)); + EXPECT_THAT(actual_attr.value, StrEq("23dp")); + + ASSERT_THAT(actual_attr.compiled_value, NotNull()); + const BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(actual_attr.compiled_value.get()); + ASSERT_THAT(prim, NotNull()); + EXPECT_THAT(prim->value.dataType, Eq(android::Res_value::TYPE_DIMENSION)); + + ASSERT_TRUE(actual_attr.compiled_attribute); + ASSERT_TRUE(actual_attr.compiled_attribute.value().id); + + ASSERT_THAT(actual_el.children, SizeIs(2u)); + const xml::Text* child_text = xml::NodeCast<xml::Text>(actual_el.children[0].get()); + ASSERT_THAT(child_text, NotNull()); + const xml::Element* child_el = xml::NodeCast<xml::Element>(actual_el.children[1].get()); + ASSERT_THAT(child_el, NotNull()); + + EXPECT_THAT(child_text->line_number, Eq(25u)); + EXPECT_THAT(child_text->column_number, Eq(3u)); + EXPECT_THAT(child_text->text, StrEq("hey there")); + + EXPECT_THAT(child_el->name, StrEq("child")); + ASSERT_THAT(child_el->children, SizeIs(1u)); + + child_text = xml::NodeCast<xml::Text>(child_el->children[0].get()); + ASSERT_THAT(child_text, NotNull()); + EXPECT_THAT(child_text->text, StrEq("woah there")); +} + static void ExpectConfigSerializes(const StringPiece& config_str) { const ConfigDescription expected_config = test::ParseConfigOrDie(config_str); pb::Configuration pb_config; SerializeConfig(expected_config, &pb_config); ConfigDescription actual_config; - ASSERT_TRUE(DeserializeConfigDescriptionFromPb(pb_config, &actual_config)); + std::string error; + ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error)); + ASSERT_THAT(error, IsEmpty()); EXPECT_EQ(expected_config, actual_config); } -TEST(TableProtoSerializer, SerializeDeserializeConfiguration) { +TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) { ExpectConfigSerializes(""); ExpectConfigSerializes("mcc123"); diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp deleted file mode 100644 index a49f6f6e42cd..000000000000 --- a/tools/aapt2/proto/TableProtoDeserializer.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "proto/ProtoSerialize.h" - -#include "android-base/logging.h" -#include "androidfw/ResourceTypes.h" - -#include "ResourceTable.h" -#include "ResourceUtils.h" -#include "ValueVisitor.h" -#include "proto/ProtoHelpers.h" - -namespace aapt { - -namespace { - -class ReferenceIdToNameVisitor : public DescendingValueVisitor { - public: - using DescendingValueVisitor::Visit; - - explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping) - : mapping_(mapping) { - CHECK(mapping_ != nullptr); - } - - void Visit(Reference* reference) override { - if (!reference->id || !reference->id.value().is_valid()) { - return; - } - - ResourceId id = reference->id.value(); - auto cache_iter = mapping_->find(id); - if (cache_iter != mapping_->end()) { - reference->name = cache_iter->second.ToResourceName(); - } - } - - private: - const std::map<ResourceId, ResourceNameRef>* mapping_; -}; - -class PackagePbDeserializer { - public: - PackagePbDeserializer(const android::ResStringPool* sourcePool, const Source& source, - IDiagnostics* diag) - : source_pool_(sourcePool), source_(source), diag_(diag) { - } - - public: - bool DeserializeFromPb(const pb::Package& pb_package, ResourceTable* table) { - Maybe<uint8_t> id; - if (pb_package.has_package_id()) { - id = static_cast<uint8_t>(pb_package.package_id().id()); - } - - std::map<ResourceId, ResourceNameRef> id_index; - - ResourceTablePackage* pkg = table->CreatePackage(pb_package.package_name(), id); - for (const pb::Type& pb_type : pb_package.type()) { - const ResourceType* res_type = ParseResourceType(pb_type.name()); - if (res_type == nullptr) { - diag_->Error(DiagMessage(source_) << "unknown type '" << pb_type.name() << "'"); - return {}; - } - - ResourceTableType* type = pkg->FindOrCreateType(*res_type); - - for (const pb::Entry& pb_entry : pb_type.entry()) { - ResourceEntry* entry = type->FindOrCreateEntry(pb_entry.name()); - - // Deserialize the symbol status (public/private with source and comments). - if (pb_entry.has_symbol_status()) { - const pb::SymbolStatus& pb_status = pb_entry.symbol_status(); - if (pb_status.has_source()) { - DeserializeSourceFromPb(pb_status.source(), *source_pool_, - &entry->symbol_status.source); - } - - entry->symbol_status.comment = pb_status.comment(); - entry->symbol_status.allow_new = pb_status.allow_new(); - - SymbolState visibility = DeserializeVisibilityFromPb(pb_status.visibility()); - entry->symbol_status.state = visibility; - - if (visibility == SymbolState::kPublic) { - // This is a public symbol, we must encode the ID now if there is one. - if (pb_entry.has_entry_id()) { - entry->id = static_cast<uint16_t>(pb_entry.entry_id().id()); - } - - if (type->symbol_status.state != SymbolState::kPublic) { - // If the type has not been made public, do so now. - type->symbol_status.state = SymbolState::kPublic; - if (pb_type.has_type_id()) { - type->id = static_cast<uint8_t>(pb_type.type_id().id()); - } - } - } else if (visibility == SymbolState::kPrivate) { - if (type->symbol_status.state == SymbolState::kUndefined) { - type->symbol_status.state = SymbolState::kPrivate; - } - } - } - - ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(), - pb_entry.entry_id().id()); - if (resid.is_valid()) { - id_index[resid] = ResourceNameRef(pkg->name, type->type, entry->name); - } - - for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) { - const pb::Configuration& pb_config = pb_config_value.config(); - - ConfigDescription config; - if (!DeserializeConfigDescriptionFromPb(pb_config, &config)) { - diag_->Error(DiagMessage(source_) << "invalid configuration"); - return {}; - } - - ResourceConfigValue* config_value = entry->FindOrCreateValue(config, pb_config.product()); - if (config_value->value) { - // Duplicate config. - diag_->Error(DiagMessage(source_) << "duplicate configuration"); - return {}; - } - - config_value->value = - DeserializeValueFromPb(pb_config_value.value(), config, &table->string_pool); - if (!config_value->value) { - return {}; - } - } - } - } - - ReferenceIdToNameVisitor visitor(&id_index); - VisitAllValuesInPackage(pkg, &visitor); - return true; - } - - private: - std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item, - const ConfigDescription& config, StringPool* pool) { - if (pb_item.has_ref()) { - const pb::Reference& pb_ref = pb_item.ref(); - std::unique_ptr<Reference> ref = util::make_unique<Reference>(); - if (!DeserializeReferenceFromPb(pb_ref, ref.get())) { - return {}; - } - return std::move(ref); - - } else if (pb_item.has_prim()) { - const pb::Primitive& pb_prim = pb_item.prim(); - return util::make_unique<BinaryPrimitive>(static_cast<uint8_t>(pb_prim.type()), - pb_prim.data()); - - } else if (pb_item.has_id()) { - return util::make_unique<Id>(); - - } else if (pb_item.has_str()) { - return util::make_unique<String>( - pool->MakeRef(pb_item.str().value(), StringPool::Context(config))); - - } else if (pb_item.has_raw_str()) { - return util::make_unique<RawString>( - pool->MakeRef(pb_item.raw_str().value(), StringPool::Context(config))); - - } else if (pb_item.has_styled_str()) { - const pb::StyledString& pb_str = pb_item.styled_str(); - StyleString style_str{pb_str.value()}; - for (const pb::StyledString::Span& pb_span : pb_str.span()) { - style_str.spans.push_back(Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()}); - } - return util::make_unique<StyledString>(pool->MakeRef( - style_str, StringPool::Context(StringPool::Context::kNormalPriority, config))); - - } else if (pb_item.has_file()) { - return util::make_unique<FileReference>(pool->MakeRef( - pb_item.file().path(), StringPool::Context(StringPool::Context::kHighPriority, config))); - - } else { - diag_->Error(DiagMessage(source_) << "unknown item"); - } - return {}; - } - - std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value, - const ConfigDescription& config, - StringPool* pool) { - std::unique_ptr<Value> value; - if (pb_value.has_item()) { - value = DeserializeItemFromPb(pb_value.item(), config, pool); - if (!value) { - return {}; - } - - } else if (pb_value.has_compound_value()) { - const pb::CompoundValue& pb_compound_value = pb_value.compound_value(); - if (pb_compound_value.has_attr()) { - const pb::Attribute& pb_attr = pb_compound_value.attr(); - std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(); - attr->type_mask = pb_attr.format_flags(); - attr->min_int = pb_attr.min_int(); - attr->max_int = pb_attr.max_int(); - for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbol()) { - Attribute::Symbol symbol; - DeserializeItemCommon(pb_symbol, &symbol.symbol); - if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol)) { - return {}; - } - symbol.value = pb_symbol.value(); - attr->symbols.push_back(std::move(symbol)); - } - value = std::move(attr); - - } else if (pb_compound_value.has_style()) { - const pb::Style& pb_style = pb_compound_value.style(); - std::unique_ptr<Style> style = util::make_unique<Style>(); - if (pb_style.has_parent()) { - style->parent = Reference(); - if (!DeserializeReferenceFromPb(pb_style.parent(), &style->parent.value())) { - return {}; - } - - if (pb_style.has_parent_source()) { - Source parent_source; - DeserializeSourceFromPb(pb_style.parent_source(), *source_pool_, &parent_source); - style->parent.value().SetSource(std::move(parent_source)); - } - } - - for (const pb::Style_Entry& pb_entry : pb_style.entry()) { - Style::Entry entry; - DeserializeItemCommon(pb_entry, &entry.key); - if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key)) { - return {}; - } - - entry.value = DeserializeItemFromPb(pb_entry.item(), config, pool); - if (!entry.value) { - return {}; - } - - DeserializeItemCommon(pb_entry, entry.value.get()); - style->entries.push_back(std::move(entry)); - } - value = std::move(style); - - } else if (pb_compound_value.has_styleable()) { - const pb::Styleable& pb_styleable = pb_compound_value.styleable(); - std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); - for (const pb::Styleable_Entry& pb_entry : pb_styleable.entry()) { - Reference attr_ref; - DeserializeItemCommon(pb_entry, &attr_ref); - DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref); - styleable->entries.push_back(std::move(attr_ref)); - } - value = std::move(styleable); - - } else if (pb_compound_value.has_array()) { - const pb::Array& pb_array = pb_compound_value.array(); - std::unique_ptr<Array> array = util::make_unique<Array>(); - for (const pb::Array_Element& pb_entry : pb_array.element()) { - std::unique_ptr<Item> item = DeserializeItemFromPb(pb_entry.item(), config, pool); - if (!item) { - return {}; - } - - DeserializeItemCommon(pb_entry, item.get()); - array->elements.push_back(std::move(item)); - } - value = std::move(array); - - } else if (pb_compound_value.has_plural()) { - const pb::Plural& pb_plural = pb_compound_value.plural(); - std::unique_ptr<Plural> plural = util::make_unique<Plural>(); - for (const pb::Plural_Entry& pb_entry : pb_plural.entry()) { - size_t pluralIdx = DeserializePluralEnumFromPb(pb_entry.arity()); - plural->values[pluralIdx] = DeserializeItemFromPb(pb_entry.item(), config, pool); - if (!plural->values[pluralIdx]) { - return {}; - } - - DeserializeItemCommon(pb_entry, plural->values[pluralIdx].get()); - } - value = std::move(plural); - - } else { - diag_->Error(DiagMessage(source_) << "unknown compound value"); - return {}; - } - } else { - diag_->Error(DiagMessage(source_) << "unknown value"); - return {}; - } - - CHECK(value) << "forgot to set value"; - - value->SetWeak(pb_value.weak()); - DeserializeItemCommon(pb_value, value.get()); - return value; - } - - bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref) { - out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type()); - out_ref->private_reference = pb_ref.private_(); - - if (pb_ref.id() != 0) { - out_ref->id = ResourceId(pb_ref.id()); - } - - if (!pb_ref.name().empty()) { - ResourceNameRef name_ref; - if (!ResourceUtils::ParseResourceName(pb_ref.name(), &name_ref, nullptr)) { - diag_->Error(DiagMessage(source_) << "invalid reference name '" << pb_ref.name() << "'"); - return false; - } - - out_ref->name = name_ref.ToResourceName(); - } - return true; - } - - template <typename T> - void DeserializeItemCommon(const T& pb_item, Value* out_value) { - if (pb_item.has_source()) { - Source source; - DeserializeSourceFromPb(pb_item.source(), *source_pool_, &source); - out_value->SetSource(std::move(source)); - } - out_value->SetComment(pb_item.comment()); - } - - private: - const android::ResStringPool* source_pool_; - const Source source_; - IDiagnostics* diag_; -}; - -} // namespace - -std::unique_ptr<ResourceTable> DeserializeTableFromPb(const pb::ResourceTable& pb_table, - const Source& source, IDiagnostics* diag) { - // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which - // causes errors when qualifying it with android:: - using namespace android; - - std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); - - ResStringPool source_pool; - if (pb_table.has_source_pool()) { - status_t result = source_pool.setTo(pb_table.source_pool().data().data(), - pb_table.source_pool().data().size()); - if (result != NO_ERROR) { - diag->Error(DiagMessage(source) << "invalid source pool"); - return {}; - } - } - - PackagePbDeserializer package_pb_deserializer(&source_pool, source, diag); - for (const pb::Package& pb_package : pb_table.package()) { - if (!package_pb_deserializer.DeserializeFromPb(pb_package, table.get())) { - return {}; - } - } - return table; -} - -std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb( - const pb::internal::CompiledFile& pb_file, const Source& source, IDiagnostics* diag) { - std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>(); - - ResourceNameRef name_ref; - - // Need to create an lvalue here so that nameRef can point to something real. - if (!ResourceUtils::ParseResourceName(pb_file.resource_name(), &name_ref)) { - diag->Error(DiagMessage(source) - << "invalid resource name in compiled file header: " - << pb_file.resource_name()); - return {}; - } - file->name = name_ref.ToResourceName(); - file->source.path = pb_file.source_path(); - if (!DeserializeConfigDescriptionFromPb(pb_file.config(), &file->config)) { - diag->Error(DiagMessage(source) << "invalid resource configuration in compiled file header"); - return {}; - } - - for (const pb::internal::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbol()) { - // Need to create an lvalue here so that nameRef can point to something real. - if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), &name_ref)) { - diag->Error(DiagMessage(source) - << "invalid resource name for exported symbol in compiled file header: " - << pb_file.resource_name()); - return {}; - } - size_t line = 0u; - if (pb_symbol.has_source()) { - line = pb_symbol.source().line_number(); - } - file->exported_symbols.push_back(SourcedResourceName{name_ref.ToResourceName(), line}); - } - return file; -} - -} // namespace aapt diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp deleted file mode 100644 index e15a0adbda9b..000000000000 --- a/tools/aapt2/proto/TableProtoSerializer.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "proto/ProtoSerialize.h" - -#include "android-base/logging.h" - -#include "Resource.h" -#include "ResourceTable.h" -#include "StringPool.h" -#include "ValueVisitor.h" -#include "proto/ProtoHelpers.h" -#include "util/BigBuffer.h" - -using ::google::protobuf::io::CodedInputStream; -using ::google::protobuf::io::CodedOutputStream; -using ::google::protobuf::io::ZeroCopyOutputStream; - -namespace aapt { - -namespace { - -class PbSerializerVisitor : public ConstValueVisitor { - public: - using ConstValueVisitor::Visit; - - // Constructor to use when expecting to serialize any value. - PbSerializerVisitor(StringPool* source_pool, pb::Value* out_pb_value) - : source_pool_(source_pool), out_pb_value_(out_pb_value), out_pb_item_(nullptr) { - } - - // Constructor to use when expecting to serialize an Item. - PbSerializerVisitor(StringPool* sourcePool, pb::Item* outPbItem) - : source_pool_(sourcePool), out_pb_value_(nullptr), out_pb_item_(outPbItem) { - } - - void Visit(const Reference* ref) override { - SerializeReferenceToPb(*ref, pb_item()->mutable_ref()); - } - - void Visit(const String* str) override { - pb_item()->mutable_str()->set_value(*str->value); - } - - void Visit(const RawString* str) override { - pb_item()->mutable_raw_str()->set_value(*str->value); - } - - void Visit(const StyledString* str) override { - pb::StyledString* pb_str = pb_item()->mutable_styled_str(); - pb_str->set_value(str->value->value); - - for (const StringPool::Span& span : str->value->spans) { - pb::StyledString::Span* pb_span = pb_str->add_span(); - pb_span->set_tag(*span.name); - pb_span->set_first_char(span.first_char); - pb_span->set_last_char(span.last_char); - } - } - - void Visit(const FileReference* file) override { - pb_item()->mutable_file()->set_path(*file->path); - } - - void Visit(const Id* /*id*/) override { - pb_item()->mutable_id(); - } - - void Visit(const BinaryPrimitive* prim) override { - android::Res_value val = {}; - prim->Flatten(&val); - - pb::Primitive* pb_prim = pb_item()->mutable_prim(); - pb_prim->set_type(val.dataType); - pb_prim->set_data(val.data); - } - - void VisitItem(const Item* item) override { - LOG(FATAL) << "unimplemented item"; - } - - void Visit(const Attribute* attr) override { - pb::Attribute* pb_attr = pb_compound_value()->mutable_attr(); - pb_attr->set_format_flags(attr->type_mask); - pb_attr->set_min_int(attr->min_int); - pb_attr->set_max_int(attr->max_int); - - for (const auto& symbol : attr->symbols) { - pb::Attribute_Symbol* pb_symbol = pb_attr->add_symbol(); - SerializeItemCommonToPb(symbol.symbol, pb_symbol); - SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name()); - pb_symbol->set_value(symbol.value); - } - } - - void Visit(const Style* style) override { - pb::Style* pb_style = pb_compound_value()->mutable_style(); - if (style->parent) { - SerializeReferenceToPb(style->parent.value(), pb_style->mutable_parent()); - SerializeSourceToPb(style->parent.value().GetSource(), source_pool_, - pb_style->mutable_parent_source()); - } - - for (const Style::Entry& entry : style->entries) { - pb::Style_Entry* pb_entry = pb_style->add_entry(); - SerializeReferenceToPb(entry.key, pb_entry->mutable_key()); - - pb::Item* pb_item = pb_entry->mutable_item(); - SerializeItemCommonToPb(entry.key, pb_entry); - PbSerializerVisitor sub_visitor(source_pool_, pb_item); - entry.value->Accept(&sub_visitor); - } - } - - void Visit(const Styleable* styleable) override { - pb::Styleable* pb_styleable = pb_compound_value()->mutable_styleable(); - for (const Reference& entry : styleable->entries) { - pb::Styleable_Entry* pb_entry = pb_styleable->add_entry(); - SerializeItemCommonToPb(entry, pb_entry); - SerializeReferenceToPb(entry, pb_entry->mutable_attr()); - } - } - - void Visit(const Array* array) override { - pb::Array* pb_array = pb_compound_value()->mutable_array(); - for (const auto& value : array->elements) { - pb::Array_Element* pb_element = pb_array->add_element(); - SerializeItemCommonToPb(*value, pb_element); - PbSerializerVisitor sub_visitor(source_pool_, pb_element->mutable_item()); - value->Accept(&sub_visitor); - } - } - - void Visit(const Plural* plural) override { - pb::Plural* pb_plural = pb_compound_value()->mutable_plural(); - const size_t count = plural->values.size(); - for (size_t i = 0; i < count; i++) { - if (!plural->values[i]) { - // No plural value set here. - continue; - } - - pb::Plural_Entry* pb_entry = pb_plural->add_entry(); - pb_entry->set_arity(SerializePluralEnumToPb(i)); - pb::Item* pb_element = pb_entry->mutable_item(); - SerializeItemCommonToPb(*plural->values[i], pb_entry); - PbSerializerVisitor sub_visitor(source_pool_, pb_element); - plural->values[i]->Accept(&sub_visitor); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(PbSerializerVisitor); - - pb::Item* pb_item() { - if (out_pb_value_) { - return out_pb_value_->mutable_item(); - } - return out_pb_item_; - } - - pb::CompoundValue* pb_compound_value() { - CHECK(out_pb_value_ != nullptr); - return out_pb_value_->mutable_compound_value(); - } - - template <typename T> - void SerializeItemCommonToPb(const Item& item, T* pb_item) { - SerializeSourceToPb(item.GetSource(), source_pool_, pb_item->mutable_source()); - pb_item->set_comment(item.GetComment()); - } - - void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) { - pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id); - - if (ref.name) { - pb_ref->set_name(ref.name.value().ToString()); - } - - pb_ref->set_private_(ref.private_reference); - pb_ref->set_type(SerializeReferenceTypeToPb(ref.reference_type)); - } - - StringPool* source_pool_; - pb::Value* out_pb_value_; - pb::Item* out_pb_item_; -}; - -} // namespace - -std::unique_ptr<pb::ResourceTable> SerializeTableToPb(ResourceTable* table) { - // We must do this before writing the resources, since the string pool IDs may change. - table->string_pool.Prune(); - table->string_pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int { - int diff = util::compare(a.priority, b.priority); - if (diff == 0) { - diff = a.config.compare(b.config); - } - return diff; - }); - - auto pb_table = util::make_unique<pb::ResourceTable>(); - StringPool source_pool; - - for (auto& package : table->packages) { - pb::Package* pb_package = pb_table->add_package(); - if (package->id) { - pb_package->mutable_package_id()->set_id(package->id.value()); - } - pb_package->set_package_name(package->name); - - for (auto& type : package->types) { - pb::Type* pb_type = pb_package->add_type(); - if (type->id) { - pb_type->mutable_type_id()->set_id(type->id.value()); - } - pb_type->set_name(ToString(type->type).to_string()); - - for (auto& entry : type->entries) { - pb::Entry* pb_entry = pb_type->add_entry(); - if (entry->id) { - pb_entry->mutable_entry_id()->set_id(entry->id.value()); - } - pb_entry->set_name(entry->name); - - // Write the SymbolStatus struct. - pb::SymbolStatus* pb_status = pb_entry->mutable_symbol_status(); - pb_status->set_visibility(SerializeVisibilityToPb(entry->symbol_status.state)); - SerializeSourceToPb(entry->symbol_status.source, &source_pool, pb_status->mutable_source()); - pb_status->set_comment(entry->symbol_status.comment); - pb_status->set_allow_new(entry->symbol_status.allow_new); - - for (auto& config_value : entry->values) { - pb::ConfigValue* pb_config_value = pb_entry->add_config_value(); - SerializeConfig(config_value->config, pb_config_value->mutable_config()); - pb_config_value->mutable_config()->set_product(config_value->product); - - pb::Value* pb_value = pb_config_value->mutable_value(); - SerializeSourceToPb(config_value->value->GetSource(), &source_pool, - pb_value->mutable_source()); - pb_value->set_comment(config_value->value->GetComment()); - pb_value->set_weak(config_value->value->IsWeak()); - - PbSerializerVisitor visitor(&source_pool, pb_value); - config_value->value->Accept(&visitor); - } - } - } - } - - SerializeStringPoolToPb(source_pool, pb_table->mutable_source_pool()); - return pb_table; -} - -std::unique_ptr<pb::internal::CompiledFile> SerializeCompiledFileToPb(const ResourceFile& file) { - auto pb_file = util::make_unique<pb::internal::CompiledFile>(); - pb_file->set_resource_name(file.name.ToString()); - pb_file->set_source_path(file.source.path); - SerializeConfig(file.config, pb_file->mutable_config()); - - for (const SourcedResourceName& exported : file.exported_symbols) { - pb::internal::CompiledFile_Symbol* pb_symbol = pb_file->add_exported_symbol(); - pb_symbol->set_resource_name(exported.name.ToString()); - pb_symbol->mutable_source()->set_line_number(exported.line); - } - return pb_file; -} - -CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : out_(out) { -} - -void CompiledFileOutputStream::EnsureAlignedWrite() { - const int overflow = out_.ByteCount() % 4; - if (overflow > 0) { - uint32_t zero = 0u; - out_.WriteRaw(&zero, 4 - overflow); - } -} - -void CompiledFileOutputStream::WriteLittleEndian32(uint32_t val) { - EnsureAlignedWrite(); - out_.WriteLittleEndian32(val); -} - -void CompiledFileOutputStream::WriteCompiledFile(const pb::internal::CompiledFile* compiled_file) { - EnsureAlignedWrite(); - out_.WriteLittleEndian64(static_cast<uint64_t>(compiled_file->ByteSize())); - compiled_file->SerializeWithCachedSizes(&out_); -} - -void CompiledFileOutputStream::WriteData(const BigBuffer* buffer) { - EnsureAlignedWrite(); - out_.WriteLittleEndian64(static_cast<uint64_t>(buffer->size())); - for (const BigBuffer::Block& block : *buffer) { - out_.WriteRaw(block.buffer.get(), block.size); - } -} - -void CompiledFileOutputStream::WriteData(const void* data, size_t len) { - EnsureAlignedWrite(); - out_.WriteLittleEndian64(static_cast<uint64_t>(len)); - out_.WriteRaw(data, len); -} - -bool CompiledFileOutputStream::HadError() { - return out_.HadError(); -} - -CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) - : in_(static_cast<const uint8_t*>(data), size) {} - -void CompiledFileInputStream::EnsureAlignedRead() { - const int overflow = in_.CurrentPosition() % 4; - if (overflow > 0) { - // Reads are always 4 byte aligned. - in_.Skip(4 - overflow); - } -} - -bool CompiledFileInputStream::ReadLittleEndian32(uint32_t* out_val) { - EnsureAlignedRead(); - return in_.ReadLittleEndian32(out_val); -} - -bool CompiledFileInputStream::ReadCompiledFile(pb::internal::CompiledFile* out_val) { - EnsureAlignedRead(); - - google::protobuf::uint64 pb_size = 0u; - if (!in_.ReadLittleEndian64(&pb_size)) { - return false; - } - - CodedInputStream::Limit l = in_.PushLimit(static_cast<int>(pb_size)); - - // Check that we haven't tried to read past the end. - if (static_cast<uint64_t>(in_.BytesUntilLimit()) != pb_size) { - in_.PopLimit(l); - in_.PushLimit(0); - return false; - } - - if (!out_val->ParsePartialFromCodedStream(&in_)) { - in_.PopLimit(l); - in_.PushLimit(0); - return false; - } - - in_.PopLimit(l); - return true; -} - -bool CompiledFileInputStream::ReadDataMetaData(uint64_t* out_offset, uint64_t* out_len) { - EnsureAlignedRead(); - - google::protobuf::uint64 pb_size = 0u; - if (!in_.ReadLittleEndian64(&pb_size)) { - return false; - } - - // Check that we aren't trying to read past the end. - if (pb_size > static_cast<uint64_t>(in_.BytesUntilLimit())) { - in_.PushLimit(0); - return false; - } - - uint64_t offset = static_cast<uint64_t>(in_.CurrentPosition()); - if (!in_.Skip(pb_size)) { - return false; - } - - *out_offset = offset; - *out_len = pb_size; - return true; -} - -} // namespace aapt |