| #include <cstddef> | |
| #include <cstdint> | |
| #include <fstream> | |
| #include <sstream> | |
| #include <string> | |
| #ifdef _WIN32 | |
| #include <fcntl.h> | |
| #else | |
| #include <unistd.h> | |
| #endif | |
| #include "google/protobuf/descriptor.pb.h" | |
| #include "absl/flags/flag.h" | |
| #include "absl/flags/parse.h" | |
| #include "absl/log/absl_log.h" | |
| #include "absl/strings/escaping.h" | |
| #include "absl/strings/str_cat.h" | |
| #include "absl/strings/string_view.h" | |
| #if defined(_WIN32) | |
| #include "google/protobuf/io/io_win32.h" | |
| // DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and | |
| // import them like we do below. | |
| using google::protobuf::io::win32::setmode; | |
| #endif | |
| ABSL_FLAG(std::string, encoding, "octal", | |
| "The encoding to use for the output."); | |
| ABSL_FLAG(std::string, defaults_path, "defaults_path", | |
| "The path to the compile_edition_defaults file to embed."); | |
| ABSL_FLAG(std::string, template_path, "template_path", | |
| "The template to use for generating the output file."); | |
| ABSL_FLAG(std::string, output_path, "output_path", | |
| "The path to the the output file."); | |
| ABSL_FLAG( | |
| std::string, placeholder, "placeholder", | |
| "The placeholder to replace with a serialized string in the template."); | |
| int defaults_escape(const std::string& defaults_path, | |
| const std::string& encoding, std::string& out_content) { | |
| std::ifstream defaults_file(defaults_path); | |
| if (!defaults_file.is_open()) { | |
| ABSL_LOG(ERROR) << "Could not open defaults file " << defaults_path; | |
| return 1; | |
| } | |
| google::protobuf::FeatureSetDefaults defaults; | |
| if (!defaults.ParseFromIstream(&defaults_file)) { | |
| ABSL_LOG(ERROR) << "Unable to parse edition defaults " << defaults_path; | |
| defaults_file.close(); | |
| return 1; | |
| } | |
| defaults_file.close(); | |
| std::string content = {}; | |
| // TODO: Remove this suppression. | |
| (void)defaults.SerializeToString(&content); | |
| if (encoding == "base64") { | |
| content = absl::Base64Escape(content); | |
| } else if (encoding == "octal") { | |
| content = absl::CEscape(content); | |
| } else if (encoding == "decimal_array") { | |
| std::string encoded; | |
| bool first = true; | |
| for (uint8_t c : content) { | |
| if (first) { | |
| first = false; | |
| absl::StrAppend(&encoded, c); | |
| } else { | |
| absl::StrAppend(&encoded, ", ", c); | |
| } | |
| } | |
| content = encoded; | |
| } else if (encoding == "hex_array") { | |
| std::string encoded = {}; | |
| size_t count = 0; | |
| for (uint8_t c : content) { | |
| absl::string_view prefix = | |
| (count % 12 != 0) ? ", 0x" : (count == 0 ? " 0x" : ",\n 0x"); | |
| absl::StrAppend(&encoded, prefix, absl::Hex(c, absl::kZeroPad2)); | |
| ++count; | |
| } | |
| content = encoded; | |
| } else { | |
| ABSL_LOG(FATAL) << "Unknown encoding: " << encoding; | |
| return 1; | |
| } | |
| out_content = content; | |
| return 0; | |
| } | |
| int read_to_string(const std::string& path, std::string& out_content) { | |
| std::ifstream input_file(path); | |
| if (!input_file.is_open()) { | |
| ABSL_LOG(ERROR) << "Could not open file " << path; | |
| return 1; | |
| } | |
| std::ostringstream buffer; | |
| buffer << input_file.rdbuf(); | |
| out_content = buffer.str(); | |
| input_file.close(); | |
| return 0; | |
| } | |
| int replace_placeholder(std::string& out_content, | |
| const std::string& placeholder, | |
| const std::string& replacement) { | |
| size_t pos = 0; | |
| while ((pos = out_content.find(placeholder, pos)) != std::string::npos) { | |
| out_content.replace(pos, placeholder.length(), replacement); | |
| pos += replacement.length(); | |
| } | |
| return 0; | |
| } | |
| int write(const std::string& path, const std::string& content) { | |
| std::ofstream output_file(path); | |
| if (!output_file.is_open()) { | |
| ABSL_LOG(ERROR) << "Could not write to file " << path; | |
| return 1; | |
| } | |
| output_file << content; | |
| output_file.close(); | |
| return 0; | |
| } | |
| int main(int argc, char* argv[]) { | |
| absl::ParseCommandLine(argc, argv); | |
| #ifdef _WIN32 | |
| setmode(STDOUT_FILENO, _O_BINARY); | |
| #endif | |
| std::string encoding = absl::GetFlag(FLAGS_encoding); | |
| std::string defaults_path = absl::GetFlag(FLAGS_defaults_path); | |
| std::string template_path = absl::GetFlag(FLAGS_template_path); | |
| std::string output_path = absl::GetFlag(FLAGS_output_path); | |
| std::string placeholder = absl::GetFlag(FLAGS_placeholder); | |
| std::string replacement = {}; | |
| if (defaults_escape(defaults_path, encoding, replacement)) { | |
| return 1; | |
| } | |
| std::string content = {}; | |
| if (read_to_string(template_path, content)) { | |
| return 1; | |
| } | |
| if (replace_placeholder(content, placeholder, replacement)) { | |
| return 1; | |
| } | |
| if (write(output_path, content)) { | |
| return 1; | |
| } | |
| return 0; | |
| } |