lin
2025-08-14 dae8bad597b6607a449b32bf76c523423f7720ed
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// 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;
}