1 // Copyright 2017 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <getopt.h>
16
17 #include <fstream>
18 #include <iostream>
19
20 #include "examples/xml/xml.pb.h"
21 #include "examples/xml/xml_writer.h"
22 #include "port/protobuf.h"
23 #include "src/text_format.h"
24
25 using protobuf_mutator::xml::Input;
26
27 namespace {
28
29 struct option const kLongOptions[] = {{"reverse", no_argument, NULL, 'r'},
30 {"verbose", no_argument, NULL, 'v'},
31 {"help", no_argument, NULL, 'h'},
32 {NULL, 0, NULL, 0}};
33
PrintUsage()34 void PrintUsage() {
35 std::cerr << "Usage: xml_converter [OPTION]... [INFILE [OUTFILE]]\n"
36 << "Converts between proto used by fuzzer and XML.\n\n"
37 << "\t-h, --help\tPrint this help\n"
38 << "\t-r, --reverse\tConverts from XML to proto\n"
39 << "\t-v, --verbose\tPrint input\n";
40 }
41
42 struct Options {
43 bool reverse = false;
44 bool verbose = false;
45 std::string in_file;
46 std::string out_file;
47 };
48
ParseOptions(int argc,char ** argv,Options * options)49 bool ParseOptions(int argc, char** argv, Options* options) {
50 int c = 0;
51 while ((c = getopt_long(argc, argv, "hrv", kLongOptions, nullptr)) != -1) {
52 switch (c) {
53 case 'v':
54 options->verbose = true;
55 break;
56 case 'r':
57 options->reverse = true;
58 break;
59 case 'h':
60 default:
61 return false;
62 }
63 }
64
65 int i = optind;
66 if (i < argc) options->in_file = argv[i++];
67 if (i < argc) options->out_file = argv[i++];
68 if (i != argc) return false;
69
70 return true;
71 }
72
73 } // namespace
74
main(int argc,char ** argv)75 int main(int argc, char** argv) {
76 Options options;
77 if (!ParseOptions(argc, argv, &options)) {
78 PrintUsage();
79 return 1;
80 }
81
82 std::istream* cin = &std::cin;
83 std::ostream* cout = &std::cout;
84
85 std::ifstream in_file_stream;
86 if (!options.in_file.empty()) {
87 in_file_stream.open(options.in_file);
88 cin = &in_file_stream;
89 }
90
91 std::ofstream out_file_stream;
92 if (!options.out_file.empty()) {
93 out_file_stream.open(options.out_file);
94 cout = &out_file_stream;
95 }
96
97 std::string input;
98 std::vector<char> buff(1 << 20);
99 while (auto size = cin->readsome(buff.data(), buff.size())) {
100 input += std::string(buff.data(), size);
101 }
102 std::string output;
103
104 int ret = 0;
105
106 if (options.reverse) {
107 Input message;
108 message.mutable_document()->mutable_element()->add_content()->set_char_data(
109 input);
110 output = protobuf_mutator::SaveMessageAsText(message);
111 } else {
112 Input message;
113 bool is_proto = protobuf_mutator::ParseTextMessage(input.data(), &message);
114 output = MessageToXml(message.document());
115 if (!is_proto) {
116 ret = 2;
117 if (options.verbose) std::cerr << "Input is not proto\n";
118 }
119 }
120
121 if (options.verbose) {
122 std::cerr << input << "\n\n";
123 std::cerr.flush();
124 }
125 *cout << output;
126
127 return ret;
128 }
129