// Copyright 2017 Google Inc. All rights reserved.
//
// 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 <getopt.h>
#include <fstream>
#include <iostream>
#include "examples/xml/xml.pb.h"
#include "examples/xml/xml_writer.h"
#include "port/protobuf.h"
#include "src/text_format.h"
using protobuf_mutator::xml::Input;
namespace {
struct option const kLongOptions[] = {{"reverse", no_argument, NULL, 'r'},
{"verbose", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}};
void PrintUsage() {
std::cerr << "Usage: xml_converter [OPTION]... [INFILE [OUTFILE]]\n"
<< "Converts between proto used by fuzzer and XML.\n\n"
<< "\t-h, --help\tPrint this help\n"
<< "\t-r, --reverse\tConverts from XML to proto\n"
<< "\t-v, --verbose\tPrint input\n";
}
struct Options {
bool reverse = false;
bool verbose = false;
std::string in_file;
std::string out_file;
};
bool ParseOptions(int argc, char** argv, Options* options) {
int c = 0;
while ((c = getopt_long(argc, argv, "hrv", kLongOptions, nullptr)) != -1) {
switch (c) {
case 'v':
options->verbose = true;
break;
case 'r':
options->reverse = true;
break;
case 'h':
default:
return false;
}
}
int i = optind;
if (i < argc) options->in_file = argv[i++];
if (i < argc) options->out_file = argv[i++];
if (i != argc) return false;
return true;
}
} // namespace
int main(int argc, char** argv) {
Options options;
if (!ParseOptions(argc, argv, &options)) {
PrintUsage();
return 1;
}
std::istream* cin = &std::cin;
std::ostream* cout = &std::cout;
std::ifstream in_file_stream;
if (!options.in_file.empty()) {
in_file_stream.open(options.in_file);
cin = &in_file_stream;
}
std::ofstream out_file_stream;
if (!options.out_file.empty()) {
out_file_stream.open(options.out_file);
cout = &out_file_stream;
}
std::string input;
std::vector<char> buff(1 << 20);
while (auto size = cin->readsome(buff.data(), buff.size())) {
input += std::string(buff.data(), size);
}
std::string output;
int ret = 0;
if (options.reverse) {
Input message;
message.mutable_document()->mutable_element()->add_content()->set_char_data(
input);
output = protobuf_mutator::SaveMessageAsText(message);
} else {
Input message;
bool is_proto = protobuf_mutator::ParseTextMessage(input.data(), &message);
output = MessageToXml(message.document());
if (!is_proto) {
ret = 2;
if (options.verbose) std::cerr << "Input is not proto\n";
}
}
if (options.verbose) {
std::cerr << input << "\n\n";
std::cerr.flush();
}
*cout << output;
return ret;
}