/** * 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 #include #include #include #include #include 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(strA[i])) != toupper(static_cast(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 " << std::endl; file_out << "\tusing std::size_t;" << std::endl; file_out << "#else" << std::endl; file_out << "\t#include " << std::endl; file_out << "#endif" << std::endl; if (wxWidgets_image) { file_out << "#include " << std::endl; file_out << "#include " << std::endl; file_out << "#include " << 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(file_in)), std::istreambuf_iterator()); 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(::toupper(static_cast(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 " << std::endl; out << "\tusing std::size_t;" << std::endl; out << "#else" << std::endl; out << "\t#include " << std::endl; out << "#endif" << std::endl; if (wxWidgets_image) { out << "#include " << 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] " << 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; }