summaryrefslogtreecommitdiff
path: root/src/coff2bin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/coff2bin.cpp')
-rw-r--r--src/coff2bin.cpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/coff2bin.cpp b/src/coff2bin.cpp
new file mode 100644
index 0000000..6438d36
--- /dev/null
+++ b/src/coff2bin.cpp
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: Unlicense
+ */
+
+#include "coff_image.h"
+#include "data_buffer.h"
+
+#define OPTPARSE_IMPLEMENTATION
+#define OPTPARSE_API static
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#pragma GCC diagnostic ignored "-Wshadow"
+#endif
+#include "optparse/optparse.h"
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+static int Coff2Bin(FILE *input_stream, FILE *output_stream)
+{
+ auto input = DataBuffer::FromStream(input_stream);
+ const size_t input_size = input.occupied_size;
+ if (input_size == 0) {
+ fprintf(stderr, "DataBuffer::FromStream(input, input_stream): "
+ "Error: No data has been read\n");
+ return EXIT_FAILURE;
+ }
+ const COFF::Image coff(static_cast<DataBuffer&&>(input));
+ if (!coff.IsValid()) {
+ fprintf(stderr, "Error: COFF image is not valid: %s\n", coff.Error());
+ return EXIT_FAILURE;
+ }
+ const auto &file_header = coff.FileHeader();
+ if (file_header.nsections == 0) {
+ fprintf(stderr, "Error: COFF image does not contain sections\n");
+ return EXIT_FAILURE;
+ }
+ for (size_t i = 0; i < file_header.nsections; i++) {
+ const auto section = coff.GetSectionHeader(i);
+ const auto type = static_cast<COFF::SectionType>(section.flags & 0x8ff);
+ if (COFF::SectionType::Text == type) {
+ const auto data = coff.GetSectionDataView(section);
+ const size_t ret = fwrite(
+ data.buffer, data.size, 1, output_stream);
+ (void) ret;
+ assert(ret == 1);
+ break;
+ }
+ }
+ return EXIT_SUCCESS;
+}
+
+static void PrintUsage(FILE *s, const char *argv0)
+{
+ // Please, keep all lines in 80 columns range when printed.
+ fprintf(s,
+ "Usage: %s [options] <input-file-name>\n"
+ "Options:\n"
+ " -h, --help Show this message.\n"
+ " -o, --output FILE Where to write binary data to (stdout if not set).\n"
+ " <input_file_name> COFF file with the machine code to extract\n"
+ " ('-' means stdin).\n"
+ , argv0);
+}
+
+int main(int, char* argv[])
+{
+ struct optparse_long longopts[] = {
+ {"help", 'h', OPTPARSE_NONE},
+ {"output", 'o', OPTPARSE_OPTIONAL},
+ {},
+ };
+ const char *input_file_name = nullptr;
+ const char *output_file_name = nullptr;
+ struct optparse options;
+ optparse_init(&options, argv);
+ // Parse opts
+ int option;
+ while ((option = optparse_long(&options, longopts, NULL)) != -1) {
+ switch (option) {
+ case 'h':
+ PrintUsage(stdout, argv[0]);
+ return EXIT_SUCCESS;
+ break;
+ case 'o':
+ output_file_name = options.optarg;
+ break;
+ case '?':
+ fprintf(stderr, "main: optparse_long: Error: \"%s\"\n", options.errmsg);
+ return EXIT_FAILURE;
+ }
+ }
+ // Parse input file name
+ char *arg;
+ while ((arg = optparse_arg(&options))) {
+ if (input_file_name == nullptr) {
+ input_file_name = arg;
+ } else {
+ fprintf(stderr, "error: too many free arguments provided\n");
+ return EXIT_FAILURE;
+ }
+ }
+ // Open the files
+ FILE *input_stream = nullptr;
+ FILE *output_stream = stdout;
+ if (input_file_name) {
+ if (0 == strcmp(input_file_name, "-")) {
+ input_stream = stdin;
+ } else {
+ input_stream = fopen(input_file_name, "r");
+ }
+ if (input_stream == nullptr) {
+ const int err = errno;
+ fprintf(stderr,
+ "main: fopen(\"%s\", \"r\"): Error (%d): \"%s\"\n",
+ input_file_name, err, strerror(err));
+ return EXIT_FAILURE;
+ }
+ } else {
+ fprintf(stderr, "main: Error: no input file name specified, see usage below.\n");
+ PrintUsage(stderr, argv[0]);
+ return EXIT_FAILURE;
+ }
+ if (output_file_name) {
+ output_stream = fopen(output_file_name, "w");
+ if (output_stream == nullptr) {
+ const int err = errno;
+ fprintf(stderr,
+ "main: fopen(\"%s\", \"w\"): Error (%d): \"%s\"\n",
+ output_file_name, err, strerror(err));
+ fclose(input_stream);
+ return EXIT_FAILURE;
+ }
+ }
+ // Run the program
+ const int ret = Coff2Bin(input_stream, output_stream);
+ fclose(output_stream);
+ fclose(input_stream);
+ return ret;
+}