summaryrefslogtreecommitdiff
path: root/startop/view_compiler/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'startop/view_compiler/main.cc')
-rw-r--r--startop/view_compiler/main.cc98
1 files changed, 74 insertions, 24 deletions
diff --git a/startop/view_compiler/main.cc b/startop/view_compiler/main.cc
index 609bcf377b46..11ecde27f5cd 100644
--- a/startop/view_compiler/main.cc
+++ b/startop/view_compiler/main.cc
@@ -16,8 +16,12 @@
#include "gflags/gflags.h"
+#include "android-base/stringprintf.h"
+#include "apk_layout_compiler.h"
#include "dex_builder.h"
+#include "dex_layout_compiler.h"
#include "java_lang_builder.h"
+#include "layout_validation.h"
#include "tinyxml_layout_parser.h"
#include "util.h"
@@ -32,49 +36,67 @@
namespace {
using namespace tinyxml2;
+using android::base::StringPrintf;
+using startop::dex::ClassBuilder;
+using startop::dex::DexBuilder;
+using startop::dex::MethodBuilder;
+using startop::dex::Prototype;
+using startop::dex::TypeDescriptor;
using namespace startop::util;
using std::string;
constexpr char kStdoutFilename[]{"stdout"};
+DEFINE_bool(apk, false, "Compile layouts in an APK");
DEFINE_bool(dex, false, "Generate a DEX file instead of Java");
+DEFINE_int32(infd, -1, "Read input from the given file descriptor");
DEFINE_string(out, kStdoutFilename, "Where to write the generated class");
DEFINE_string(package, "", "The package name for the generated class (required)");
-class ViewCompilerXmlVisitor : public XMLVisitor {
+template <typename Visitor>
+class XmlVisitorAdapter : public XMLVisitor {
public:
- explicit ViewCompilerXmlVisitor(JavaLangViewBuilder* builder) : builder_(builder) {}
+ explicit XmlVisitorAdapter(Visitor* visitor) : visitor_{visitor} {}
bool VisitEnter(const XMLDocument& /*doc*/) override {
- builder_->Start();
+ visitor_->VisitStartDocument();
return true;
}
bool VisitExit(const XMLDocument& /*doc*/) override {
- builder_->Finish();
+ visitor_->VisitEndDocument();
return true;
}
bool VisitEnter(const XMLElement& element, const XMLAttribute* /*firstAttribute*/) override {
- builder_->StartView(element.Name());
+ visitor_->VisitStartTag(
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(
+ element.Name()));
return true;
}
bool VisitExit(const XMLElement& /*element*/) override {
- builder_->FinishView();
+ visitor_->VisitEndTag();
return true;
}
private:
- JavaLangViewBuilder* builder_;
+ Visitor* visitor_;
};
+template <typename Builder>
+void CompileLayout(XMLDocument* xml, Builder* builder) {
+ startop::LayoutCompilerVisitor visitor{builder};
+ XmlVisitorAdapter<decltype(visitor)> adapter{&visitor};
+ xml->Accept(&adapter);
+}
+
} // end namespace
int main(int argc, char** argv) {
constexpr size_t kProgramName = 0;
constexpr size_t kFileNameParam = 1;
- constexpr size_t kNumRequiredArgs = 2;
+ constexpr size_t kNumRequiredArgs = 1;
gflags::SetUsageMessage(
"Compile XML layout files into equivalent Java language code\n"
@@ -83,21 +105,37 @@ int main(int argc, char** argv) {
gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags*/ true);
gflags::CommandLineFlagInfo cmd = gflags::GetCommandLineFlagInfoOrDie("package");
- if (argc != kNumRequiredArgs || cmd.is_default) {
+ if (argc < kNumRequiredArgs || cmd.is_default) {
gflags::ShowUsageWithFlags(argv[kProgramName]);
return 1;
}
- if (FLAGS_dex) {
- startop::dex::WriteTestDexFile("test.dex");
+ const bool is_stdout = FLAGS_out == kStdoutFilename;
+
+ std::ofstream outfile;
+ if (!is_stdout) {
+ outfile.open(FLAGS_out);
+ }
+
+ if (FLAGS_apk) {
+ const startop::CompilationTarget target =
+ FLAGS_dex ? startop::CompilationTarget::kDex : startop::CompilationTarget::kJavaLanguage;
+ if (FLAGS_infd >= 0) {
+ startop::CompileApkLayoutsFd(
+ android::base::unique_fd{FLAGS_infd}, target, is_stdout ? std::cout : outfile);
+ } else {
+ if (argc < 2) {
+ gflags::ShowUsageWithFlags(argv[kProgramName]);
+ return 1;
+ }
+ const char* const filename = argv[kFileNameParam];
+ startop::CompileApkLayouts(filename, target, is_stdout ? std::cout : outfile);
+ }
return 0;
}
const char* const filename = argv[kFileNameParam];
- const string layout_name = FindLayoutNameFromFilename(filename);
-
- // We want to generate Java language code to inflate exactly this layout. This means
- // generating code to walk the resource XML too.
+ const string layout_name = startop::util::FindLayoutNameFromFilename(filename);
XMLDocument xml;
xml.LoadFile(filename);
@@ -108,15 +146,27 @@ int main(int argc, char** argv) {
return 1;
}
- std::ofstream outfile;
- if (FLAGS_out != kStdoutFilename) {
- outfile.open(FLAGS_out);
+ if (FLAGS_dex) {
+ DexBuilder dex_file;
+ string class_name = StringPrintf("%s.CompiledView", FLAGS_package.c_str());
+ ClassBuilder compiled_view{dex_file.MakeClass(class_name)};
+ MethodBuilder method{compiled_view.CreateMethod(
+ layout_name,
+ Prototype{TypeDescriptor::FromClassname("android.view.View"),
+ TypeDescriptor::FromClassname("android.content.Context"),
+ TypeDescriptor::Int()})};
+ startop::DexViewBuilder builder{&method};
+ CompileLayout(&xml, &builder);
+ method.Encode();
+
+ slicer::MemView image{dex_file.CreateImage()};
+
+ (is_stdout ? std::cout : outfile).write(image.ptr<const char>(), image.size());
+ } else {
+ // Generate Java language output.
+ JavaLangViewBuilder builder{FLAGS_package, layout_name, is_stdout ? std::cout : outfile};
+
+ CompileLayout(&xml, &builder);
}
- JavaLangViewBuilder builder{
- FLAGS_package, layout_name, FLAGS_out == kStdoutFilename ? std::cout : outfile};
-
- ViewCompilerXmlVisitor visitor{&builder};
- xml.Accept(&visitor);
-
return 0;
}