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