Files
Goober5000 1c9066485c STL fixes and cleanup (#6455)
* fix some usages of std::transform

* change parse_string_flag_list to use a reference

* add a variant of parse_string_flag_list that can use a SCP_set, and make a templated version of flag_def_list
2024-12-16 18:12:30 +01:00

294 lines
7.6 KiB
C++

/**
* Originally written by z64555
* Adapted to use stdlib by m!m
*/
// ToDo: Review wxWidgets API to file input and output
// Correct the code so that the program will properly output text to a target .h file
// Correct the code so that the program will properly read bytes in and output as hexidecimal string values.
#include <cstring>
#include <string>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <iomanip>
bool casecmp(const char* strA, const char* strB) {
size_t lenA = strlen(strA);
if (lenA != strlen(strB)) {
return false;
}
for (size_t i = 0; i < lenA; i++) {
if (toupper(static_cast<unsigned char>(strA[i])) != toupper(static_cast<unsigned char>(strB[i]))) {
return false;
}
}
return true;
}
// Input: Filename of file to convert
// Function output: standard status codes
// Side-effect output: converted file
enum embedpng_errors {
error_none = 0,
error_cantopenfile,
error_cantoutputfile,
error_invalidargs,
error_ioerror,
};
static const size_t INPUT_BUFFER_SIZE = 1024;
typedef unsigned char ubyte;
void write_byte(std::ostream& stream, ubyte byte, size_t i) {
auto flags = stream.flags();
stream << "0x" << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << int(byte);
stream.flags(flags);
if ((i % 16) == 0) {
// End of 16-byte row
stream << "," << std::endl;
stream << "\t";
}
else {
// Somewhere within a column
stream << ", ";
}
}
void do_binary_content(std::ifstream& file_in, std::ofstream& file_out,
const std::string& field_name, size_t input_size, bool wxWidgets_image) {
file_out << "#ifdef __cplusplus" << std::endl;
file_out << "\t#include <cstddef>" << std::endl;
file_out << "\tusing std::size_t;" << std::endl;
file_out << "#else" << std::endl;
file_out << "\t#include <stddef.h>" << std::endl;
file_out << "#endif" << std::endl;
if (wxWidgets_image) {
file_out << "#include <wx/mstream.h>" << std::endl;
file_out << "#include <wx/image.h>" << std::endl;
file_out << "#include <wx/bitmap.h>" << std::endl;
file_out << std::endl;
}
file_out << "unsigned char " << field_name << "[] = " << std::endl;
file_out << "{" << std::endl;
file_out << "\t";
ubyte buffer[INPUT_BUFFER_SIZE];
size_t i = 0;
while (i < input_size) {
size_t current_size = std::min(input_size - i, INPUT_BUFFER_SIZE);
file_in.read((char*) buffer, current_size);
for (size_t j = 0; j < current_size; j++) {
i++;
write_byte(file_out, buffer[j], i);
}
}
file_out << std::endl;
file_out << "};" << std::endl;
file_out << "size_t " << field_name << "_size = sizeof(" << field_name << ");" << std::endl;
if (wxWidgets_image) {
file_out << std::endl;
file_out << "wxBitmap& " << field_name << "_to_wx_bitmap()" << std::endl;
file_out << "{" << std::endl;
file_out << "\tstatic wxMemoryInputStream memIStream( " << field_name << ", sizeof( " << field_name << " ) );"
<< std::endl;
file_out << "\tstatic wxImage image( memIStream );" << std::endl;
file_out << "\tstatic wxBitmap bmp( image );" << std::endl;
file_out << "\treturn bmp;" << std::endl;
file_out << "};" << std::endl;
}
}
void do_text_content(std::ifstream& file_in, std::ofstream& file_out,
const std::string& field_name, size_t input_size) {
const char* escapeCharacters = "\\\"\n\r";
std::string file_content;
file_content.reserve(input_size);
file_content.assign((std::istreambuf_iterator<char>(file_in)),
std::istreambuf_iterator<char>());
file_out << "const char *" << field_name << " = " << std::endl;
file_out << "\"";
size_t pos = 0;
const char* str = file_content.c_str();
while (pos < file_content.length()) {
const char* found_ptr = strpbrk(str + pos, escapeCharacters);
if (found_ptr == nullptr) {
file_out.write(str + pos, file_content.length() - pos);
break;
}
size_t found_pos = (size_t) (found_ptr - str);
size_t delta = found_pos - pos;
if (delta != 0) {
file_out.write(str + pos, delta);
}
switch (str[found_pos]) {
case '\\':
file_out << "\\\\";
break;
case '\n':
file_out << "\\n\"" << std::endl << "\"";
break;
case '"':
file_out << "\\\"";
break;
case '\r':
// Discard this character, possibly breaks on mac but whatever...
break;
default:
std::cout << "ERROR: Invalid character encountered!" << std::endl;
}
pos = found_pos + 1;
}
file_out << "\";" << std::endl;
}
void write_header(std::ostream& out, const std::string& fieldName, bool text_content, bool wxWidgets_image) {
std::string headerDefine(fieldName);
std::transform(fieldName.begin(), fieldName.end(), std::back_inserter(headerDefine),
[](char c) { return static_cast<char>(::toupper(static_cast<unsigned char>(c))); });
headerDefine = "SCP_" + headerDefine + "_H";
out << "#ifndef " << headerDefine << std::endl;
out << "#define " << headerDefine << std::endl;
out << "#pragma once" << std::endl;
out << "#ifdef __cplusplus" << std::endl;
out << "\t#include <cstddef>" << std::endl;
out << "\tusing std::size_t;" << std::endl;
out << "#else" << std::endl;
out << "\t#include <stddef.h>" << std::endl;
out << "#endif" << std::endl;
if (wxWidgets_image) {
out << "#include <wx/bitmap.h>" << std::endl;
}
out << std::endl;
if (text_content) {
out << "extern const char* " << fieldName << ";" << std::endl;
}
else {
out << "extern unsigned char " << fieldName << "[];" << std::endl;
out << "extern size_t " << fieldName << "_size;" << std::endl;
}
out << std::endl;
if (wxWidgets_image) {
out << "wxBitmap& " << fieldName << "_to_wx_bitmap();" << std::endl;
}
out << "#endif" << std::endl;
}
int main(int argc, char* argv[]) {
if (argc < 4 || argc > 6) {
std::cout << "Usage: embedfile [-wx] [-text] <inout> <output> <fieldname>" << std::endl;
return error_invalidargs;
}
bool wxWidgets_image = false;
bool text_content = false;
int argc_offset = 1;
if (casecmp(argv[argc_offset], "-wx")) {
wxWidgets_image = true;
argc_offset++;
}
if (casecmp(argv[argc_offset], "-text")) {
text_content = true;
argc_offset++;
}
std::string input_file(argv[argc_offset]);
std::string output_basename(argv[argc_offset + 1]);
std::string field_name(argv[argc_offset + 2]);
std::ios::openmode mode = std::ios::in;
if (!text_content) {
mode |= std::ios::binary;
}
std::ifstream file_in(input_file.c_str(), mode);
if (file_in.bad()) {
std::cout << "ERROR: Error opening input file: " << input_file << std::endl;
return error_cantopenfile;
}
// Get the size of the input stream
size_t input_size;
file_in.seekg(0, std::ios::end);
if ((int) file_in.tellg() != -1) {
input_size = (size_t) file_in.tellg();
}
else {
std::cout << "ERROR: Failed to get size of input file: " << input_file << std::endl;
file_in.close();
return error_ioerror;
}
file_in.seekg(0, std::ios::beg);
// Generates two files, one header and one source file
std::string headerName = output_basename + ".h";
std::string sourceName = output_basename + ".cpp";
std::ofstream source_out(sourceName.c_str());
if (source_out.bad()) {
std::cout << "ERROR: Error opening output file: " << sourceName << std::endl;
return error_cantoutputfile;
}
std::ofstream header_out(headerName.c_str());
if (header_out.bad()) {
std::cout << "ERROR: Error opening output file: " << headerName << std::endl;
return error_cantoutputfile;
}
if (text_content) {
do_text_content(file_in, source_out, field_name, input_size);
}
else {
do_binary_content(file_in, source_out, field_name, input_size, wxWidgets_image);
}
write_header(header_out, field_name, text_content, wxWidgets_image);
file_in.close();
source_out.close();
header_out.close();
return error_none;
}