summaryrefslogtreecommitdiff
path: root/startop/tools/view_compiler/main.cc
blob: 7d791c229a98adda660fc14cc70b991c5c1acb89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*
 * Copyright (C) 2018 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 "gflags/gflags.h"

#include "dex_builder.h"
#include "java_lang_builder.h"
#include "util.h"

#include "tinyxml2.h"

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

namespace {

using namespace tinyxml2;
using std::string;

constexpr char kStdoutFilename[]{"stdout"};

DEFINE_bool(dex, false, "Generate a DEX file instead of Java");
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 {
 public:
  ViewCompilerXmlVisitor(JavaLangViewBuilder* builder) : builder_(builder) {}

  bool VisitEnter(const XMLDocument& /*doc*/) override {
    builder_->Start();
    return true;
  }

  bool VisitExit(const XMLDocument& /*doc*/) override {
    builder_->Finish();
    return true;
  }

  bool VisitEnter(const XMLElement& element, const XMLAttribute* /*firstAttribute*/) override {
    builder_->StartView(element.Name());
    return true;
  }

  bool VisitExit(const XMLElement& /*element*/) override {
    builder_->FinishView();
    return true;
  }

 private:
  JavaLangViewBuilder* builder_;
};

}  // end namespace

int main(int argc, char** argv) {
  constexpr size_t kProgramName = 0;
  constexpr size_t kFileNameParam = 1;
  constexpr size_t kNumRequiredArgs = 2;

  gflags::SetUsageMessage(
      "Compile XML layout files into equivalent Java language code\n"
      "\n"
      "  example usage:  viewcompiler layout.xml --package com.example.androidapp");
  gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags*/ true);

  gflags::CommandLineFlagInfo cmd = gflags::GetCommandLineFlagInfoOrDie("package");
  if (argc != kNumRequiredArgs || cmd.is_default) {
    gflags::ShowUsageWithFlags(argv[kProgramName]);
    return 1;
  }

  if (FLAGS_dex) {
    startop::dex::WriteTestDexFile("test.dex");
    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.

  XMLDocument xml;
  xml.LoadFile(filename);

  std::ofstream outfile;
  if (FLAGS_out != kStdoutFilename) {
    outfile.open(FLAGS_out);
  }
  JavaLangViewBuilder builder{
      FLAGS_package, layout_name, FLAGS_out == kStdoutFilename ? std::cout : outfile};

  ViewCompilerXmlVisitor visitor{&builder};
  xml.Accept(&visitor);

  return 0;
}