diff options
Diffstat (limited to 'startop/view_compiler/main.cc')
-rw-r--r-- | startop/view_compiler/main.cc | 98 |
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; } |