AAPT2: Cleanup proto classes/methods and add XML serialization
Test: make aapt2_tests
Change-Id: I01ac2285af6771a683533c033a59ae6cfe875d93
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index f0ebf10..7a8a4ee 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -106,9 +106,8 @@
"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 7f5bbf0..0690dc1 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -248,8 +248,9 @@
// 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 @@
// 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 @@
// 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 @@
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 0965910..0dedc91 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 @@
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 @@
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;
+ }
+
+ BinaryResourceParser parser(context, &table, Source(file_path), data->data(), data->size());
+ if (!parser.Parse()) {
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;
- }
+ DebugPrintTableOptions options;
+ options.show_sources = true;
+ Debug::PrintTable(&table, options);
+ return true;
+ }
- table = util::make_unique<ResourceTable>();
- BinaryResourceParser parser(context, table.get(), Source(file_path), data->data(),
- data->size());
- if (!parser.Parse()) {
- return false;
- }
- }
+ err.clear();
+
+ Maybe<android::FileMap> file = file::MmapPath(file_path, &err);
+ if (!file) {
+ context->GetDiagnostics()->Error(DiagMessage(file_path) << err);
+ return false;
+ }
+
+ 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) {
- Maybe<android::FileMap> file = file::MmapPath(file_path, &err);
- if (!file) {
- context->GetDiagnostics()->Error(DiagMessage(file_path) << err);
+ // 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;
+ }
+
+ 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;
}
- android::FileMap* file_map = &file.value();
-
- // 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());
+ uint64_t offset, len;
+ if (!input.ReadDataMetaData(&offset, &len)) {
+ context->GetDiagnostics()->Warn(DiagMessage() << "failed to read meta data");
+ return false;
}
- if (!table) {
- // 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;
- }
-
- 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;
- }
- }
+ const void* data = static_cast<const uint8_t*>(file_map->getDataPtr()) + offset;
+ if (!DumpCompiledFile(compiled_file, data, len, Source(file_path), context)) {
+ return false;
}
}
-
- if (table) {
- DebugPrintTableOptions options;
- options.show_sources = true;
- Debug::PrintTable(table.get(), options);
- }
-
return true;
}
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index e3ee206d..f72069c 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 @@
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 @@
}
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 @@
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 0000000..dc13881
--- /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 0000000..3d76ea4
--- /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 18f7e1d..0000000
--- 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 714a2b2..0000000
--- 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 0000000..d36d668
--- /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 8c46642..4bf7e1c 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 @@
void EnsureAlignedWrite();
- google::protobuf::io::CodedOutputStream out_;
+ ::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_;
-};
-
-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/ProtoSerialize_test.cpp b/tools/aapt2/proto/ProtoSerialize_test.cpp
new file mode 100644
index 0000000..b263aff
--- /dev/null
+++ b/tools/aapt2/proto/ProtoSerialize_test.cpp
@@ -0,0 +1,435 @@
+/*
+ * 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 "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(ProtoSerializeTest, SerializeSinglePackage) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
+ .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
+ .AddString("com.app.a:string/text", {}, "hi")
+ .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
+ .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
+ .Build();
+
+ Symbol public_symbol;
+ public_symbol.state = SymbolState::kPublic;
+ ASSERT_TRUE(table->SetSymbolState(test::ParseNameOrDie("com.app.a:layout/main"),
+ ResourceId(0x7f020000), public_symbol,
+ context->GetDiagnostics()));
+
+ Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
+ ASSERT_THAT(id, NotNull());
+
+ // 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()));
+
+ // Make a styled string.
+ StyleString style_string;
+ style_string.str = "hello";
+ style_string.spans.push_back(Span{"b", 0u, 4u});
+ ASSERT_TRUE(
+ table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
+ util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
+ context->GetDiagnostics()));
+
+ // 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()));
+ 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()));
+
+ // 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
+ // get serialized.
+ 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()));
+
+ pb::ResourceTable pb_table;
+ SerializeTableToPb(*table, &pb_table);
+
+ 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, "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"));
+ 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"));
+ 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, "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, "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, "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, "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));
+ EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
+ EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
+ EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
+}
+
+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});
+
+ const std::string expected_data1 = "123";
+ const std::string expected_data2 = "1234";
+
+ std::string output_str;
+ {
+ pb::internal::CompiledFile pb_f1, pb_f2;
+ SerializeCompiledFileToPb(f, &pb_f1);
+
+ f.name.entry = "__" + f.name.entry + "$0";
+ 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_f1);
+ out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
+ out_file_stream.WriteCompiledFile(pb_f2);
+ out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
+ ASSERT_FALSE(out_file_stream.HadError());
+ }
+
+ CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
+ uint32_t num_files = 0;
+ ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
+ ASSERT_EQ(2u, num_files);
+
+ // Read the first compiled file.
+
+ pb::internal::CompiledFile new_pb_f1;
+ ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f1));
+
+ 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));
+
+ std::string actual_data(output_str.data() + offset, len);
+ EXPECT_EQ(expected_data1, actual_data);
+
+ // Expect the data to be aligned.
+ EXPECT_EQ(0u, offset & 0x03);
+
+ 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.
+
+ pb::internal::CompiledFile new_pb_f2;
+ ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_f2));
+
+ ResourceFile new_f2;
+ ASSERT_TRUE(DeserializeCompiledFileFromPb(new_pb_f2, &new_f2, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
+
+ actual_data = std::string(output_str.data() + offset, len);
+ EXPECT_EQ(expected_data2, actual_data);
+
+ // Expect the data to be aligned.
+ EXPECT_EQ(0u, offset & 0x03);
+}
+
+TEST(ProtoSerializeTest, DeserializeCorruptHeaderSafely) {
+ ResourceFile f;
+ pb::internal::CompiledFile pb_file;
+ SerializeCompiledFileToPb(f, &pb_file);
+
+ const std::string expected_data = "1234";
+
+ std::string output_str;
+ {
+ StringOutputStream out_stream(&output_str);
+ CompiledFileOutputStream out_file_stream(&out_stream);
+ out_file_stream.WriteLittleEndian32(1);
+ out_file_stream.WriteCompiledFile(pb_file);
+ out_file_stream.WriteData(expected_data.data(), expected_data.size());
+ ASSERT_FALSE(out_file_stream.HadError());
+ }
+
+ output_str[4] = 0xff;
+
+ CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
+
+ uint32_t num_files = 0;
+ EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
+ EXPECT_EQ(1u, num_files);
+
+ pb::internal::CompiledFile new_pb_file;
+ EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
+
+ uint64_t offset, len;
+ 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;
+ std::string error;
+ ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error));
+ ASSERT_THAT(error, IsEmpty());
+ EXPECT_EQ(expected_config, actual_config);
+}
+
+TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
+ ExpectConfigSerializes("");
+
+ ExpectConfigSerializes("mcc123");
+
+ ExpectConfigSerializes("mnc123");
+
+ ExpectConfigSerializes("en");
+ ExpectConfigSerializes("en-rGB");
+ ExpectConfigSerializes("b+en+GB");
+
+ ExpectConfigSerializes("ldltr");
+ ExpectConfigSerializes("ldrtl");
+
+ ExpectConfigSerializes("sw3600dp");
+
+ ExpectConfigSerializes("w300dp");
+
+ ExpectConfigSerializes("h400dp");
+
+ ExpectConfigSerializes("small");
+ ExpectConfigSerializes("normal");
+ ExpectConfigSerializes("large");
+ ExpectConfigSerializes("xlarge");
+
+ ExpectConfigSerializes("long");
+ ExpectConfigSerializes("notlong");
+
+ ExpectConfigSerializes("round");
+ ExpectConfigSerializes("notround");
+
+ ExpectConfigSerializes("widecg");
+ ExpectConfigSerializes("nowidecg");
+
+ ExpectConfigSerializes("highdr");
+ ExpectConfigSerializes("lowdr");
+
+ ExpectConfigSerializes("port");
+ ExpectConfigSerializes("land");
+ ExpectConfigSerializes("square");
+
+ ExpectConfigSerializes("desk");
+ ExpectConfigSerializes("car");
+ ExpectConfigSerializes("television");
+ ExpectConfigSerializes("appliance");
+ ExpectConfigSerializes("watch");
+ ExpectConfigSerializes("vrheadset");
+
+ ExpectConfigSerializes("night");
+ ExpectConfigSerializes("notnight");
+
+ ExpectConfigSerializes("300dpi");
+ ExpectConfigSerializes("hdpi");
+
+ ExpectConfigSerializes("notouch");
+ ExpectConfigSerializes("stylus");
+ ExpectConfigSerializes("finger");
+
+ ExpectConfigSerializes("keysexposed");
+ ExpectConfigSerializes("keyshidden");
+ ExpectConfigSerializes("keyssoft");
+
+ ExpectConfigSerializes("nokeys");
+ ExpectConfigSerializes("qwerty");
+ ExpectConfigSerializes("12key");
+
+ ExpectConfigSerializes("navhidden");
+ ExpectConfigSerializes("navexposed");
+
+ ExpectConfigSerializes("nonav");
+ ExpectConfigSerializes("dpad");
+ ExpectConfigSerializes("trackball");
+ ExpectConfigSerializes("wheel");
+
+ ExpectConfigSerializes("300x200");
+
+ ExpectConfigSerializes("v8");
+
+ ExpectConfigSerializes(
+ "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
+ "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp
deleted file mode 100644
index a49f6f6..0000000
--- 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 e15a0ad..0000000
--- 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
diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/TableProtoSerializer_test.cpp
deleted file mode 100644
index 8f6414c..0000000
--- a/tools/aapt2/proto/TableProtoSerializer_test.cpp
+++ /dev/null
@@ -1,336 +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 "ResourceTable.h"
-#include "test/Test.h"
-
-using ::android::StringPiece;
-using ::google::protobuf::io::StringOutputStream;
-using ::testing::Eq;
-using ::testing::NotNull;
-using ::testing::SizeIs;
-
-namespace aapt {
-
-TEST(TableProtoSerializer, SerializeSinglePackage) {
- std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
- std::unique_ptr<ResourceTable> table =
- test::ResourceTableBuilder()
- .SetPackageId("com.app.a", 0x7f)
- .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
- .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
- .AddString("com.app.a:string/text", {}, "hi")
- .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
- .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
- .Build();
-
- Symbol public_symbol;
- public_symbol.state = SymbolState::kPublic;
- ASSERT_TRUE(table->SetSymbolState(test::ParseNameOrDie("com.app.a:layout/main"),
- ResourceId(0x7f020000), public_symbol,
- context->GetDiagnostics()));
-
- Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
- ASSERT_THAT(id, NotNull());
-
- // 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()));
-
- // Make a styled string.
- StyleString style_string;
- style_string.str = "hello";
- style_string.spans.push_back(Span{"b", 0u, 4u});
- ASSERT_TRUE(
- table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
- util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
- context->GetDiagnostics()));
-
- // 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()));
- 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()));
-
- // 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
- // get serialized.
- 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()));
-
- std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(table.get());
- ASSERT_THAT(pb_table, NotNull());
-
- std::unique_ptr<ResourceTable> new_table = DeserializeTableFromPb(
- *pb_table, Source{"test"}, context->GetDiagnostics());
- ASSERT_THAT(new_table, NotNull());
-
- Id* new_id = test::GetValue<Id>(new_table.get(), "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"));
- 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"));
- 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"), "");
- 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");
- 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");
- 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");
- ASSERT_THAT(actual_styled_str, NotNull());
- EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
- ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
- EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
- EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
- EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
-}
-
-TEST(TableProtoSerializer, 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});
-
- 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);
-
- f.name.entry = "__" + f.name.entry + "$0";
- std::unique_ptr<pb::internal::CompiledFile> pb_file2 = SerializeCompiledFileToPb(f);
-
- 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.WriteData(expected_data1.data(), expected_data1.size());
- out_file_stream.WriteCompiledFile(pb_file2.get());
- out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
- ASSERT_FALSE(out_file_stream.HadError());
- }
-
- CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
- uint32_t num_files = 0;
- ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
- ASSERT_EQ(2u, num_files);
-
- // Read the first compiled file.
-
- pb::internal::CompiledFile new_pb_file;
- ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
-
- std::unique_ptr<ResourceFile> file = DeserializeCompiledFileFromPb(
- new_pb_file, Source("test"), context->GetDiagnostics());
- ASSERT_THAT(file, NotNull());
-
- uint64_t offset, len;
- ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
-
- std::string actual_data(output_str.data() + offset, len);
- EXPECT_EQ(expected_data1, actual_data);
-
- // 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);
-
- // Read the second compiled file.
-
- ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
-
- file = DeserializeCompiledFileFromPb(new_pb_file, Source("test"), context->GetDiagnostics());
- ASSERT_THAT(file, NotNull());
-
- ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
-
- actual_data = std::string(output_str.data() + offset, len);
- EXPECT_EQ(expected_data2, actual_data);
-
- // Expect the data to be aligned.
- EXPECT_EQ(0u, offset & 0x03);
-}
-
-TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
- ResourceFile f;
- std::unique_ptr<pb::internal::CompiledFile> pb_file = SerializeCompiledFileToPb(f);
-
- const std::string expected_data = "1234";
-
- std::string output_str;
- {
- 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.WriteData(expected_data.data(), expected_data.size());
- ASSERT_FALSE(out_file_stream.HadError());
- }
-
- output_str[4] = 0xff;
-
- CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
-
- uint32_t num_files = 0;
- EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
- EXPECT_EQ(1u, num_files);
-
- pb::internal::CompiledFile new_pb_file;
- EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
-
- uint64_t offset, len;
- EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
-}
-
-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));
- EXPECT_EQ(expected_config, actual_config);
-}
-
-TEST(TableProtoSerializer, SerializeDeserializeConfiguration) {
- ExpectConfigSerializes("");
-
- ExpectConfigSerializes("mcc123");
-
- ExpectConfigSerializes("mnc123");
-
- ExpectConfigSerializes("en");
- ExpectConfigSerializes("en-rGB");
- ExpectConfigSerializes("b+en+GB");
-
- ExpectConfigSerializes("ldltr");
- ExpectConfigSerializes("ldrtl");
-
- ExpectConfigSerializes("sw3600dp");
-
- ExpectConfigSerializes("w300dp");
-
- ExpectConfigSerializes("h400dp");
-
- ExpectConfigSerializes("small");
- ExpectConfigSerializes("normal");
- ExpectConfigSerializes("large");
- ExpectConfigSerializes("xlarge");
-
- ExpectConfigSerializes("long");
- ExpectConfigSerializes("notlong");
-
- ExpectConfigSerializes("round");
- ExpectConfigSerializes("notround");
-
- ExpectConfigSerializes("widecg");
- ExpectConfigSerializes("nowidecg");
-
- ExpectConfigSerializes("highdr");
- ExpectConfigSerializes("lowdr");
-
- ExpectConfigSerializes("port");
- ExpectConfigSerializes("land");
- ExpectConfigSerializes("square");
-
- ExpectConfigSerializes("desk");
- ExpectConfigSerializes("car");
- ExpectConfigSerializes("television");
- ExpectConfigSerializes("appliance");
- ExpectConfigSerializes("watch");
- ExpectConfigSerializes("vrheadset");
-
- ExpectConfigSerializes("night");
- ExpectConfigSerializes("notnight");
-
- ExpectConfigSerializes("300dpi");
- ExpectConfigSerializes("hdpi");
-
- ExpectConfigSerializes("notouch");
- ExpectConfigSerializes("stylus");
- ExpectConfigSerializes("finger");
-
- ExpectConfigSerializes("keysexposed");
- ExpectConfigSerializes("keyshidden");
- ExpectConfigSerializes("keyssoft");
-
- ExpectConfigSerializes("nokeys");
- ExpectConfigSerializes("qwerty");
- ExpectConfigSerializes("12key");
-
- ExpectConfigSerializes("navhidden");
- ExpectConfigSerializes("navexposed");
-
- ExpectConfigSerializes("nonav");
- ExpectConfigSerializes("dpad");
- ExpectConfigSerializes("trackball");
- ExpectConfigSerializes("wheel");
-
- ExpectConfigSerializes("300x200");
-
- ExpectConfigSerializes("v8");
-
- ExpectConfigSerializes(
- "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
- "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
-}
-
-} // namespace aapt