diff --git a/CHANGES b/CHANGES index 892bec6..be92adb 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,7 @@ Changes for 3.1.0: * Fixed issue #64: Remove build artifacts of samples from installation packages. * Fixed issue #72: Move the code FileManager class generation code into its own IGenerator implementation. * Fixed issue #74: Invalid generated output file name: index.cpptml.cpp. +* Fixed issue #77: Refactor generating code to use full file templates with markers. Changes for 3.0.1: diff --git a/README.md b/README.md index 8b44bb0..4bee374 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Github Releases](https://img.shields.io/github/release/end2endzone/bin2cpp.svg)](https://github.com/end2endzone/bin2cpp/releases) -bin2cpp is a command line tool for embedding small files (like images, icons or raw data files) into a C++ executable. +bin2cpp is a command line tool for embedding small files (like images, icons or raw data files) into a C or C++ executable. -When executed, bin2cpp takes binary file as input and outputs c++ code (a function) that when called allows a c++ program to retrieve the content of the input binary file. +When executed, bin2cpp takes binary file as input and outputs C or C++ code (a function) that when called allows a program to retrieve the content of the input binary file. @@ -22,13 +22,6 @@ Build: | Ubuntu 20.04 | [![Build on Linux](https://github.com/end2endzone/bin2cpp/actions/workflows/build_linux.yml/badge.svg)](https://github.com/end2endzone/bin2cpp/actions/workflows/build_linux.yml) | [![Tests on Linux](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/end2endzone/58cf6c72c08e706335337d5ef9ca48e8/raw/bin2cpp.master.Linux.json)](https://github.com/end2endzone/bin2cpp/actions/workflows/build_linux.yml) | | macOS 10.15 | [![Build on macOS](https://github.com/end2endzone/bin2cpp/actions/workflows/build_macos.yml/badge.svg)](https://github.com/end2endzone/bin2cpp/actions/workflows/build_macos.yml) | [![Tests on macOS](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/end2endzone/58cf6c72c08e706335337d5ef9ca48e8/raw/bin2cpp.master.macOS.json)](https://github.com/end2endzone/bin2cpp/actions/workflows/build_macos.yml) | -Statistics: - -| AppVeyor | Travic CI | GitHub | -| ---------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| [![Statistics](https://buildstats.info/appveyor/chart/end2endzone/bin2cpp)](https://ci.appveyor.com/project/end2endzone/bin2cpp/branch/master) | [![Statistics](https://buildstats.info/travisci/chart/end2endzone/bin2cpp)](https://travis-ci.org/end2endzone/bin2cpp) | [![Statistics](https://buildstats.info/github/chart/end2endzone/bin2cpp)](https://github.com/end2endzone/bin2cpp/actions/) | - - # Purpose @@ -46,7 +39,7 @@ The generated functions that reads and extracts the embedded content does not re The main features of the project are: -* Easily converts small files as C++ source code for embedding into a C++ executable. +* Easily converts small files to C or C++ source code for embedding into an executable. * Access content with a unique function call for each embedded file. * Supports multiple embedded files at once. * Keep the directory structure when embedding directories. @@ -54,16 +47,16 @@ The main features of the project are: * Makes it harder for resource hacker to modify or steal the embedded files. * No third party libraries required for retrieving the data of the embedded files. * Supports different types of code generator: string, segment, array, win32 resources. -* File's originals `size`, `filename` and `directory` properties available from generated source code. +* File's originals `size`, `filename` and `relative path` properties available from generated source code. * Control generated source code: choose your custom _File_ interface and namespace. * Print a file encoded content to stdout. Useful for scripts and integration with third party application. -* Generated code is C++98 standard-compliant. +* Generated code is C99 or C++98 standard-compliant. ## Use cases -The following list show situations where bin2cpp is useful: +The following list show use cases where bin2cpp is useful: * Embedding default configuration files if none are provided. * Embedding GLSL shaders into the executable. diff --git a/src/bin2cpp/ArrayGenerator.cpp b/src/bin2cpp/ArrayGenerator.cpp index b43bfa2..a5c5123 100644 --- a/src/bin2cpp/ArrayGenerator.cpp +++ b/src/bin2cpp/ArrayGenerator.cpp @@ -23,10 +23,12 @@ *********************************************************************************/ #include "ArrayGenerator.h" +#include "TemplateProcessor.h" #include #include #include #include +#include #include "rapidassist/code_cpp.h" #include "rapidassist/strings.h" @@ -47,147 +49,57 @@ namespace bin2cpp return "array"; } - bool ArrayGenerator::createCppSourceFile(const char * cpp_file_path) + bool ArrayGenerator::createCppSourceFile(const char * file_path) { //check if input file exists - FILE * input = fopen(mContext.inputFilePath.c_str(), "rb"); - if (!input) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Uppercase function identifier - std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(getContext().functionIdentifier); - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(cpp_file_path); - std::string cppPath = cpp_file_path; - - //create cpp file - FILE * cpp = fopen(cppPath.c_str(), "w"); - if (!cpp) - { - fclose(input); - return false; - } - - //determine file properties - uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); - - //Build class name - std::string className = getClassName(); - - //Build function - std::string getterFunctionName = getGetterFunctionName(); - - //write cpp file heading - fprintf(cpp, "%s", getHeaderTemplate().c_str()); - fprintf(cpp, "#include \"%s\"\n", mContext.headerFilename.c_str() ); - fprintf(cpp, "#include \n"); - fprintf(cpp, "#include //for ofstream\n"); - fprintf(cpp, "namespace %s\n", getContext().codeNamespace.c_str()); - fprintf(cpp, "{\n"); - fprintf(cpp, " class %s : public virtual %s::%s\n", className.c_str(), getContext().codeNamespace.c_str(), getContext().baseClass.c_str()); - fprintf(cpp, " {\n"); - fprintf(cpp, " public:\n"); - fprintf(cpp, " %s() {}\n", className.c_str()); - fprintf(cpp, " virtual ~%s() {}\n", className.c_str()); - fprintf(cpp, " virtual size_t getSize() const { return %u; }\n", fileSize); - fprintf(cpp, " virtual const char * getFileName() const { %s }\n", getImplOfGetFileName().c_str()); - fprintf(cpp, " virtual const char * getFilePath() const { %s }\n", getImplOfGetFilePath().c_str()); - fprintf(cpp, " virtual const char * getBuffer() const\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " static const unsigned char buffer[] = {\n"); - - //create buffer for each chunks from input buffer - int numLinePrinted = 0; - unsigned char * buffer = new unsigned char[getContext().chunkSize]; - while(!feof(input)) - { - //read a chunk of the file - size_t readSize = fread(buffer, 1, getContext().chunkSize, input); - - bool isLastChunk = !(readSize == getContext().chunkSize); - - if (readSize > 0) - { - if (numLinePrinted > 0) - { - //end previous line - fprintf(cpp, ",\n"); - } - - //output - fprintf(cpp, " %s", ra::code::cpp::ToCppCharactersArray(buffer, readSize).c_str()); - numLinePrinted++; - } - - //end the array. all the file content is printed - if (isLastChunk) - { - fprintf(cpp, "\n"); - fprintf(cpp, " };\n"); - } - } - delete[] buffer; - buffer = NULL; - - //write cpp source file footer - fprintf(cpp, " return (const char *)buffer;\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, "%s", getSaveMethodTemplate().c_str()); - fprintf(cpp, " };\n"); - fprintf(cpp, " const %s & %s() { static %s _instance; return _instance; }\n", getContext().baseClass.c_str(), getterFunctionName.c_str(), className.c_str()); - if (mContext.registerFiles) - { - std::string fileManagerTemplate = getCppFileManagerRegistrationImplementationTemplate(); - fprintf(cpp, "%s", fileManagerTemplate.c_str()); - } - fprintf(cpp, "}; //%s\n", getContext().codeNamespace.c_str()); - - fclose(input); - fclose(cpp); - - return true; + const std::string text = "" + "${bin2cpp_output_file_header_template}" + "#include \"${bin2cpp_header_file_include_path}\"\n" + "#include \n" + "#include //for ofstream\n" + "namespace ${bin2cpp_namespace}\n" + "{\n" + " class ${bin2cpp_classname} : public virtual ${bin2cpp_namespace}::${bin2cpp_baseclass}\n" + " {\n" + " public:\n" + " ${bin2cpp_classname}() {}\n" + " virtual ~${bin2cpp_classname}() {}\n" + " virtual size_t getSize() const { return ${bin2cpp_input_file_size}; }\n" + " virtual const char * getFileName() const { return \"${bin2cpp_file_object_file_name}\"; }\n" + " virtual const char * getFilePath() const { return \"${bin2cpp_file_object_file_path}\"; }\n" + " virtual const char * getBuffer() const\n" + " {\n" + " static const unsigned char buffer[] = {\n${bin2cpp_insert_input_file_as_code}" // INPUT FILE AS CODE HERE + " };\n" + " return (const char *)buffer;\n" + " }\n" + "${bin2cpp_cpp_save_method_template}" + " };\n" + " const ${bin2cpp_baseclass} & ${bin2cpp_file_object_getter_function_name}() { static ${bin2cpp_classname} _instance; return _instance; }\n" + "${bin2cpp_file_manager_cpp_registration_implementation}" + "}; //${bin2cpp_namespace}\n"; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; } bool ArrayGenerator::printFileContent() { //check if input file exists - FILE * input = fopen(mContext.inputFilePath.c_str(), "rb"); - if (!input) + if (!ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //determine file properties - uint32_t fileSize = ra::filesystem::GetFileSize(input); - - //create buffer for each chunks from input buffer - int numLinePrinted = 0; - unsigned char * buffer = new unsigned char[getContext().chunkSize]; - while(!feof(input)) - { - //read a chunk of the file - size_t readSize = fread(buffer, 1, getContext().chunkSize, input); - - bool isLastChunk = !(readSize == getContext().chunkSize); + std::ostringstream output_stream; + writeInputFileDataAsCode(output_stream); + std::string str = output_stream.str(); - if (readSize > 0) - { - if (numLinePrinted > 0) - { - //end previous line - printf("\n"); - } - - //output - std::string text = ra::code::cpp::ToCppCharactersArray(buffer, readSize); - printf("\"%s\"", text.c_str()); - numLinePrinted++; - } - } - delete[] buffer; - buffer = NULL; - - fclose(input); + printf("\"%s\"", str.c_str()); return true; } @@ -195,163 +107,112 @@ namespace bin2cpp bool ArrayGenerator::createCSourceFile(const char* file_path) { //check if input file exists - FILE* input = fopen(mContext.inputFilePath.c_str(), "rb"); - if ( !input ) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; + + const std::string text = "" + "${bin2cpp_output_file_header_template}" + "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n" + "#define _CRT_SECURE_NO_WARNINGS\n" + "#endif\n" + "#include \"${bin2cpp_header_file_include_path}\"\n" + "#include // for malloc\n" + "#include // for memset\n" + "#include // for fopen\n" + "static ${bin2cpp_baseclass} ${bin2cpp_function_identifier_lowercase}_file = { 0 };\n" + "static bool ${bin2cpp_function_identifier_lowercase}_initialized = false;\n" + "\n" + "${bin2cpp_file_manager_c_registration_predeclaration}" + "bool ${bin2cpp_function_identifier_lowercase}_load()\n" + "{\n" + " if ( ${bin2cpp_function_identifier_lowercase}_file.buffer )\n" + " return true;\n" + " static const unsigned char static_buffer[] = {\n${bin2cpp_insert_input_file_as_code}" // INPUT FILE AS CODE HERE + " };\n" + "\n" + " ${bin2cpp_function_identifier_lowercase}_file.buffer = static_buffer;\n" + " return true;\n" + "}\n" + "\n" + "void ${bin2cpp_function_identifier_lowercase}_free()\n" + "{\n" + " ${bin2cpp_function_identifier_lowercase}_file.buffer = NULL;\n" + "}\n" + "\n" + "bool ${bin2cpp_function_identifier_lowercase}_save(const char* path)\n" + "{\n" + " if ( !${bin2cpp_function_identifier_lowercase}_file.buffer )\n" + " return false;\n" + " FILE* f = fopen(path, \"wb\");\n" + " if ( !f )\n" + " return false;\n" + " size_t write_size = fwrite(${bin2cpp_function_identifier_lowercase}_file.buffer, 1, ${bin2cpp_function_identifier_lowercase}_file.size, f);\n" + " fclose(f);\n" + " if ( write_size != ${bin2cpp_function_identifier_lowercase}_file.size )\n" + " return false;\n" + " return true;\n" + "}\n" + "\n" + "static inline void ${bin2cpp_function_identifier_lowercase}_init()\n" + "{\n" + " // remember we already initialized\n" + " if ( ${bin2cpp_function_identifier_lowercase}_initialized )\n" + " return;\n" + " ${bin2cpp_function_identifier_lowercase}_initialized = true;\n" + "\n" + " // initialize\n" + " ${bin2cpp_baseclass}* file = &${bin2cpp_function_identifier_lowercase}_file;\n" + " file->size = ${bin2cpp_input_file_size}ULL;\n" + " file->file_name = \"${bin2cpp_file_object_file_name}\";\n" + " file->file_path = \"${bin2cpp_file_object_file_path}\";\n" + " file->buffer = NULL;\n" + " file->load = ${bin2cpp_function_identifier_lowercase}_load;\n" + " file->unload = ${bin2cpp_function_identifier_lowercase}_free;\n" + " file->save = ${bin2cpp_function_identifier_lowercase}_save;\n" + "\n" + " // load file by default on init as in c++ implementation\n" + " file->load();\n" + "${bin2cpp_file_manager_c_registration_post_init_implementation}" + "}\n" + "\n" + "${bin2cpp_baseclass}* ${bin2cpp_file_object_getter_function_name}(void)\n" + "{\n" + " ${bin2cpp_function_identifier_lowercase}_init();\n" + " return &${bin2cpp_function_identifier_lowercase}_file;\n" + "}\n" + "${bin2cpp_file_manager_c_registration_implementation}"; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; + } - //Lowercase function identifier - std::string functionIdentifier = ra::strings::Lowercase(mContext.functionIdentifier); - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(file_path); - std::string sourcePath = file_path; - - //create c source file - FILE* fout = fopen(sourcePath.c_str(), "w"); - if ( !fout ) - { - fclose(input); - return false; - } - - //determine file properties - uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); - //long lastSegmentSize = fileSize%chunk_size; - //size_t numSegments = fileSize/chunk_size + (lastSegmentSize == 0 ? 0 : 1); - - //Build class name - std::string className = getClassName(); - - //Build function - std::string getterFunctionName = getGetterFunctionName(); - - //Build FileManager class template - std::string manager = mContext.managerHeaderFilename; - - //write c file heading - fprintf(fout, "%s", getHeaderTemplate().c_str()); - fprintf(fout, "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n"); - fprintf(fout, "#define _CRT_SECURE_NO_WARNINGS\n"); - fprintf(fout, "#endif\n"); - fprintf(fout, "#include \"%s\"\n", mContext.headerFilename.c_str()); - fprintf(fout, "#include // for malloc\n"); - fprintf(fout, "#include // for memset\n"); - fprintf(fout, "#include // for fopen\n"); - - fprintf(fout, "static %s %s_file = { 0 };\n", mContext.baseClass.c_str(), functionIdentifier.c_str()); - fprintf(fout, "static bool %s_initialized = false;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - - // File registration predeclaration code - fprintf(fout, "%s", getCFileManagerRegistrationPredeclarationTemplate().c_str()); - - fprintf(fout, "bool %s_load()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( %s_file.buffer )\n", functionIdentifier.c_str()); - fprintf(fout, " return true;\n"); - fprintf(fout, " static const unsigned char static_buffer[] = {\n"); - - //create buffer for each chunks from input buffer - int numLinePrinted = 0; - unsigned char* buffer = new unsigned char[getContext().chunkSize]; - while ( !feof(input) ) - { - //read a chunk of the file - size_t readSize = fread(buffer, 1, getContext().chunkSize, input); - - bool isLastChunk = !(readSize == getContext().chunkSize); - - if ( readSize > 0 ) - { - if ( numLinePrinted > 0 ) - { - //end previous line - fprintf(fout, ",\n"); - } - - //output - fprintf(fout, " %s", ra::code::cpp::ToCppCharactersArray(buffer, readSize).c_str()); - numLinePrinted++; - } - - //end the array. all the file content is printed - if ( isLastChunk ) - { - fprintf(fout, "\n"); - fprintf(fout, " };\n"); - } - } - delete[] buffer; - buffer = NULL; - - //write c source file footer - fprintf(fout, "\n"); - fprintf(fout, " %s_file.buffer = static_buffer;\n", functionIdentifier.c_str()); - fprintf(fout, " return true;\n"); - fprintf(fout, "}\n"); - - fprintf(fout, "\n"); - - fprintf(fout, "void %s_free()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " %s_file.buffer = NULL;\n", functionIdentifier.c_str()); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "bool %s_save(const char* path)\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( !%s_file.buffer )\n", functionIdentifier.c_str()); - fprintf(fout, " return false;\n"); - fprintf(fout, " FILE* f = fopen(path, \"wb\");\n"); - fprintf(fout, " if ( !f )\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " size_t write_size = fwrite(%s_file.buffer, 1, %s_file.size, f);\n", functionIdentifier.c_str(), functionIdentifier.c_str()); - fprintf(fout, " fclose(f);\n"); - fprintf(fout, " if ( write_size != %s_file.size )\n", functionIdentifier.c_str()); - fprintf(fout, " return false;\n"); - fprintf(fout, " return true;\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "static inline void %s_init()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " // remember we already initialized\n"); - fprintf(fout, " if ( %s_initialized )\n", functionIdentifier.c_str()); - fprintf(fout, " return;\n"); - fprintf(fout, " %s_initialized = true;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - fprintf(fout, " // initialize\n"); - fprintf(fout, " %s* file = &%s_file;\n", mContext.baseClass.c_str(), functionIdentifier.c_str()); - fprintf(fout, " file->size = %uULL;\n", fileSize); - fprintf(fout, " file->file_name = \"%s\";\n", getFileClassFileName().c_str()); - fprintf(fout, " file->file_path = \"%s\";\n", getFileClassFilePath().c_str()); - fprintf(fout, " file->buffer = NULL;\n"); - fprintf(fout, " file->load = %s_load;\n", functionIdentifier.c_str()); - fprintf(fout, " file->unload = %s_free;\n", functionIdentifier.c_str()); - fprintf(fout, " file->save = %s_save;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - fprintf(fout, " // load file by default on init as in c++ implementation"); - fprintf(fout, " file->load();\n"); - if ( mContext.registerFiles ) - { - fprintf(fout, " \n"); - fprintf(fout, " // register when loaded if static initialisation does not work\n"); - fprintf(fout, " %s_filemanager_register_file(file);\n", mContext.codeNamespace.c_str()); - } - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "%s* %s(void)\n", mContext.baseClass.c_str(), getGetterFunctionName().c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " %s_init();\n", functionIdentifier.c_str()); - fprintf(fout, " return &%s_file;\n", functionIdentifier.c_str()); - fprintf(fout, "}\n"); - - // File registration implementation code - fprintf(fout, "%s", getCFileManagerRegistrationImplementationTemplate().c_str()); - - fclose(input); - fclose(fout); - - return true; + void ArrayGenerator::writeInputFileChunkAsCode(const unsigned char * buffer, size_t buffer_size, size_t index, size_t count, bool is_last_chunk, std::ostream& output) + { + size_t indentation = 0; + + if ( mContext.plainOutput ) + indentation = 0; + else if ( mContext.code == CodeGenerationEnum::CODE_GENERATION_CPP ) + indentation = 8; + else if ( mContext.code == CodeGenerationEnum::CODE_GENERATION_C ) + indentation = 4; + + std::string str; + if ( indentation ) + str += std::string(indentation, ' '); + if ( mContext.plainOutput ) + str += "\""; + str += ra::code::cpp::ToCppCharactersArray(buffer, buffer_size); + if ( mContext.plainOutput ) + str += "\""; + if ( !is_last_chunk ) + str += ","; + str += "\n"; + + output << str; } }; //bin2cpp \ No newline at end of file diff --git a/src/bin2cpp/ArrayGenerator.h b/src/bin2cpp/ArrayGenerator.h index 46ec570..7093a9d 100644 --- a/src/bin2cpp/ArrayGenerator.h +++ b/src/bin2cpp/ArrayGenerator.h @@ -40,9 +40,10 @@ namespace bin2cpp ArrayGenerator(); virtual ~ArrayGenerator(); virtual const char * getName() const; - virtual bool createCppSourceFile(const char * cpp_file_path); - virtual bool createCSourceFile(const char * cpp_file_path); + virtual bool createCppSourceFile(const char * file_path); + virtual bool createCSourceFile(const char * file_path); virtual bool printFileContent(); + virtual void writeInputFileChunkAsCode(const unsigned char * buffer, size_t buffer_size, size_t index, size_t count, bool is_last_chunk, std::ostream& output); }; }; //bin2cpp diff --git a/src/bin2cpp/BaseGenerator.cpp b/src/bin2cpp/BaseGenerator.cpp index 980fefa..0ea6536 100755 --- a/src/bin2cpp/BaseGenerator.cpp +++ b/src/bin2cpp/BaseGenerator.cpp @@ -23,6 +23,7 @@ *********************************************************************************/ #include "BaseGenerator.h" +#include "TemplateProcessor.h" #include #include #include @@ -55,11 +56,50 @@ namespace bin2cpp return mContext; } + bool BaseGenerator::lookupStringVariable(const std::string& name, std::string& output) + { + if ( name == "bin2cpp_baseclass" ) { output = mContext.baseClass; return true; } + if ( name == "bin2cpp_classname" ) { output = getClassName(); return true; } + if ( name == "bin2cpp_cpp_save_method_template" ) { output = getCppSaveMethodTemplate(); return true; } + if ( name == "bin2cpp_file_manager_c_registration_implementation" && mContext.registerFiles ) { output = getCFileManagerStaticFileRegistrationImplementation(); return true; } + if ( name == "bin2cpp_file_manager_c_registration_post_init_implementation" && mContext.registerFiles ) { output = getCFileManagerRegistrationPostInitImplementation(); return true; } + if ( name == "bin2cpp_file_manager_c_registration_predeclaration" && mContext.registerFiles ) { output = getCFileManagerRegistrationPredeclarationImplementation(); return true; } + if ( name == "bin2cpp_file_manager_cpp_registration_implementation" && mContext.registerFiles ) { output = getCppFileManagerRegistrationImplementationTemplate(); return true; } + if ( name == "bin2cpp_file_manager_file_header" ) { output = getHeaderTemplate(false); return true; } + if ( name == "bin2cpp_file_manager_header_file_name" ) { output = mContext.managerHeaderFilename; return true; } + if ( name == "bin2cpp_file_manager_macro_guard_prefix" ) { output = getFileManagerMacroGuardPrefix(); return true; } + if ( name == "bin2cpp_file_object_file_name" ) { output = getFileObjectFileName(); return true; } + if ( name == "bin2cpp_file_object_file_path" ) { output = getFileObjectFilePath(); return true; } + if ( name == "bin2cpp_file_object_getter_function_name" ) { output = getFileObjectGetterFunctionName(); return true; } + if ( name == "bin2cpp_file_object_macro_guard_prefix" ) { output = getClassMacroGuardPrefix(); return true; } + if ( name == "bin2cpp_function_identifier_lowercase" ) { output = ra::strings::Lowercase(mContext.functionIdentifier); return true; } + if ( name == "bin2cpp_function_identifier" ) { output = mContext.functionIdentifier; return true; } + if ( name == "bin2cpp_header_file_include_path" ) { output = getHeaderFileIncludePath(); return true; } + if ( name == "bin2cpp_input_file_size" ) { output = ra::strings::ToString(ra::filesystem::GetFileSize(mContext.inputFilePath.c_str())); return true; } + if ( name == "bin2cpp_namespace" ) { output = mContext.codeNamespace; return true; } + if ( name == "bin2cpp_output_file_header_template" ) { output = getHeaderTemplate(); return true; } + if ( name == "bin2cpp_output_file_macro_guard" ) { output = getIncludeGuardMacroName(mContext.headerFilename); return true; } + + // Unknown name + return false; + } + + bool BaseGenerator::lookupStreamVariable(const std::string& name, std::ostream& output) + { + if ( name == "bin2cpp_insert_input_file_as_code" ) + { + writeInputFileDataAsCode(output); + return true; + } + + return false; + } + //------------------------------- //protected methods //------------------------------- - std::string BaseGenerator::getGetterFunctionName() + std::string BaseGenerator::getFileObjectGetterFunctionName() { std::string getter; @@ -151,7 +191,7 @@ namespace bin2cpp return header; } - std::string BaseGenerator::getSaveMethodTemplate() + std::string BaseGenerator::getCppSaveMethodTemplate() { std::string output; output << " virtual bool save(const char * filename) const\n"; @@ -178,11 +218,12 @@ namespace bin2cpp std::string output; output << " typedef const " << mContext.baseClass << " & (*t_func)();\n"; output << " extern bool RegisterFile(t_func iFunctionPointer);\n"; - output << " static bool k" << className << "Registered = " << mContext.codeNamespace << "::RegisterFile(&" << getGetterFunctionName() << ");\n"; + output << " static bool k" << className << "Registered = " << mContext.codeNamespace << "::RegisterFile(&" << getFileObjectGetterFunctionName() << ");\n"; + output << " \n"; return output; } - std::string BaseGenerator::getCFileManagerRegistrationPredeclarationTemplate() + std::string BaseGenerator::getCFileManagerRegistrationPredeclarationImplementation() { if ( !mContext.registerFiles ) return std::string(); @@ -193,7 +234,7 @@ namespace bin2cpp return output; } - std::string BaseGenerator::getCFileManagerRegistrationImplementationTemplate() + std::string BaseGenerator::getCFileManagerStaticFileRegistrationImplementation() { if ( !mContext.registerFiles ) return std::string(); @@ -202,21 +243,31 @@ namespace bin2cpp std::string functionIdentifier = ra::strings::Lowercase(mContext.functionIdentifier); std::string output; + output << "\n"; output << "#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) // GCC 4.0+ required, Clang supports it by default\n"; output << "__attribute__((constructor))\n"; output << "#endif\n"; - output << "void " << mContext.codeNamespace << "_register_file_static_init_" << functionIdentifier << "(void)\n"; + output << "void " << mContext.codeNamespace << "_" << functionIdentifier << "_register_file_static_init(void)\n"; output << "{\n"; output << " " << mContext.baseClass << "* this_file = " << mContext.codeNamespace << "_get_file_" << functionIdentifier << "();\n"; output << " " << mContext.codeNamespace << "_filemanager_register_file(this_file);\n"; output << "}\n"; output << "#if _MSC_VER >= 1920 // Visual Studio 2019 or later\n"; output << "#pragma section(\".CRT$XCU\", read)\n"; - output << "__declspec(allocate(\".CRT$XCU\")) void (*init_ptr_" << functionIdentifier << ")(void) = " << mContext.codeNamespace << "_register_file_static_init_" << functionIdentifier << ";\n"; + output << "__declspec(allocate(\".CRT$XCU\")) void (*init_ptr_" << mContext.codeNamespace << "_" << functionIdentifier << ")(void) = " << mContext.codeNamespace << "_" << functionIdentifier << "_register_file_static_init" << ";\n"; output << "#endif\n"; return output; } + std::string BaseGenerator::getCFileManagerRegistrationPostInitImplementation() + { + std::string output; + output += " \n"; + output += " // register when loaded if static initialisation does not work\n"; + output += " ${bin2cpp_namespace}_filemanager_register_file(file);\n"; + return output; + } + std::string BaseGenerator::getClassName() { std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(mContext.functionIdentifier); @@ -236,34 +287,29 @@ namespace bin2cpp return macroGuardPrefix; } - std::string BaseGenerator::getImplOfGetFileName() + std::string BaseGenerator::getFileManagerMacroGuardPrefix() { + //define macro guard a macro matching the filename std::string output; + output += getIncludeGuardMacroName(mContext.codeNamespace.c_str()); //prefix the custom namespace for the file manager + if ( !output.empty() ) + output += "_"; + output += getIncludeGuardMacroName(mContext.managerHeaderFilename); + return output; + } - std::string inputFileName = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); + std::string BaseGenerator::getFileObjectFileName() + { + std::string output; - //could we report getFileName() as a substring of getFilePath() ? - const char * reported_path = mContext.reportedFilePath.c_str(); - if (reported_path != NULL && reported_path[0] != '\0') - { - size_t offset = mContext.reportedFilePath.find(inputFileName); - if (offset != std::string::npos) - { - output = "return &getFilePath()["; - output += ra::strings::ToString(offset); - output += "];"; - return output; - } - } + std::string inputFileName = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); //return default implementation - output = "return \""; output += inputFileName; - output += "\";"; return output; } - std::string BaseGenerator::getImplOfGetFilePath() + std::string BaseGenerator::getFileObjectFilePath() { std::string output; @@ -280,111 +326,105 @@ namespace bin2cpp const char * reported_path = mContext.reportedFilePath.c_str(); if (reported_path != NULL && reported_path[0] != '\0') { - output = "return \""; output += path; - output += "\";"; return output; } else { //if reported path is not specified ? //report the same as getFileName() - output = "return getFileName();"; + output = getFileObjectFileName(); return output; } //return default implementation - output = "return \""; output += path; - output += "\";"; return output; } - std::string BaseGenerator::getFileClassFileName() + std::string BaseGenerator::getHeaderFileIncludePath() { - std::string output; - - std::string inputFileName = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); - - //return default implementation - output += inputFileName; - return output; + return mContext.headerFilename; } - std::string BaseGenerator::getFileClassFilePath() + void BaseGenerator::writeInputFileDataAsCode(std::ostream& output) { - std::string output; + //check if input file exists + FILE* fin = fopen(mContext.inputFilePath.c_str(), "rb"); + if ( !fin ) + return; - //convert mReportedFilePath string to c++ - std::string path = mContext.reportedFilePath; -#ifdef _WIN32 - //escape backslash characters for c++ - static const std::string BACKSLASH = "\\"; - static const std::string BACKSLASH_ESCAPED = "\\\\"; - ra::strings::Replace(path, BACKSLASH, BACKSLASH_ESCAPED); -#endif + uint64_t fileSize = ra::filesystem::GetFileSize64(mContext.inputFilePath.c_str()); + size_t chunkCount = fileSize / mContext.chunkSize; + if ( fileSize % mContext.chunkSize > 0 ) + chunkCount++; - //is there a reported path specified ? - const char * reported_path = mContext.reportedFilePath.c_str(); - if (reported_path != NULL && reported_path[0] != '\0') - { - output += path; - return output; - } - else + //create buffer for each chunks from input buffer + int numLinePrinted = 0; + size_t chunkIndex = 0; + unsigned char* buffer = new unsigned char[mContext.chunkSize]; + while ( !feof(fin) ) { - //if reported path is not specified ? - //report the same as getFileName() - output = getFileClassFileName(); - return output; + //read a chunk of the file + size_t readSize = fread(buffer, 1, mContext.chunkSize, fin); + + bool isLastChunk = (chunkIndex == (chunkCount - 1)); + + if ( readSize > 0 ) + { + //append chunk as code in output stream + writeInputFileChunkAsCode(buffer, readSize, chunkIndex, chunkCount, isLastChunk, output); + + numLinePrinted++; + chunkIndex++; + } + } + delete[] buffer; + buffer = NULL; - //return default implementation - output += path; - return output; + fclose(fin); } - bool BaseGenerator::createCppHeaderFile(const char * header_file_path) + void BaseGenerator::writeInputFileChunkAsCode(const unsigned char* buffer, size_t buffer_size, size_t index, size_t count, bool is_last_chunk, std::ostream& output) { - FILE * header = fopen(header_file_path, "w"); - if (!header) - return false; - - //define macro guard matching the filename - std::string macroGuard = getCppIncludeGuardMacroName(header_file_path); - - std::string classMacroGuardPrefix = getClassMacroGuardPrefix(); - std::string fileHeader = getHeaderTemplate(); - - fprintf(header, "%s", fileHeader.c_str()); - fprintf(header, "#ifndef %s\n", macroGuard.c_str()); - fprintf(header, "#define %s\n", macroGuard.c_str()); - fprintf(header, "\n"); - fprintf(header, "#include \n"); - fprintf(header, "\n"); - fprintf(header, "namespace %s\n", mContext.codeNamespace.c_str()); - fprintf(header, "{\n"); - fprintf(header, " #ifndef %s_EMBEDDEDFILE_CLASS\n", classMacroGuardPrefix.c_str()); - fprintf(header, " #define %s_EMBEDDEDFILE_CLASS\n", classMacroGuardPrefix.c_str()); - fprintf(header, " class %s\n", mContext.baseClass.c_str()); - fprintf(header, " {\n"); - fprintf(header, " public:\n"); - fprintf(header, " virtual size_t getSize() const = 0;\n"); - fprintf(header, " /* DEPRECATED */ virtual inline const char * getFilename() const { return getFileName(); }\n"); - fprintf(header, " virtual const char * getFileName() const = 0;\n"); - fprintf(header, " virtual const char * getFilePath() const = 0;\n"); - fprintf(header, " virtual const char * getBuffer() const = 0;\n"); - fprintf(header, " virtual bool save(const char * filename) const = 0;\n"); - fprintf(header, " };\n"); - fprintf(header, " #endif //%s_EMBEDDEDFILE_CLASS\n", classMacroGuardPrefix.c_str()); - fprintf(header, " const %s & %s();\n", mContext.baseClass.c_str(), getGetterFunctionName().c_str()); - fprintf(header, "}; //%s\n", mContext.codeNamespace.c_str()); - fprintf(header, "\n"); - fprintf(header, "#endif //%s\n", macroGuard.c_str()); - - fclose(header); + } - return true; + bool BaseGenerator::createCppHeaderFile(const char * header_file_path) + { + const std::string text = "" + "${bin2cpp_output_file_header_template}" + "#ifndef ${bin2cpp_output_file_macro_guard}\n" + "#define ${bin2cpp_output_file_macro_guard}\n" + "\n" + "#include \n" + "\n" + "namespace ${bin2cpp_namespace}\n" + "{\n" + " #ifndef ${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_CLASS\n" + " #define ${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_CLASS\n" + " class ${bin2cpp_baseclass}\n" + " {\n" + " public:\n" + " virtual size_t getSize() const = 0;\n" + " /* DEPRECATED */ virtual inline const char * getFilename() const { return getFileName(); }\n" + " virtual const char * getFileName() const = 0;\n" + " virtual const char * getFilePath() const = 0;\n" + " virtual const char * getBuffer() const = 0;\n" + " virtual bool save(const char * filename) const = 0;\n" + " };\n" + " #endif //${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_CLASS\n" + " const ${bin2cpp_baseclass} & ${bin2cpp_file_object_getter_function_name}();\n" + "}; //${bin2cpp_namespace}\n" + "\n" + "#endif //${bin2cpp_output_file_macro_guard}\n" + ; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(header_file_path); + + return write_success; } bool BaseGenerator::printFileContent() @@ -441,48 +481,42 @@ namespace bin2cpp bool BaseGenerator::createCHeaderFile(const char* file_path) { - FILE* header = fopen(file_path, "w"); - if ( !header ) - return false; - - //define macro guard matching the filename - std::string macroGuard = getCppIncludeGuardMacroName(file_path); - - std::string classMacroGuardPrefix = getClassMacroGuardPrefix(); - std::string fileHeader = getHeaderTemplate(); - - fprintf(header, "%s", fileHeader.c_str()); - fprintf(header, "#ifndef %s\n", macroGuard.c_str()); - fprintf(header, "#define %s\n", macroGuard.c_str()); - fprintf(header, "\n"); - fprintf(header, "#include \n"); - fprintf(header, "#include \n"); - fprintf(header, "\n"); - fprintf(header, "#ifndef %s_EMBEDDEDFILE_STRUCT\n", classMacroGuardPrefix.c_str()); - fprintf(header, "#define %s_EMBEDDEDFILE_STRUCT\n", classMacroGuardPrefix.c_str()); - fprintf(header, "typedef struct %s %s;\n", mContext.baseClass.c_str(), mContext.baseClass.c_str()); - fprintf(header, "typedef bool(*%s_load_func)();\n", mContext.codeNamespace.c_str()); - fprintf(header, "typedef void(*%s_free_func)();\n", mContext.codeNamespace.c_str()); - fprintf(header, "typedef bool(*%s_save_func)(const char*);\n", mContext.codeNamespace.c_str()); - fprintf(header, "typedef struct %s\n", mContext.baseClass.c_str()); - fprintf(header, "{\n"); - fprintf(header, " size_t size;\n"); - fprintf(header, " const char* file_name;\n"); - fprintf(header, " const char* file_path;\n"); - fprintf(header, " const unsigned char* buffer;\n"); - fprintf(header, " %s_load_func load;\n", mContext.codeNamespace.c_str()); - fprintf(header, " %s_free_func unload;\n", mContext.codeNamespace.c_str()); - fprintf(header, " %s_save_func save;\n", mContext.codeNamespace.c_str()); - fprintf(header, "} %s;\n", mContext.baseClass.c_str()); - fprintf(header, "typedef %s* %sPtr;\n", mContext.baseClass.c_str(), mContext.baseClass.c_str()); - fprintf(header, "#endif //%s_EMBEDDEDFILE_STRUCT\n", classMacroGuardPrefix.c_str()); - fprintf(header, "%s* %s(void);\n", mContext.baseClass.c_str(), getGetterFunctionName().c_str()); - fprintf(header, "\n"); - fprintf(header, "#endif //%s\n", macroGuard.c_str()); - - fclose(header); - - return true; + const std::string text = "" + "${bin2cpp_output_file_header_template}" + "#ifndef ${bin2cpp_output_file_macro_guard}\n" + "#define ${bin2cpp_output_file_macro_guard}\n" + "\n" + "#include \n" + "#include \n" + "\n" + "#ifndef ${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_STRUCT\n" + "#define ${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_STRUCT\n" + "typedef struct ${bin2cpp_baseclass} ${bin2cpp_baseclass};\n" + "typedef bool(*${bin2cpp_namespace}_load_func)();\n" + "typedef void(*${bin2cpp_namespace}_free_func)();\n" + "typedef bool(*${bin2cpp_namespace}_save_func)(const char*);\n" + "typedef struct ${bin2cpp_baseclass}\n" + "{\n" + " size_t size;\n" + " const char* file_name;\n" + " const char* file_path;\n" + " const unsigned char* buffer;\n" + " ${bin2cpp_namespace}_load_func load;\n" + " ${bin2cpp_namespace}_free_func unload;\n" + " ${bin2cpp_namespace}_save_func save;\n" + "} ${bin2cpp_baseclass};\n" + "typedef ${bin2cpp_baseclass}* ${bin2cpp_baseclass}Ptr;\n" + "#endif //${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_STRUCT\n" + "${bin2cpp_baseclass}* ${bin2cpp_file_object_getter_function_name}(void);\n" + "\n" + "#endif //${bin2cpp_output_file_macro_guard}\n" + ; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; } bool BaseGenerator::createCSourceFile(const char* file_path) diff --git a/src/bin2cpp/BaseGenerator.h b/src/bin2cpp/BaseGenerator.h index 31473df..ba9ae4c 100644 --- a/src/bin2cpp/BaseGenerator.h +++ b/src/bin2cpp/BaseGenerator.h @@ -26,6 +26,7 @@ #define BASEGENERATOR_H #include "IGenerator.h" +#include namespace bin2cpp { @@ -43,6 +44,10 @@ namespace bin2cpp virtual void setContext(const Context& c); virtual const Context & getContext() const; + //ITemplateVariableLookup methods + virtual bool lookupStringVariable(const std::string& name, std::string& output); + virtual bool lookupStreamVariable(const std::string& name, std::ostream& output); + //same header file for all generators virtual bool createCppHeaderFile(const char * header_file_path); virtual bool printFileContent(); @@ -51,21 +56,24 @@ namespace bin2cpp protected: - virtual std::string getGetterFunctionName(); + virtual std::string getFileObjectGetterFunctionName(); virtual std::string getHeaderFilePath(const char * cpp_file_path); virtual std::string getCppFilePath(const char * header_file_path); virtual std::string getHeaderTemplate(); virtual std::string getHeaderTemplate(bool include_source_file); - virtual std::string getSaveMethodTemplate(); + virtual std::string getCppSaveMethodTemplate(); virtual std::string getCppFileManagerRegistrationImplementationTemplate(); - virtual std::string getCFileManagerRegistrationPredeclarationTemplate(); - virtual std::string getCFileManagerRegistrationImplementationTemplate(); + virtual std::string getCFileManagerRegistrationPredeclarationImplementation(); + virtual std::string getCFileManagerStaticFileRegistrationImplementation(); + virtual std::string getCFileManagerRegistrationPostInitImplementation(); virtual std::string getClassName(); virtual std::string getClassMacroGuardPrefix(); - virtual std::string getImplOfGetFileName(); - virtual std::string getImplOfGetFilePath(); - virtual std::string getFileClassFileName(); - virtual std::string getFileClassFilePath(); + virtual std::string getFileManagerMacroGuardPrefix(); + virtual std::string getFileObjectFileName(); + virtual std::string getFileObjectFilePath(); + virtual std::string getHeaderFileIncludePath(); + virtual void writeInputFileDataAsCode(std::ostream& output); + virtual void writeInputFileChunkAsCode(const unsigned char * buffer, size_t buffer_size, size_t index, size_t count, bool is_last_chunk, std::ostream& output); //attributes Context mContext; diff --git a/src/bin2cpp/CMakeLists.txt b/src/bin2cpp/CMakeLists.txt index 326f03b..c21f1b5 100644 --- a/src/bin2cpp/CMakeLists.txt +++ b/src/bin2cpp/CMakeLists.txt @@ -22,6 +22,7 @@ add_executable(bin2cpp enums.h IGenerator.h INameProvider.h + ITemplateVariableLookup.h LegacyNameProvider.cpp LegacyNameProvider.h main.cpp @@ -31,6 +32,8 @@ add_executable(bin2cpp SegmentGenerator.h StringGenerator.cpp StringGenerator.h + TemplateProcessor.cpp + TemplateProcessor.h types.h wildcard.cpp wildcard.h diff --git a/src/bin2cpp/IGenerator.h b/src/bin2cpp/IGenerator.h index 5b459cb..da7ca54 100644 --- a/src/bin2cpp/IGenerator.h +++ b/src/bin2cpp/IGenerator.h @@ -27,11 +27,12 @@ #include #include "Context.h" - +#include "ITemplateVariableLookup.h" + namespace bin2cpp { - class IGenerator + class IGenerator : public virtual ITemplateVariableLookup { public: diff --git a/src/bin2cpp/ITemplateVariableLookup.h b/src/bin2cpp/ITemplateVariableLookup.h new file mode 100644 index 0000000..33d251b --- /dev/null +++ b/src/bin2cpp/ITemplateVariableLookup.h @@ -0,0 +1,63 @@ +/********************************************************************************** + * MIT License + * + * Copyright (c) 2018 Antoine Beauchamp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *********************************************************************************/ + +#ifndef ITEMPLATE_VARIABLE_LOOKUP_H +#define ITEMPLATE_VARIABLE_LOOKUP_H + +#include +#include + +namespace bin2cpp +{ + + class ITemplateVariableLookup + { + public: + virtual ~ITemplateVariableLookup() + {} + + /// + ///Lookup the string value for a given template variable name. + ///String template variables supports recursive lookup. + /// + ///The name of the template variable. + ///The output string for getting the value or the template variable. + ///Returns true when the template variable is handled by the instance. Returns false otherwise. + virtual bool lookupStringVariable(const std::string& name, std::string& output) = 0; + + /// + ///Lookup the string value for a given template variable name. + ///Stream template variables do not support template variables recursive lookup. + ///If a streams loopup outputs text such as `${foo}`, it will not be processed and will be output as literal string `${foo}`. + /// + ///The name of the template variable. + ///The output string for getting the value or the template variable. + ///Returns true when the template variable is handled by the instance. Returns false otherwise. + virtual bool lookupStreamVariable(const std::string& name, std::ostream& output) = 0; + + }; + +}; //bin2cpp + +#endif //ITEMPLATE_VARIABLE_LOOKUP_H diff --git a/src/bin2cpp/ManagerGenerator.cpp b/src/bin2cpp/ManagerGenerator.cpp index fa38a8f..e5825ae 100644 --- a/src/bin2cpp/ManagerGenerator.cpp +++ b/src/bin2cpp/ManagerGenerator.cpp @@ -23,6 +23,7 @@ *********************************************************************************/ #include "ManagerGenerator.h" +#include "TemplateProcessor.h" #include #include #include @@ -45,425 +46,393 @@ namespace bin2cpp return "manager"; } - bool ManagerGenerator::createCppHeaderFile(const char* header_file_path) + bool ManagerGenerator::createCppHeaderFile(const char* file_path) { - FILE* header = fopen(header_file_path, "w"); - if ( !header ) - return false; + const std::string text = "" + "${bin2cpp_file_manager_file_header}" + "#ifndef ${bin2cpp_file_manager_macro_guard_prefix}\n" + "#define ${bin2cpp_file_manager_macro_guard_prefix}\n" + "\n" + "#include \n" + "#include \n" + "\n" + "namespace ${bin2cpp_namespace}\n" + "{\n" + " #ifndef ${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_CLASS\n" + " #define ${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_CLASS\n" + " class ${bin2cpp_baseclass}\n" + " {\n" + " public:\n" + " virtual size_t getSize() const = 0;\n" + " /* DEPRECATED */ virtual inline const char * getFilename() const { return getFileName(); }\n" + " virtual const char * getFileName() const = 0;\n" + " virtual const char * getFilePath() const = 0;\n" + " virtual const char * getBuffer() const = 0;\n" + " virtual bool save(const char * filename) const = 0;\n" + " };\n" + " #endif //${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_CLASS\n" + "\n" + " #ifndef ${bin2cpp_file_object_macro_guard_prefix}_FILEMANAGER_CLASS\n" + " #define ${bin2cpp_file_object_macro_guard_prefix}_FILEMANAGER_CLASS\n" + " class FileManager\n" + " {\n" + " private:\n" + " FileManager();\n" + " ~FileManager();\n" + " public:\n" + " typedef const ${bin2cpp_baseclass} & (*t_func)();\n" + " static FileManager & getInstance();\n" + " void registerFile(t_func func);\n" + " size_t getFileCount() const;\n" + " const ${bin2cpp_baseclass} * getFile(const size_t & index) const;\n" + " bool saveFiles(const char * directory) const;\n" + " bool createParentDirectories(const char * file_path) const;\n" + " bool createDirectories(const char * path) const;\n" + " private:\n" + " std::vector functions_;\n" + " };\n" + " #endif //${bin2cpp_file_object_macro_guard_prefix}_FILEMANAGER_CLASS\n" + "}; //${bin2cpp_namespace}\n" + "\n" + "#endif //${bin2cpp_file_manager_macro_guard_prefix}\n" + ; - //define macro guard a macro matching the filename - std::string macroGuard; - macroGuard += getCppIncludeGuardMacroName(mContext.codeNamespace.c_str()); //prefix the custom namespace for the file manager - if ( !macroGuard.empty() ) - macroGuard += "_"; - macroGuard += getCppIncludeGuardMacroName(header_file_path); + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); - std::string classMacroGuardPrefix = getClassMacroGuardPrefix(); - std::string fileHeader = getHeaderTemplate(false); - - fprintf(header, "%s", fileHeader.c_str()); - fprintf(header, "#ifndef %s\n", macroGuard.c_str()); - fprintf(header, "#define %s\n", macroGuard.c_str()); - fprintf(header, "\n"); - fprintf(header, "#include \n"); - fprintf(header, "#include \n"); - fprintf(header, "\n"); - fprintf(header, "namespace %s\n", mContext.codeNamespace.c_str()); - fprintf(header, "{\n"); - fprintf(header, " #ifndef %s_EMBEDDEDFILE_CLASS\n", classMacroGuardPrefix.c_str()); - fprintf(header, " #define %s_EMBEDDEDFILE_CLASS\n", classMacroGuardPrefix.c_str()); - fprintf(header, " class %s\n", mContext.baseClass.c_str()); - fprintf(header, " {\n"); - fprintf(header, " public:\n"); - fprintf(header, " virtual size_t getSize() const = 0;\n"); - fprintf(header, " /* DEPRECATED */ virtual inline const char * getFilename() const { return getFileName(); }\n"); - fprintf(header, " virtual const char * getFileName() const = 0;\n"); - fprintf(header, " virtual const char * getFilePath() const = 0;\n"); - fprintf(header, " virtual const char * getBuffer() const = 0;\n"); - fprintf(header, " virtual bool save(const char * filename) const = 0;\n"); - fprintf(header, " };\n"); - fprintf(header, " #endif //%s_EMBEDDEDFILE_CLASS\n", classMacroGuardPrefix.c_str()); - fprintf(header, "\n"); - fprintf(header, " #ifndef %s_FILEMANAGER_CLASS\n", classMacroGuardPrefix.c_str()); - fprintf(header, " #define %s_FILEMANAGER_CLASS\n", classMacroGuardPrefix.c_str()); - fprintf(header, " class FileManager\n"); - fprintf(header, " {\n"); - fprintf(header, " private:\n"); - fprintf(header, " FileManager();\n"); - fprintf(header, " ~FileManager();\n"); - fprintf(header, " public:\n"); - fprintf(header, " typedef const %s & (*t_func)();\n", mContext.baseClass.c_str()); - fprintf(header, " static FileManager & getInstance();\n"); - fprintf(header, " void registerFile(t_func func);\n"); - fprintf(header, " size_t getFileCount() const;\n"); - fprintf(header, " const %s * getFile(const size_t & index) const;\n", mContext.baseClass.c_str()); - fprintf(header, " bool saveFiles(const char * directory) const;\n"); - fprintf(header, " bool createParentDirectories(const char * file_path) const;\n"); - fprintf(header, " bool createDirectories(const char * path) const;\n"); - fprintf(header, " private:\n"); - fprintf(header, " std::vector functions_;\n"); - fprintf(header, " };\n"); - fprintf(header, " #endif //%s_FILEMANAGER_CLASS\n", classMacroGuardPrefix.c_str()); - fprintf(header, "}; //%s\n", mContext.codeNamespace.c_str()); - fprintf(header, "\n"); - fprintf(header, "#endif //%s\n", macroGuard.c_str()); - - fclose(header); - - return true; + return write_success; } - bool ManagerGenerator::createCppSourceFile(const char* cpp_file_path) + bool ManagerGenerator::createCppSourceFile(const char* file_path) { - FILE* cpp = fopen(cpp_file_path, "w"); - if ( !cpp ) - return false; - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(cpp_file_path); - std::string cppPath = cpp_file_path; - - std::string fileHeader = getHeaderTemplate(false); - - fprintf(cpp, "%s", fileHeader.c_str()); - fprintf(cpp, "#include \"%s\"\n", mContext.managerHeaderFilename.c_str()); - fprintf(cpp, "#include \n"); - fprintf(cpp, "#include // strlen\n"); - fprintf(cpp, "#include // stat\n"); - fprintf(cpp, "#include // errno, EEXIST\n"); - fprintf(cpp, "#if defined(_WIN32)\n"); - fprintf(cpp, "#include // _mkdir\n"); - fprintf(cpp, "#endif\n"); - fprintf(cpp, "\n"); - fprintf(cpp, "#if defined(_WIN32)\n"); - fprintf(cpp, "#define portable_stat _stat\n"); - fprintf(cpp, "#define portable_mkdir(path) _mkdir(path)\n"); - fprintf(cpp, "#define PATH_SEPARATOR_CHAR '\\\\'\n"); - fprintf(cpp, "#define PATH_SEPARATOR_STR \"\\\\\"\n"); - fprintf(cpp, "#else\n"); - fprintf(cpp, "#define portable_stat stat\n"); - fprintf(cpp, "#define portable_mkdir(path) mkdir(path, 0755)\n"); - fprintf(cpp, "#define PATH_SEPARATOR_CHAR '/'\n"); - fprintf(cpp, "#define PATH_SEPARATOR_STR \"/\"\n"); - fprintf(cpp, "#endif\n"); - fprintf(cpp, "\n"); - fprintf(cpp, "namespace %s\n", mContext.codeNamespace.c_str()); - fprintf(cpp, "{\n"); - fprintf(cpp, " bool RegisterFile(FileManager::t_func functionPointer)\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " if (functionPointer == NULL)\n"); - fprintf(cpp, " return false;\n"); - fprintf(cpp, " FileManager::getInstance().registerFile(functionPointer);\n"); - fprintf(cpp, " return true;\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " FileManager::FileManager() {}\n"); - fprintf(cpp, " FileManager::~FileManager() {}\n"); - fprintf(cpp, " FileManager & FileManager::getInstance() { static FileManager _mgr; return _mgr; }\n"); - fprintf(cpp, " void FileManager::registerFile(t_func func) { functions_.push_back(func); }\n"); - fprintf(cpp, " size_t FileManager::getFileCount() const { return functions_.size(); }\n"); - fprintf(cpp, " const File * FileManager::getFile(const size_t & index) const\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " if (index >= functions_.size())\n"); - fprintf(cpp, " return NULL;\n"); - fprintf(cpp, " t_func ressource_getter_function = functions_[index];\n"); - fprintf(cpp, " const %s::File & resource = ressource_getter_function();\n", mContext.codeNamespace.c_str()); - fprintf(cpp, " return &resource;\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " bool FileManager::saveFiles(const char * directory) const\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " if (directory == NULL)\n"); - fprintf(cpp, " return false;\n"); - fprintf(cpp, " size_t count = getFileCount();\n"); - fprintf(cpp, " for(size_t i=0; igetFilePath());\n"); - fprintf(cpp, " if (!createParentDirectories(path.c_str()))\n"); - fprintf(cpp, " return false;\n"); - fprintf(cpp, " bool saved = f->save(path.c_str());\n"); - fprintf(cpp, " if (!saved)\n"); - fprintf(cpp, " return false;\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " return true;\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " static inline bool isRootDirectory(const char * path)\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " if (path == NULL && path[0] == '\\0')\n"); - fprintf(cpp, " return false;\n"); - fprintf(cpp, " #if defined(_WIN32)\n"); - fprintf(cpp, " bool isDriveLetter = ((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z'));\n"); - fprintf(cpp, " if ((isDriveLetter && path[1] == ':' && path[2] == '\\0') || // test for C:\n"); - fprintf(cpp, " (isDriveLetter && path[1] == ':' && path[2] == PATH_SEPARATOR_CHAR && path[3] == '\\0')) // test for C:\\ \n"); - fprintf(cpp, " return true;\n"); - fprintf(cpp, " #else\n"); - fprintf(cpp, " if (path[0] == PATH_SEPARATOR_CHAR)\n"); - fprintf(cpp, " return true;\n"); - fprintf(cpp, " #endif\n"); - fprintf(cpp, " return false;\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " bool FileManager::createParentDirectories(const char * file_path) const\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " if (file_path == NULL)\n"); - fprintf(cpp, " return false;\n"); - fprintf(cpp, " std::string accumulator;\n"); - fprintf(cpp, " size_t length = strlen(file_path);\n"); - fprintf(cpp, " for(size_t i=0; i\n" + "#include // strlen\n" + "#include // stat\n" + "#include // errno, EEXIST\n" + "#if defined(_WIN32)\n" + "#include // _mkdir\n" + "#endif\n" + "\n" + "#if defined(_WIN32)\n" + "#define portable_stat _stat\n" + "#define portable_mkdir(path) _mkdir(path)\n" + "#define PATH_SEPARATOR_CHAR '\\\\'\n" + "#define PATH_SEPARATOR_STR \"\\\\\"\n" + "#else\n" + "#define portable_stat stat\n" + "#define portable_mkdir(path) mkdir(path, 0755)\n" + "#define PATH_SEPARATOR_CHAR '/'\n" + "#define PATH_SEPARATOR_STR \"/\"\n" + "#endif\n" + "\n" + "namespace ${bin2cpp_namespace}\n" + "{\n" + " bool RegisterFile(FileManager::t_func functionPointer)\n" + " {\n" + " if (functionPointer == NULL)\n" + " return false;\n" + " FileManager::getInstance().registerFile(functionPointer);\n" + " return true;\n" + " }\n" + " FileManager::FileManager() {}\n" + " FileManager::~FileManager() {}\n" + " FileManager & FileManager::getInstance() { static FileManager _mgr; return _mgr; }\n" + " void FileManager::registerFile(t_func func) { functions_.push_back(func); }\n" + " size_t FileManager::getFileCount() const { return functions_.size(); }\n" + " const File * FileManager::getFile(const size_t & index) const\n" + " {\n" + " if (index >= functions_.size())\n" + " return NULL;\n" + " t_func ressource_getter_function = functions_[index];\n" + " const ${bin2cpp_namespace}::File & resource = ressource_getter_function();\n" + " return &resource;\n" + " }\n" + " bool FileManager::saveFiles(const char * directory) const\n" + " {\n" + " if (directory == NULL)\n" + " return false;\n" + " size_t count = getFileCount();\n" + " for(size_t i=0; igetFilePath());\n" + " if (!createParentDirectories(path.c_str()))\n" + " return false;\n" + " bool saved = f->save(path.c_str());\n" + " if (!saved)\n" + " return false;\n" + " }\n" + " return true;\n" + " }\n" + " static inline bool isRootDirectory(const char * path)\n" + " {\n" + " if (path == NULL && path[0] == '\\0')\n" + " return false;\n" + " #if defined(_WIN32)\n" + " bool isDriveLetter = ((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z'));\n" + " if ((isDriveLetter && path[1] == ':' && path[2] == '\\0') || // test for C:\n" + " (isDriveLetter && path[1] == ':' && path[2] == PATH_SEPARATOR_CHAR && path[3] == '\\0')) // test for C:\\ \n" + " return true;\n" + " #else\n" + " if (path[0] == PATH_SEPARATOR_CHAR)\n" + " return true;\n" + " #endif\n" + " return false;\n" + " }\n" + " bool FileManager::createParentDirectories(const char * file_path) const\n" + " {\n" + " if (file_path == NULL)\n" + " return false;\n" + " std::string accumulator;\n" + " size_t length = strlen(file_path);\n" + " for(size_t i=0; i\n" + "#include \n" + "\n" + "#ifndef ${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_STRUCT\n" + "#define ${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_STRUCT\n" + "typedef struct ${bin2cpp_baseclass} ${bin2cpp_baseclass};\n" + "typedef bool(*${bin2cpp_namespace}_load_func)();\n" + "typedef void(*${bin2cpp_namespace}_free_func)();\n" + "typedef bool(*${bin2cpp_namespace}_save_func)(const char*);\n" + "typedef struct ${bin2cpp_baseclass}\n" + "{\n" + " size_t size;\n" + " const char* file_name;\n" + " const char* file_path;\n" + " const unsigned char* buffer;\n" + " ${bin2cpp_namespace}_load_func load;\n" + " ${bin2cpp_namespace}_free_func unload;\n" + " ${bin2cpp_namespace}_save_func save;\n" + "} ${bin2cpp_baseclass};\n" + "typedef ${bin2cpp_baseclass}* ${bin2cpp_baseclass}Ptr;\n" + "#endif //${bin2cpp_file_object_macro_guard_prefix}_FILE_OBJECT_STRUCT\n" + "\n" + "size_t ${bin2cpp_namespace}_filemanager_get_file_count();\n" + "bool ${bin2cpp_namespace}_filemanager_register_file(${bin2cpp_baseclass}* file);\n" + "const ${bin2cpp_baseclass}* ${bin2cpp_namespace}_filemanager_get_file(size_t index);\n" + "bool ${bin2cpp_namespace}_filemanager_save_files(const char* directory);\n" + "\n" + "#endif //${bin2cpp_file_manager_macro_guard_prefix}\n" + ; - //define macro guard a macro matching the filename - std::string macroGuard; - macroGuard += getCppIncludeGuardMacroName(mContext.codeNamespace.c_str()); //prefix the custom namespace for the file manager - if ( !macroGuard.empty() ) - macroGuard += "_"; - macroGuard += getCppIncludeGuardMacroName(file_path); + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); - std::string classMacroGuardPrefix = getClassMacroGuardPrefix(); - std::string fileHeader = getHeaderTemplate(false); - - fprintf(fout, "%s", fileHeader.c_str()); - fprintf(fout, "#ifndef %s\n", macroGuard.c_str()); - fprintf(fout, "#define %s\n", macroGuard.c_str()); - fprintf(fout, "\n"); - fprintf(fout, "#include \n"); - fprintf(fout, "#include \n"); - fprintf(fout, "\n"); - fprintf(fout, "#ifndef %s_EMBEDDEDFILE_STRUCT\n", classMacroGuardPrefix.c_str()); - fprintf(fout, "#define %s_EMBEDDEDFILE_STRUCT\n", classMacroGuardPrefix.c_str()); - fprintf(fout, "typedef struct %s %s;\n", mContext.baseClass.c_str(), mContext.baseClass.c_str()); - fprintf(fout, "typedef bool(*%s_load_func)();\n", mContext.codeNamespace.c_str()); - fprintf(fout, "typedef void(*%s_free_func)();\n", mContext.codeNamespace.c_str()); - fprintf(fout, "typedef bool(*%s_save_func)(const char*);\n", mContext.codeNamespace.c_str()); - fprintf(fout, "typedef struct %s\n", mContext.baseClass.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " size_t size;\n"); - fprintf(fout, " const char* file_name;\n"); - fprintf(fout, " const char* file_path;\n"); - fprintf(fout, " const unsigned char* buffer;\n"); - fprintf(fout, " %s_load_func load;\n", mContext.codeNamespace.c_str()); - fprintf(fout, " %s_free_func unload;\n", mContext.codeNamespace.c_str()); - fprintf(fout, " %s_save_func save;\n", mContext.codeNamespace.c_str()); - fprintf(fout, "} %s;\n", mContext.baseClass.c_str()); - fprintf(fout, "typedef %s* %sPtr;\n", mContext.baseClass.c_str(), mContext.baseClass.c_str()); - fprintf(fout, "#endif //%s_EMBEDDEDFILE_STRUCT\n", classMacroGuardPrefix.c_str()); - fprintf(fout, "\n"); - fprintf(fout, "size_t %s_filemanager_get_file_count();\n", mContext.codeNamespace.c_str()); - fprintf(fout, "bool %s_filemanager_register_file(%s* file);\n", mContext.codeNamespace.c_str(), mContext.baseClass.c_str()); - fprintf(fout, "const %s* %s_filemanager_get_file(size_t index);\n", mContext.baseClass.c_str(), mContext.codeNamespace.c_str()); - fprintf(fout, "bool %s_filemanager_save_files(const char* directory);\n", mContext.codeNamespace.c_str()); - fprintf(fout, "\n"); - fprintf(fout, "#endif //%s\n", macroGuard.c_str()); - - fclose(fout); - - return true; + return write_success; } bool ManagerGenerator::createCSourceFile(const char* file_path) { - FILE* fout = fopen(file_path, "w"); - if ( !fout ) - return false; - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(file_path); - std::string sourcePath = file_path; - - std::string fileHeader = getHeaderTemplate(false); - - fprintf(fout, "%s", fileHeader.c_str()); - fprintf(fout, "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n"); - fprintf(fout, "#define _CRT_SECURE_NO_WARNINGS\n"); - fprintf(fout, "#endif\n"); - fprintf(fout, "\n"); - fprintf(fout, "#include \"%s\"\n", mContext.managerHeaderFilename.c_str()); - fprintf(fout, "#include // for malloc\n"); - fprintf(fout, "#include // for snprintf()\n"); - fprintf(fout, "#include // strlen\n"); - fprintf(fout, "#include // stat\n"); - fprintf(fout, "#include // errno, EEXIST\n"); - fprintf(fout, "#if defined(_WIN32)\n"); - fprintf(fout, "#include // _mkdir\n"); - fprintf(fout, "#endif\n"); - fprintf(fout, "#if defined(_WIN32)\n"); - fprintf(fout, "#define portable_stat _stat\n"); - fprintf(fout, "#define portable_mkdir(path) _mkdir(path)\n"); - fprintf(fout, "#define PATH_SEPARATOR_CHAR '\\\\'\n"); - fprintf(fout, "#define PATH_SEPARATOR_STR \"\\\\\"\n"); - fprintf(fout, "#else\n"); - fprintf(fout, "#define portable_stat stat\n"); - fprintf(fout, "#define portable_mkdir(path) mkdir(path, 0755)\n"); - fprintf(fout, "#define PATH_SEPARATOR_CHAR '/'\n"); - fprintf(fout, "#define PATH_SEPARATOR_STR \"/\"\n"); - fprintf(fout, "#endif\n"); - fprintf(fout, "\n"); - fprintf(fout, "#define BIN2C_MAX_PATH 32767\n"); - fprintf(fout, "\n"); - fprintf(fout, "static %s** registered_files = NULL;\n", mContext.baseClass.c_str()); - fprintf(fout, "static size_t registered_files_count = 0;\n"); - fprintf(fout, "\n"); - fprintf(fout, "size_t %s_filemanager_get_file_count()\n", mContext.codeNamespace.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " return registered_files_count;\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "bool %s_filemanager_register_file(%s* file)\n", mContext.codeNamespace.c_str(), mContext.baseClass.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " // check if already registered\n"); - fprintf(fout, " if ( registered_files_count && registered_files )\n"); - fprintf(fout, " {\n"); - fprintf(fout, " for ( size_t i = 0; i < registered_files_count; i++ )\n"); - fprintf(fout, " {\n"); - fprintf(fout, " const %s* existing_file = registered_files[i];\n", mContext.baseClass.c_str()); - fprintf(fout, " if ( existing_file == file )\n"); - fprintf(fout, " return true; // nothing to do\n"); - fprintf(fout, " }\n"); - fprintf(fout, " }\n"); - fprintf(fout, " \n"); - fprintf(fout, " // allocate ram\n"); - fprintf(fout, " size_t new_ram_size = sizeof(%s**) * (registered_files_count + 1);\n", mContext.baseClass.c_str()); - fprintf(fout, " %s** tmp = NULL;\n", mContext.baseClass.c_str()); - fprintf(fout, " if ( registered_files == NULL )\n"); - fprintf(fout, " tmp = (%s**)malloc(new_ram_size);\n", mContext.baseClass.c_str()); - fprintf(fout, " else\n"); - fprintf(fout, " tmp = (%s**)realloc(registered_files, new_ram_size);\n", mContext.baseClass.c_str()); - fprintf(fout, " if ( tmp == NULL )\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " \n"); - fprintf(fout, " registered_files = tmp;\n"); - fprintf(fout, " registered_files_count++;\n"); - fprintf(fout, " \n"); - fprintf(fout, " // insert\n"); - fprintf(fout, " registered_files[registered_files_count - 1] = file;\n"); - fprintf(fout, " \n"); - fprintf(fout, " return true;\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "const %s* %s_filemanager_get_file(size_t index)\n", mContext.baseClass.c_str(), mContext.codeNamespace.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( index >= registered_files_count )\n"); - fprintf(fout, " return NULL;\n"); - fprintf(fout, " return registered_files[index];\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "static inline bool %s_filemanager_is_root_directory(const char* path)\n", mContext.codeNamespace.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( path == NULL && path[0] == '\\0' )\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, "#if defined(_WIN32)\n"); - fprintf(fout, " bool is_drive_letter = ((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z'));\n"); - fprintf(fout, " if ( (is_drive_letter && path[1] == ':' && path[2] == '\\0') || // test for C:\n"); - fprintf(fout, " (is_drive_letter && path[1] == ':' && path[2] == PATH_SEPARATOR_CHAR && path[3] == '\\0') ) // test for C:\\ \n"); - fprintf(fout, " return true;\n"); - fprintf(fout, "#else\n"); - fprintf(fout, " if ( path[0] == PATH_SEPARATOR_CHAR )\n"); - fprintf(fout, " return true;\n"); - fprintf(fout, "#endif\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "bool %s_filemanager_create_parent_directories(const char* file_path)\n", mContext.codeNamespace.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( file_path == NULL )\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " char* accumulator = (char*)malloc(BIN2C_MAX_PATH);\n"); - fprintf(fout, " if ( accumulator == NULL )\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " accumulator[0] = '\\0';\n"); - fprintf(fout, " size_t length = strlen(file_path);\n"); - fprintf(fout, " for ( size_t i = 0; i < length; i++ )\n"); - fprintf(fout, " {\n"); - fprintf(fout, " if ( file_path[i] == PATH_SEPARATOR_CHAR && !(accumulator[0] == '\\0') && !%s_filemanager_is_root_directory(accumulator) )\n", mContext.codeNamespace.c_str()); - fprintf(fout, " {\n"); - fprintf(fout, " int ret = portable_mkdir(accumulator);\n"); - fprintf(fout, " if ( ret != 0 && errno != EEXIST )\n"); - fprintf(fout, " {\n"); - fprintf(fout, " free(accumulator);\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " }\n"); - fprintf(fout, " }\n"); - fprintf(fout, " \n"); - fprintf(fout, " // append\n"); - fprintf(fout, " char tmp[] = { file_path[i], '\\0' };\n"); - fprintf(fout, " strcat(accumulator, tmp);\n"); - fprintf(fout, " }\n"); - fprintf(fout, " free(accumulator);\n"); - fprintf(fout, " return true;\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "bool %s_filemanager_save_files(const char * directory)\n", mContext.codeNamespace.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if (directory == NULL)\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " char* path = (char*)malloc(BIN2C_MAX_PATH);\n"); - fprintf(fout, " if ( path == NULL )\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " path[0] = '\\0';\n"); - fprintf(fout, " for(size_t i=0; i< registered_files_count; i++)\n"); - fprintf(fout, " {\n"); - fprintf(fout, " const %s* f = %s_filemanager_get_file(i);\n", mContext.baseClass.c_str(), mContext.codeNamespace.c_str()); - fprintf(fout, " if ( !f )\n"); - fprintf(fout, " {\n"); - fprintf(fout, " free(path);\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " }\n"); - fprintf(fout, " \n"); - fprintf(fout, " snprintf(path, sizeof(path), \"%%s%%c%%s\", directory, PATH_SEPARATOR_CHAR, f->file_path);\n"); - fprintf(fout, " \n"); - fprintf(fout, " if (!%s_filemanager_create_parent_directories(path))\n", mContext.codeNamespace.c_str()); - fprintf(fout, " {\n"); - fprintf(fout, " free(path);\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " }\n"); - fprintf(fout, " bool saved = f->save(path);\n"); - fprintf(fout, " if (!saved)\n"); - fprintf(fout, " {\n"); - fprintf(fout, " free(path);\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " }\n"); - fprintf(fout, " }\n"); - fprintf(fout, " free(path);\n"); - fprintf(fout, " return true;\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); + const std::string text = "" + "${bin2cpp_file_manager_file_header}" + "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n" + "#define _CRT_SECURE_NO_WARNINGS\n" + "#endif\n" + "\n" + "#include \"${bin2cpp_file_manager_header_file_name}\"\n" + "#include // for malloc\n" + "#include // for snprintf()\n" + "#include // strlen\n" + "#include // stat\n" + "#include // errno, EEXIST\n" + "#if defined(_WIN32)\n" + "#include // _mkdir\n" + "#endif\n" + "#if defined(_WIN32)\n" + "#define portable_stat _stat\n" + "#define portable_mkdir(path) _mkdir(path)\n" + "#define PATH_SEPARATOR_CHAR '\\\\'\n" + "#define PATH_SEPARATOR_STR \"\\\\\"\n" + "#else\n" + "#define portable_stat stat\n" + "#define portable_mkdir(path) mkdir(path, 0755)\n" + "#define PATH_SEPARATOR_CHAR '/'\n" + "#define PATH_SEPARATOR_STR \"/\"\n" + "#endif\n" + "\n" + "#define BIN2C_MAX_PATH 32767\n" + "\n" + "static ${bin2cpp_baseclass}** registered_files = NULL;\n" + "static size_t registered_files_count = 0;\n" + "\n" + "size_t ${bin2cpp_namespace}_filemanager_get_file_count()\n" + "{\n" + " return registered_files_count;\n" + "}\n" + "\n" + "bool ${bin2cpp_namespace}_filemanager_register_file(${bin2cpp_baseclass}* file)\n" + "{\n" + " // check if already registered\n" + " if ( registered_files_count && registered_files )\n" + " {\n" + " for ( size_t i = 0; i < registered_files_count; i++ )\n" + " {\n" + " const ${bin2cpp_baseclass}* existing_file = registered_files[i];\n" + " if ( existing_file == file )\n" + " return true; // nothing to do\n" + " }\n" + " }\n" + " \n" + " // allocate ram\n" + " size_t new_ram_size = sizeof(${bin2cpp_baseclass}**) * (registered_files_count + 1);\n" + " ${bin2cpp_baseclass}** tmp = NULL;\n" + " if ( registered_files == NULL )\n" + " tmp = (${bin2cpp_baseclass}**)malloc(new_ram_size);\n" + " else\n" + " tmp = (${bin2cpp_baseclass}**)realloc(registered_files, new_ram_size);\n" + " if ( tmp == NULL )\n" + " return false;\n" + " \n" + " registered_files = tmp;\n" + " registered_files_count++;\n" + " \n" + " // insert\n" + " registered_files[registered_files_count - 1] = file;\n" + " \n" + " return true;\n" + "}\n" + "\n" + "const ${bin2cpp_baseclass}* ${bin2cpp_namespace}_filemanager_get_file(size_t index)\n" + "{\n" + " if ( index >= registered_files_count )\n" + " return NULL;\n" + " return registered_files[index];\n" + "}\n" + "\n" + "static inline bool ${bin2cpp_namespace}_filemanager_is_root_directory(const char* path)\n" + "{\n" + " if ( path == NULL && path[0] == '\\0' )\n" + " return false;\n" + "#if defined(_WIN32)\n" + " bool is_drive_letter = ((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z'));\n" + " if ( (is_drive_letter && path[1] == ':' && path[2] == '\\0') || // test for C:\n" + " (is_drive_letter && path[1] == ':' && path[2] == PATH_SEPARATOR_CHAR && path[3] == '\\0') ) // test for C:\\ \n" + " return true;\n" + "#else\n" + " if ( path[0] == PATH_SEPARATOR_CHAR )\n" + " return true;\n" + "#endif\n" + " return false;\n" + "}\n" + "\n" + "bool ${bin2cpp_namespace}_filemanager_create_parent_directories(const char* file_path)\n" + "{\n" + " if ( file_path == NULL )\n" + " return false;\n" + " char* accumulator = (char*)malloc(BIN2C_MAX_PATH);\n" + " if ( accumulator == NULL )\n" + " return false;\n" + " accumulator[0] = '\\0';\n" + " size_t length = strlen(file_path);\n" + " for ( size_t i = 0; i < length; i++ )\n" + " {\n" + " if ( file_path[i] == PATH_SEPARATOR_CHAR && !(accumulator[0] == '\\0') && !${bin2cpp_namespace}_filemanager_is_root_directory(accumulator) )\n" + " {\n" + " int ret = portable_mkdir(accumulator);\n" + " if ( ret != 0 && errno != EEXIST )\n" + " {\n" + " free(accumulator);\n" + " return false;\n" + " }\n" + " }\n" + " \n" + " // append\n" + " char tmp[] = { file_path[i], '\\0' };\n" + " strcat(accumulator, tmp);\n" + " }\n" + " free(accumulator);\n" + " return true;\n" + "}\n" + "\n" + "bool ${bin2cpp_namespace}_filemanager_save_files(const char * directory)\n" + "{\n" + " if (directory == NULL)\n" + " return false;\n" + " char* path = (char*)malloc(BIN2C_MAX_PATH);\n" + " if ( path == NULL )\n" + " return false;\n" + " path[0] = '\\0';\n" + " for(size_t i=0; i< registered_files_count; i++)\n" + " {\n" + " const ${bin2cpp_baseclass}* f = ${bin2cpp_namespace}_filemanager_get_file(i);\n" + " if ( !f )\n" + " {\n" + " free(path);\n" + " return false;\n" + " }\n" + " \n" + " snprintf(path, sizeof(path), \"%s%c%s\", directory, PATH_SEPARATOR_CHAR, f->file_path);\n" + " \n" + " if (!${bin2cpp_namespace}_filemanager_create_parent_directories(path))\n" + " {\n" + " free(path);\n" + " return false;\n" + " }\n" + " bool saved = f->save(path);\n" + " if (!saved)\n" + " {\n" + " free(path);\n" + " return false;\n" + " }\n" + " }\n" + " free(path);\n" + " return true;\n" + "}\n" + "\n" + ; - fclose(fout); + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); - return true; + return write_success; } bool ManagerGenerator::printFileContent() diff --git a/src/bin2cpp/ManagerGenerator.h b/src/bin2cpp/ManagerGenerator.h index a6d7981..7bad555 100644 --- a/src/bin2cpp/ManagerGenerator.h +++ b/src/bin2cpp/ManagerGenerator.h @@ -39,8 +39,8 @@ namespace bin2cpp ManagerGenerator(); virtual ~ManagerGenerator(); virtual const char * getName() const; - virtual bool createCppHeaderFile(const char* header_file_path); - virtual bool createCppSourceFile(const char * cpp_file_path); + virtual bool createCppHeaderFile(const char* file_path); + virtual bool createCppSourceFile(const char * file_path); virtual bool createCHeaderFile(const char* file_path); virtual bool createCSourceFile(const char* file_path); virtual bool printFileContent(); diff --git a/src/bin2cpp/SegmentGenerator.cpp b/src/bin2cpp/SegmentGenerator.cpp index 071365d..d01f52f 100755 --- a/src/bin2cpp/SegmentGenerator.cpp +++ b/src/bin2cpp/SegmentGenerator.cpp @@ -23,6 +23,7 @@ *********************************************************************************/ #include "SegmentGenerator.h" +#include "TemplateProcessor.h" #include #include #include @@ -47,284 +48,196 @@ namespace bin2cpp return "segment"; } - bool SegmentGenerator::createCppSourceFile(const char * cpp_file_path) + bool SegmentGenerator::createCppSourceFile(const char * file_path) { //check if input file exists - FILE * input = fopen(mContext.inputFilePath.c_str(), "rb"); - if (!input) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Uppercase function identifier - std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(getContext().functionIdentifier); - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(cpp_file_path); - std::string cppPath = cpp_file_path; - - //create cpp source file - FILE * cpp = fopen(cppPath.c_str(), "w"); - if (!cpp) - { - fclose(input); - return false; - } - - //determine file properties - uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); - //long lastSegmentSize = fileSize%chunk_size; - //size_t numSegments = fileSize/chunk_size + (lastSegmentSize == 0 ? 0 : 1); - - //Build class name - std::string className = getClassName(); - - //Build function - std::string getterFunctionName = getGetterFunctionName(); - - //Build FileManager class template - std::string manager = mContext.managerHeaderFilename; - - //write cpp file heading - fprintf(cpp, "%s", getHeaderTemplate().c_str()); - fprintf(cpp, "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n"); - fprintf(cpp, "#define _CRT_SECURE_NO_WARNINGS\n"); - fprintf(cpp, "#endif\n"); - fprintf(cpp, "#include \"%s\"\n", mContext.headerFilename.c_str() ); - fprintf(cpp, "#include //for std::string\n"); - fprintf(cpp, "#include \n"); - fprintf(cpp, "#include //for ofstream\n"); - fprintf(cpp, "namespace %s\n", getContext().codeNamespace.c_str()); - fprintf(cpp, "{\n"); - fprintf(cpp, " class %s : public virtual %s::%s\n", className.c_str(), getContext().codeNamespace.c_str(), getContext().baseClass.c_str()); - fprintf(cpp, " {\n"); - fprintf(cpp, " public:\n"); - fprintf(cpp, " %s() { build(); }\n", className.c_str()); - fprintf(cpp, " virtual ~%s() {}\n", className.c_str()); - fprintf(cpp, " virtual size_t getSize() const { return %u; }\n", fileSize); - fprintf(cpp, " virtual const char * getFileName() const { %s }\n", getImplOfGetFileName().c_str()); - fprintf(cpp, " virtual const char * getFilePath() const { %s }\n", getImplOfGetFilePath().c_str()); - fprintf(cpp, " virtual const char * getBuffer() const { return mBuffer.c_str(); }\n"); - fprintf(cpp, " void build()\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " mBuffer.clear();\n"); - fprintf(cpp, " mBuffer.reserve(getSize()); //allocate all required memory at once to prevent reallocations\n"); - - //create buffer for each chunks from input buffer - unsigned char * buffer = new unsigned char[getContext().chunkSize]; - while(!feof(input)) - { - //read a chunk of the file - size_t readSize = fread(buffer, 1, getContext().chunkSize, input); - - //bool isLastChunk = !(readSize == chunk_size); - - if (readSize == 0) - continue; //nothing to output if nothing was read - - //convert to cpp string - std::string cppEncoder; - switch(getContext().cppEncoder) - { - case CPP_ENCODER_HEX: - cppEncoder = ra::code::cpp::ToHexString(buffer, readSize); - break; - case CPP_ENCODER_OCT: - default: - cppEncoder = ra::code::cpp::ToOctString(buffer, readSize, false); - break; - }; - - //output - fprintf(cpp, " mBuffer.append(\"%s\", %s);\n", cppEncoder.c_str(), ra::strings::ToString(readSize).c_str()); - } - delete[] buffer; - buffer = NULL; - - //write cpp source file footer - fprintf(cpp, " }\n"); - fprintf(cpp, "%s", getSaveMethodTemplate().c_str()); - fprintf(cpp, " private:\n"); - fprintf(cpp, " std::string mBuffer;\n"); - fprintf(cpp, " };\n"); - fprintf(cpp, " const %s & %s() { static %s _instance; return _instance; }\n", getContext().baseClass.c_str(), getterFunctionName.c_str(), className.c_str()); - if (mContext.registerFiles) - { - std::string fileManagerTemplate = getCppFileManagerRegistrationImplementationTemplate(); - fprintf(cpp, "%s", fileManagerTemplate.c_str()); - } - fprintf(cpp, "}; //%s\n", getContext().codeNamespace.c_str()); - - fclose(input); - fclose(cpp); - - return true; + const std::string text = "" + "${bin2cpp_output_file_header_template}" + "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n" + "#define _CRT_SECURE_NO_WARNINGS\n" + "#endif\n" + "#include \"${bin2cpp_header_file_include_path}\"\n" + "#include //for std::string\n" + "#include \n" + "#include //for ofstream\n" + "namespace ${bin2cpp_namespace}\n" + "{\n" + " class ${bin2cpp_classname} : public virtual ${bin2cpp_namespace}::${bin2cpp_baseclass}\n" + " {\n" + " public:\n" + " ${bin2cpp_classname}() { build(); }\n" + " virtual ~${bin2cpp_classname}() {}\n" + " virtual size_t getSize() const { return ${bin2cpp_input_file_size}; }\n" + " virtual const char * getFileName() const { return \"${bin2cpp_file_object_file_name}\"; }\n" + " virtual const char * getFilePath() const { return \"${bin2cpp_file_object_file_path}\"; }\n" + " virtual const char * getBuffer() const { return mBuffer.c_str(); }\n" + " void build()\n" + " {\n" + " mBuffer.clear();\n" + " mBuffer.reserve(getSize()); //allocate all required memory at once to prevent reallocations\n${bin2cpp_insert_input_file_as_code}" // INPUT FILE AS CODE HERE + " }\n" + "${bin2cpp_cpp_save_method_template}" + " private:\n" + " std::string mBuffer;\n" + " };\n" + " const ${bin2cpp_baseclass} & ${bin2cpp_file_object_getter_function_name}() { static ${bin2cpp_classname} _instance; return _instance; }\n" + "${bin2cpp_file_manager_cpp_registration_implementation}" + "}; //${bin2cpp_namespace}\n"; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; } bool SegmentGenerator::createCSourceFile(const char* file_path) { //check if input file exists - FILE* input = fopen(mContext.inputFilePath.c_str(), "rb"); - if ( !input ) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Lowercase function identifier - std::string functionIdentifier = ra::strings::Lowercase(mContext.functionIdentifier); - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(file_path); - std::string sourcePath = file_path; + const std::string text = "" + "${bin2cpp_output_file_header_template}" + "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n" + "#define _CRT_SECURE_NO_WARNINGS\n" + "#endif\n" + "#include \"${bin2cpp_header_file_include_path}\"\n" + "#include // for malloc\n" + "#include // for memset\n" + "#include // for fopen\n" + "static ${bin2cpp_baseclass} ${bin2cpp_function_identifier_lowercase}_file = { 0 };\n" + "static bool ${bin2cpp_function_identifier_lowercase}_initialized = false;\n" + "\n" + "${bin2cpp_file_manager_c_registration_predeclaration}" + "bool ${bin2cpp_function_identifier_lowercase}_load()\n" + "{\n" + " if ( ${bin2cpp_function_identifier_lowercase}_file.buffer )\n" + " return true;\n" + "\n" + " unsigned char* local_buffer = (unsigned char*)malloc(${bin2cpp_function_identifier_lowercase}_file.size);\n" + " if ( local_buffer == NULL )\n" + " return false;\n" + "\n" + " unsigned char* next = local_buffer;\n${bin2cpp_insert_input_file_as_code}" // INPUT FILE AS CODE HERE + "\n" + " ${bin2cpp_function_identifier_lowercase}_file.buffer = local_buffer;\n" + " return true;\n" + "}\n" + "\n" + "void ${bin2cpp_function_identifier_lowercase}_free()\n" + "{\n" + " if ( ${bin2cpp_function_identifier_lowercase}_file.buffer )\n" + " free((unsigned char*)${bin2cpp_function_identifier_lowercase}_file.buffer);\n" + " ${bin2cpp_function_identifier_lowercase}_file.buffer = NULL;\n" + "}\n" + "\n" + "bool ${bin2cpp_function_identifier_lowercase}_save(const char* path)\n" + "{\n" + " if ( !${bin2cpp_function_identifier_lowercase}_file.buffer )\n" + " return false;\n" + " FILE* f = fopen(path, \"wb\");\n" + " if ( !f )\n" + " return false;\n" + " size_t write_size = fwrite(${bin2cpp_function_identifier_lowercase}_file.buffer, 1, ${bin2cpp_function_identifier_lowercase}_file.size, f);\n" + " fclose(f);\n" + " if ( write_size != ${bin2cpp_function_identifier_lowercase}_file.size )\n" + " return false;\n" + " return true;\n" + "}\n" + "\n" + "static inline void ${bin2cpp_function_identifier_lowercase}_init()\n" + "{\n" + " // remember we already initialized\n" + " if ( ${bin2cpp_function_identifier_lowercase}_initialized )\n" + " return;\n" + " ${bin2cpp_function_identifier_lowercase}_initialized = true;\n" + "\n" + " // initialize\n" + " ${bin2cpp_baseclass}* file = &${bin2cpp_function_identifier_lowercase}_file;\n" + " file->size = ${bin2cpp_input_file_size}ULL;\n" + " file->file_name = \"${bin2cpp_file_object_file_name}\";\n" + " file->file_path = \"${bin2cpp_file_object_file_path}\";\n" + " file->buffer = NULL;\n" + " file->load = ${bin2cpp_function_identifier_lowercase}_load;\n" + " file->unload = ${bin2cpp_function_identifier_lowercase}_free;\n" + " file->save = ${bin2cpp_function_identifier_lowercase}_save;\n" + "\n" + " // load file by default on init as in c++ implementation\n" + " file->load();\n" + "${bin2cpp_file_manager_c_registration_post_init_implementation}" + "}\n" + "\n" + "${bin2cpp_baseclass}* ${bin2cpp_file_object_getter_function_name}(void)\n" + "{\n" + " ${bin2cpp_function_identifier_lowercase}_init();\n" + " return &${bin2cpp_function_identifier_lowercase}_file;\n" + "}\n" + "${bin2cpp_file_manager_c_registration_implementation}"; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; + } - //create c source file - FILE* fout = fopen(sourcePath.c_str(), "w"); - if ( !fout ) + void SegmentGenerator::writeInputFileChunkAsCode(const unsigned char* buffer, size_t buffer_size, size_t index, size_t count, bool is_last_chunk, std::ostream& output) + { + size_t indentation = 0; + + if ( mContext.plainOutput ) + indentation = 0; + else if ( mContext.code == CodeGenerationEnum::CODE_GENERATION_CPP ) + indentation = 6; + else if ( mContext.code == CodeGenerationEnum::CODE_GENERATION_C ) + indentation = 2; + + std::string str; + if ( indentation ) + str += std::string(indentation, ' '); + + //convert to cpp string + std::string code; + switch ( mContext.cppEncoder ) + { + case CPP_ENCODER_HEX: + code = ra::code::cpp::ToHexString(buffer, buffer_size); + break; + case CPP_ENCODER_OCT: + default: + code = ra::code::cpp::ToOctString(buffer, buffer_size, false); + break; + }; + + if ( mContext.plainOutput ) { - fclose(input); - return false; } - - //determine file properties - uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); - //long lastSegmentSize = fileSize%chunk_size; - //size_t numSegments = fileSize/chunk_size + (lastSegmentSize == 0 ? 0 : 1); - - //Build class name - std::string className = getClassName(); - - //Build function - std::string getterFunctionName = getGetterFunctionName(); - - //Build FileManager class template - std::string manager = mContext.managerHeaderFilename; - - //write c file heading - fprintf(fout, "%s", getHeaderTemplate().c_str()); - fprintf(fout, "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n"); - fprintf(fout, "#define _CRT_SECURE_NO_WARNINGS\n"); - fprintf(fout, "#endif\n"); - fprintf(fout, "#include \"%s\"\n", mContext.headerFilename.c_str()); - fprintf(fout, "#include // for malloc\n"); - fprintf(fout, "#include // for memset\n"); - fprintf(fout, "#include // for fopen\n"); - - fprintf(fout, "static %s %s_file = { 0 };\n", mContext.baseClass.c_str(), functionIdentifier.c_str()); - fprintf(fout, "static bool %s_initialized = false;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - - // File registration predeclaration code - fprintf(fout, "%s", getCFileManagerRegistrationPredeclarationTemplate().c_str()); - - fprintf(fout, "bool %s_load()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( %s_file.buffer )\n", functionIdentifier.c_str()); - fprintf(fout, " return true;\n"); - fprintf(fout, "\n"); - fprintf(fout, " unsigned char* local_buffer = (unsigned char*)malloc(%s_file.size);\n", functionIdentifier.c_str()); - fprintf(fout, " if ( local_buffer == NULL )\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, "\n"); - fprintf(fout, " unsigned char* next = local_buffer;\n"); - - //create buffer for each chunks from input buffer - unsigned char* buffer = new unsigned char[getContext().chunkSize]; - while ( !feof(input) ) + else if ( mContext.code == CodeGenerationEnum::CODE_GENERATION_CPP ) { - //read a chunk of the file - size_t readSize = fread(buffer, 1, getContext().chunkSize, input); - - //bool isLastChunk = !(readSize == chunk_size); - - if ( readSize == 0 ) - continue; //nothing to output if nothing was read - - //convert to cpp string - std::string cppEncoder; - switch ( getContext().cppEncoder ) - { - case CPP_ENCODER_HEX: - cppEncoder = ra::code::cpp::ToHexString(buffer, readSize); - break; - case CPP_ENCODER_OCT: - default: - cppEncoder = ra::code::cpp::ToOctString(buffer, readSize, false); - break; - }; - - //output - fprintf(fout, " memcpy(next, \"%s\", %s); next += %s; \n", cppEncoder.c_str(), ra::strings::ToString(readSize).c_str(), ra::strings::ToString(readSize).c_str()); + str += "mBuffer.append(\""; + str += code; + str += "\", "; + str += ra::strings::ToString(buffer_size); + str += ");"; } - delete[] buffer; - buffer = NULL; - - //write c source file footer - fprintf(fout, "\n"); - fprintf(fout, " %s_file.buffer = local_buffer;\n", functionIdentifier.c_str()); - fprintf(fout, " return true;\n"); - fprintf(fout, "}\n"); - - fprintf(fout, "\n"); - - fprintf(fout, "void %s_free()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( %s_file.buffer )\n", functionIdentifier.c_str()); - fprintf(fout, " free((unsigned char*)%s_file.buffer);\n", functionIdentifier.c_str()); - fprintf(fout, " %s_file.buffer = NULL;\n", functionIdentifier.c_str()); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "bool %s_save(const char* path)\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( !%s_file.buffer )\n", functionIdentifier.c_str()); - fprintf(fout, " return false;\n"); - fprintf(fout, " FILE* f = fopen(path, \"wb\");\n"); - fprintf(fout, " if ( !f )\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " size_t write_size = fwrite(%s_file.buffer, 1, %s_file.size, f);\n", functionIdentifier.c_str(), functionIdentifier.c_str()); - fprintf(fout, " fclose(f);\n"); - fprintf(fout, " if ( write_size != %s_file.size )\n", functionIdentifier.c_str()); - fprintf(fout, " return false;\n"); - fprintf(fout, " return true;\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "static inline void %s_init()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " // remember we already initialized\n"); - fprintf(fout, " if ( %s_initialized )\n", functionIdentifier.c_str()); - fprintf(fout, " return;\n"); - fprintf(fout, " %s_initialized = true;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - fprintf(fout, " // initialize\n"); - fprintf(fout, " %s* file = &%s_file;\n", mContext.baseClass.c_str(), functionIdentifier.c_str()); - fprintf(fout, " file->size = %uULL;\n", fileSize); - fprintf(fout, " file->file_name = \"%s\";\n", getFileClassFileName().c_str()); - fprintf(fout, " file->file_path = \"%s\";\n", getFileClassFilePath().c_str()); - fprintf(fout, " file->buffer = NULL;\n"); - fprintf(fout, " file->load = %s_load;\n", functionIdentifier.c_str()); - fprintf(fout, " file->unload = %s_free;\n", functionIdentifier.c_str()); - fprintf(fout, " file->save = %s_save;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - fprintf(fout, " // load file by default on init as in c++ implementation"); - fprintf(fout, " file->load();\n"); - if ( mContext.registerFiles ) + else if ( mContext.code == CodeGenerationEnum::CODE_GENERATION_C ) { - fprintf(fout, " \n"); - fprintf(fout, " // register when loaded if static initialisation does not work\n"); - fprintf(fout, " %s_filemanager_register_file(file);\n", mContext.codeNamespace.c_str()); + str += "memcpy(next, \""; + str += code; + str += "\", "; + str += ra::strings::ToString(buffer_size); + str += "); next += "; + str += ra::strings::ToString(buffer_size); + str += ";"; } - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "%s* %s(void)\n", mContext.baseClass.c_str(), getGetterFunctionName().c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " %s_init();\n", functionIdentifier.c_str()); - fprintf(fout, " return &%s_file;\n", functionIdentifier.c_str()); - fprintf(fout, "}\n"); - - // File registration implementation code - fprintf(fout, "%s", getCFileManagerRegistrationImplementationTemplate().c_str()); - fclose(input); - fclose(fout); + str += "\n"; - return true; + output << str; } }; //bin2cpp \ No newline at end of file diff --git a/src/bin2cpp/SegmentGenerator.h b/src/bin2cpp/SegmentGenerator.h index 767eeaa..d86f896 100644 --- a/src/bin2cpp/SegmentGenerator.h +++ b/src/bin2cpp/SegmentGenerator.h @@ -40,8 +40,9 @@ namespace bin2cpp SegmentGenerator(); virtual ~SegmentGenerator(); virtual const char * getName() const; - virtual bool createCppSourceFile(const char * cpp_file_path); + virtual bool createCppSourceFile(const char * file_path); virtual bool createCSourceFile(const char* file_path); + virtual void writeInputFileChunkAsCode(const unsigned char* buffer, size_t buffer_size, size_t index, size_t count, bool is_last_chunk, std::ostream& output); }; }; //bin2cpp diff --git a/src/bin2cpp/StringGenerator.cpp b/src/bin2cpp/StringGenerator.cpp index b3fe3af..214609b 100755 --- a/src/bin2cpp/StringGenerator.cpp +++ b/src/bin2cpp/StringGenerator.cpp @@ -23,6 +23,7 @@ *********************************************************************************/ #include "StringGenerator.h" +#include "TemplateProcessor.h" #include #include #include @@ -47,296 +48,165 @@ namespace bin2cpp return "string"; } - bool StringGenerator::createCppSourceFile(const char * cpp_file_path) + bool StringGenerator::createCppSourceFile(const char * file_path) { //check if input file exists - FILE * input = fopen(mContext.inputFilePath.c_str(), "rb"); - if (!input) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Uppercase function identifier - std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(getContext().functionIdentifier); - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(cpp_file_path); - std::string cppPath = cpp_file_path; - - //create cpp file - FILE * cpp = fopen(cppPath.c_str(), "w"); - if (!cpp) - { - fclose(input); - return false; - } - - //determine file properties - uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); - - //Build class name - std::string className = getClassName(); - - //Build function - std::string getterFunctionName = getGetterFunctionName(); - - //write cpp file heading - fprintf(cpp, "%s", getHeaderTemplate().c_str()); - fprintf(cpp, "#include \"%s\"\n", mContext.headerFilename.c_str() ); - fprintf(cpp, "#include \n"); - fprintf(cpp, "#include //for ofstream\n"); - fprintf(cpp, "namespace %s\n", getContext().codeNamespace.c_str()); - fprintf(cpp, "{\n"); - fprintf(cpp, " class %s : public virtual %s::%s\n", className.c_str(), getContext().codeNamespace.c_str(), getContext().baseClass.c_str()); - fprintf(cpp, " {\n"); - fprintf(cpp, " public:\n"); - fprintf(cpp, " %s() {}\n", className.c_str()); - fprintf(cpp, " virtual ~%s() {}\n", className.c_str()); - fprintf(cpp, " virtual size_t getSize() const { return %u; }\n", fileSize); - fprintf(cpp, " virtual const char * getFileName() const { %s }\n", getImplOfGetFileName().c_str()); - fprintf(cpp, " virtual const char * getFilePath() const { %s }\n", getImplOfGetFilePath().c_str()); - fprintf(cpp, " virtual const char * getBuffer() const\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " const char * buffer = ""\n"); - - //create buffer for each chunks from input buffer - int numLinePrinted = 0; - unsigned char * buffer = new unsigned char[getContext().chunkSize]; - while(!feof(input)) - { - //read a chunk of the file - size_t readSize = fread(buffer, 1, getContext().chunkSize, input); - - bool isLastChunk = !(readSize == getContext().chunkSize); - - if (readSize > 0) - { - if (numLinePrinted > 0) - { - //end previous line - fprintf(cpp, "\n"); - } - - //convert to cpp string - std::string cppEncoder; - switch(getContext().cppEncoder) - { - case CPP_ENCODER_HEX: - cppEncoder = ra::code::cpp::ToHexString(buffer, readSize); - break; - case CPP_ENCODER_OCT: - default: - cppEncoder = ra::code::cpp::ToOctString(buffer, readSize, false); - break; - }; - - //output - fprintf(cpp, " \"%s\"", cppEncoder.c_str()); - numLinePrinted++; - } - - //end the string if last chunk printed - if (isLastChunk) - { - fprintf(cpp, ";\n"); - } - } - delete[] buffer; - buffer = NULL; - - //write cpp source file footer - fprintf(cpp, " return buffer;\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, "%s", getSaveMethodTemplate().c_str()); - fprintf(cpp, " };\n"); - fprintf(cpp, " const %s & %s() { static %s _instance; return _instance; }\n", getContext().baseClass.c_str(), getterFunctionName.c_str(), className.c_str()); - if (mContext.registerFiles) - { - std::string fileManagerTemplate = getCppFileManagerRegistrationImplementationTemplate(); - fprintf(cpp, "%s", fileManagerTemplate.c_str()); - } - fprintf(cpp, "}; //%s\n", getContext().codeNamespace.c_str()); - - fclose(input); - fclose(cpp); - - return true; + const std::string text = "" + "${bin2cpp_output_file_header_template}" + "#include \"${bin2cpp_header_file_include_path}\"\n" + "#include \n" + "#include //for ofstream\n" + "namespace ${bin2cpp_namespace}\n" + "{\n" + " class ${bin2cpp_classname} : public virtual ${bin2cpp_namespace}::${bin2cpp_baseclass}\n" + " {\n" + " public:\n" + " ${bin2cpp_classname}() {}\n" + " virtual ~${bin2cpp_classname}() {}\n" + " virtual size_t getSize() const { return ${bin2cpp_input_file_size}; }\n" + " virtual const char * getFileName() const { return \"${bin2cpp_file_object_file_name}\"; }\n" + " virtual const char * getFilePath() const { return \"${bin2cpp_file_object_file_path}\"; }\n" + " virtual const char * getBuffer() const\n" + " {\n" + " const char * buffer = \n${bin2cpp_insert_input_file_as_code}" // INPUT FILE AS CODE HERE + " return buffer;\n" + " }\n" + "${bin2cpp_cpp_save_method_template}" + " };\n" + " const ${bin2cpp_baseclass} & ${bin2cpp_file_object_getter_function_name}() { static ${bin2cpp_classname} _instance; return _instance; }\n" + "${bin2cpp_file_manager_cpp_registration_implementation}" + "}; //${bin2cpp_namespace}\n"; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; } bool StringGenerator::createCSourceFile(const char* file_path) { //check if input file exists - FILE* input = fopen(mContext.inputFilePath.c_str(), "rb"); - if ( !input ) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Uppercase function identifier - std::string functionIdentifier = ra::strings::Lowercase(mContext.functionIdentifier); - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(file_path); - std::string sourcePath = file_path; - - //create c source file - FILE* fout = fopen(sourcePath.c_str(), "w"); - if ( !fout ) - { - fclose(input); - return false; - } - - //determine file properties - uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); - //long lastSegmentSize = fileSize%chunk_size; - //size_t numSegments = fileSize/chunk_size + (lastSegmentSize == 0 ? 0 : 1); - - //Build class name - std::string className = getClassName(); - - //Build function - std::string getterFunctionName = getGetterFunctionName(); - - //Build FileManager class template - std::string manager = mContext.managerHeaderFilename; - - //write c file heading - fprintf(fout, "%s", getHeaderTemplate().c_str()); - fprintf(fout, "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n"); - fprintf(fout, "#define _CRT_SECURE_NO_WARNINGS\n"); - fprintf(fout, "#endif\n"); - fprintf(fout, "#include \"%s\"\n", mContext.headerFilename.c_str()); - fprintf(fout, "#include // for malloc\n"); - fprintf(fout, "#include // for memset\n"); - fprintf(fout, "#include // for fopen\n"); - - fprintf(fout, "static %s %s_file = { 0 };\n", mContext.baseClass.c_str(), functionIdentifier.c_str()); - fprintf(fout, "static bool %s_initialized = false;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - - // File registration predeclaration code - fprintf(fout, "%s", getCFileManagerRegistrationPredeclarationTemplate().c_str()); - - fprintf(fout, "bool %s_load()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( %s_file.buffer )\n", functionIdentifier.c_str()); - fprintf(fout, " return true;\n"); - fprintf(fout, "\n"); - fprintf(fout, " static const char * static_buffer = ""\n"); - - //create buffer for each chunks from input buffer - int numLinePrinted = 0; - unsigned char* buffer = new unsigned char[getContext().chunkSize]; - while ( !feof(input) ) - { - //read a chunk of the file - size_t readSize = fread(buffer, 1, getContext().chunkSize, input); - - bool isLastChunk = !(readSize == getContext().chunkSize); - - if ( readSize > 0 ) - { - if ( numLinePrinted > 0 ) - { - //end previous line - fprintf(fout, "\n"); - } - - //convert to cpp string - std::string cppEncoder; - switch ( getContext().cppEncoder ) - { - case CPP_ENCODER_HEX: - cppEncoder = ra::code::cpp::ToHexString(buffer, readSize); - break; - case CPP_ENCODER_OCT: - default: - cppEncoder = ra::code::cpp::ToOctString(buffer, readSize, false); - break; - }; - - //output - fprintf(fout, " \"%s\"", cppEncoder.c_str()); - numLinePrinted++; - } + const std::string text = "" + "${bin2cpp_output_file_header_template}" + "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n" + "#define _CRT_SECURE_NO_WARNINGS\n" + "#endif\n" + "#include \"${bin2cpp_header_file_include_path}\"\n" + "#include // for malloc\n" + "#include // for memset\n" + "#include // for fopen\n" + "static ${bin2cpp_baseclass} ${bin2cpp_function_identifier_lowercase}_file = { 0 };\n" + "static bool ${bin2cpp_function_identifier_lowercase}_initialized = false;\n" + "\n" + "${bin2cpp_file_manager_c_registration_predeclaration}" + "bool ${bin2cpp_function_identifier_lowercase}_load()\n" + "{\n" + " if ( ${bin2cpp_function_identifier_lowercase}_file.buffer )\n" + " return true;\n" + "\n" + " static const char * static_buffer = \n${bin2cpp_insert_input_file_as_code}" // INPUT FILE AS CODE HERE + "\n" + " ${bin2cpp_function_identifier_lowercase}_file.buffer = static_buffer;\n" + " return true;\n" + "}\n" + "\n" + "void ${bin2cpp_function_identifier_lowercase}_free()\n" + "{\n" + " ${bin2cpp_function_identifier_lowercase}_file.buffer = NULL;\n" + "}\n" + "\n" + "bool ${bin2cpp_function_identifier_lowercase}_save(const char* path)\n" + "{\n" + " if ( !${bin2cpp_function_identifier_lowercase}_file.buffer )\n" + " return false;\n" + " FILE* f = fopen(path, \"wb\");\n" + " if ( !f )\n" + " return false;\n" + " size_t write_size = fwrite(${bin2cpp_function_identifier_lowercase}_file.buffer, 1, ${bin2cpp_function_identifier_lowercase}_file.size, f);\n" + " fclose(f);\n" + " if ( write_size != ${bin2cpp_function_identifier_lowercase}_file.size )\n" + " return false;\n" + " return true;\n" + "}\n" + "\n" + "static inline void ${bin2cpp_function_identifier_lowercase}_init()\n" + "{\n" + " // remember we already initialized\n" + " if ( ${bin2cpp_function_identifier_lowercase}_initialized )\n" + " return;\n" + " ${bin2cpp_function_identifier_lowercase}_initialized = true;\n" + "\n" + " // initialize\n" + " ${bin2cpp_baseclass}* file = &${bin2cpp_function_identifier_lowercase}_file;\n" + " file->size = ${bin2cpp_input_file_size}ULL;\n" + " file->file_name = \"${bin2cpp_file_object_file_name}\";\n" + " file->file_path = \"${bin2cpp_file_object_file_path}\";\n" + " file->buffer = NULL;\n" + " file->load = ${bin2cpp_function_identifier_lowercase}_load;\n" + " file->unload = ${bin2cpp_function_identifier_lowercase}_free;\n" + " file->save = ${bin2cpp_function_identifier_lowercase}_save;\n" + "\n" + " // load file by default on init as in c++ implementation\n" + " file->load();\n" + "${bin2cpp_file_manager_c_registration_post_init_implementation}" + "}\n" + "\n" + "${bin2cpp_baseclass}* ${bin2cpp_file_object_getter_function_name}(void)\n" + "{\n" + " ${bin2cpp_function_identifier_lowercase}_init();\n" + " return &${bin2cpp_function_identifier_lowercase}_file;\n" + "}\n" + "${bin2cpp_file_manager_c_registration_implementation}"; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; + } - //end the string if last chunk printed - if ( isLastChunk ) - { - fprintf(fout, ";\n"); - } - } - delete[] buffer; - buffer = NULL; + void StringGenerator::writeInputFileChunkAsCode(const unsigned char* buffer, size_t buffer_size, size_t index, size_t count, bool is_last_chunk, std::ostream& output) + { + size_t indentation = 0; - //write c source file footer - fprintf(fout, "\n"); - fprintf(fout, " %s_file.buffer = static_buffer;\n", functionIdentifier.c_str()); - fprintf(fout, " return true;\n"); - fprintf(fout, "}\n"); + if ( mContext.plainOutput ) + indentation = 0; + else if ( mContext.code == CodeGenerationEnum::CODE_GENERATION_CPP ) + indentation = 8; + else if ( mContext.code == CodeGenerationEnum::CODE_GENERATION_C ) + indentation = 4; - fprintf(fout, "\n"); + std::string str; + if ( indentation ) + str += std::string(indentation, ' '); - fprintf(fout, "void %s_free()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " %s_file.buffer = NULL;\n", functionIdentifier.c_str()); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "bool %s_save(const char* path)\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( !%s_file.buffer )\n", functionIdentifier.c_str()); - fprintf(fout, " return false;\n"); - fprintf(fout, " FILE* f = fopen(path, \"wb\");\n"); - fprintf(fout, " if ( !f )\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " size_t write_size = fwrite(%s_file.buffer, 1, %s_file.size, f);\n", functionIdentifier.c_str(), functionIdentifier.c_str()); - fprintf(fout, " fclose(f);\n"); - fprintf(fout, " if ( write_size != %s_file.size )\n", functionIdentifier.c_str()); - fprintf(fout, " return false;\n"); - fprintf(fout, " return true;\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "static inline void %s_init()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " // remember we already initialized\n"); - fprintf(fout, " if ( %s_initialized )\n", functionIdentifier.c_str()); - fprintf(fout, " return;\n"); - fprintf(fout, " %s_initialized = true;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - fprintf(fout, " // initialize\n"); - fprintf(fout, " %s* file = &%s_file;\n", mContext.baseClass.c_str(), functionIdentifier.c_str()); - fprintf(fout, " file->size = %uULL;\n", fileSize); - fprintf(fout, " file->file_name = \"%s\";\n", getFileClassFileName().c_str()); - fprintf(fout, " file->file_path = \"%s\";\n", getFileClassFilePath().c_str()); - fprintf(fout, " file->buffer = NULL;\n"); - fprintf(fout, " file->load = %s_load;\n", functionIdentifier.c_str()); - fprintf(fout, " file->unload = %s_free;\n", functionIdentifier.c_str()); - fprintf(fout, " file->save = %s_save;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - fprintf(fout, " // load file by default on init as in c++ implementation"); - fprintf(fout, " file->load();\n"); + str += "\""; - if ( mContext.registerFiles ) + //convert to cpp string + switch ( mContext.cppEncoder ) { - fprintf(fout, " \n"); - fprintf(fout, " // register\n"); - fprintf(fout, " %s_filemanager_register_file(file);\n", mContext.codeNamespace.c_str()); - } - - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - fprintf(fout, "%s* %s(void)\n", mContext.baseClass.c_str(), getGetterFunctionName().c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " %s_init();\n", functionIdentifier.c_str()); - fprintf(fout, " return &%s_file;\n", functionIdentifier.c_str()); - fprintf(fout, "}\n"); - - // File registration implementation code - fprintf(fout, "%s", getCFileManagerRegistrationImplementationTemplate().c_str()); - - fclose(input); - fclose(fout); - - return true; + case CPP_ENCODER_HEX: + str += ra::code::cpp::ToHexString(buffer, buffer_size); + break; + case CPP_ENCODER_OCT: + default: + str += ra::code::cpp::ToOctString(buffer, buffer_size, false); + break; + }; + + str += "\""; + if ( is_last_chunk ) + str += ";"; + str += "\n"; + + output << str; } }; //bin2cpp \ No newline at end of file diff --git a/src/bin2cpp/StringGenerator.h b/src/bin2cpp/StringGenerator.h index f3dda2f..2947d45 100644 --- a/src/bin2cpp/StringGenerator.h +++ b/src/bin2cpp/StringGenerator.h @@ -39,8 +39,9 @@ namespace bin2cpp StringGenerator(); virtual ~StringGenerator(); virtual const char * getName() const; - virtual bool createCppSourceFile(const char * cpp_file_path); + virtual bool createCppSourceFile(const char * file_path); virtual bool createCSourceFile(const char* file_path); + virtual void writeInputFileChunkAsCode(const unsigned char* buffer, size_t buffer_size, size_t index, size_t count, bool is_last_chunk, std::ostream& output); }; }; //bin2cpp diff --git a/src/bin2cpp/TemplateProcessor.cpp b/src/bin2cpp/TemplateProcessor.cpp new file mode 100644 index 0000000..4a47c6d --- /dev/null +++ b/src/bin2cpp/TemplateProcessor.cpp @@ -0,0 +1,166 @@ +/********************************************************************************** + * MIT License + * + * Copyright (c) 2018 Antoine Beauchamp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *********************************************************************************/ + +#include "TemplateProcessor.h" +#include +#include + +namespace bin2cpp +{ + TemplateProcessor::TemplateProcessor() + { + reset(); + } + + TemplateProcessor::TemplateProcessor(const std::string* value) + { + reset(); + setTemplateText(value); + } + + TemplateProcessor::~TemplateProcessor() + { + } + + void TemplateProcessor::reset() + { + mTemplateText = NULL; + mVariableLookup = NULL; + } + + void TemplateProcessor::setTemplateText(const std::string* value) + { + mTemplateText = value; + } + + const std::string* TemplateProcessor::getTemplateText() const + { + return mTemplateText; + } + + void TemplateProcessor::setTemplateVariableLookup(ITemplateVariableLookup* lookup) + { + mVariableLookup = lookup; + } + + ITemplateVariableLookup* TemplateProcessor::getTemplateVariableLookup() const + { + return mVariableLookup; + } + + void TemplateProcessor::writeStream(std::ostream& output_stream) + { + std::set recursion_history; + processTemplate(output_stream, *mTemplateText, recursion_history); + } + + void TemplateProcessor::writeString(std::string& output) + { + std::ostringstream output_stream; + std::set recursion_history; + processTemplate(output_stream, *mTemplateText, recursion_history); + output = output_stream.str(); + } + + bool TemplateProcessor::writeFile(const std::string& file_path) + { + std::ofstream output_file(file_path); + if ( !output_file.is_open() ) return false; + + std::set recursion_history; + processTemplate(output_file, *mTemplateText, recursion_history); + return true; + } + + //------------------------------- + //protected methods + //------------------------------- + + void TemplateProcessor::processTemplate(std::ostream& output_stream, const std::string& value, std::set& recursion_history) + { + size_t pos = 0; + while ( pos < value.size() ) + { + if ( value[pos] == '$' && pos + 1 < value.size() && value[pos + 1] == '{' ) + { + size_t end_pos = value.find('}', pos); + if ( end_pos != std::string::npos ) + { + std::string variable_name = value.substr(pos + 2, end_pos - pos - 2); + + // Detect actual circular dependency within same recursion path + if ( recursion_history.find(variable_name) != recursion_history.end() ) + { + pos = end_pos + 1; + continue; + } + + // Do not crash if no lookup is provided. + // All template variables will be empty. + if ( !mVariableLookup ) + { + pos = end_pos + 1; + continue; + } + + // Check if template variable is a string and do the variable expansion + std::string expanded_value; + bool found_as_string = mVariableLookup->lookupStringVariable(variable_name, expanded_value); + + // Proceed with the recursive handling + if ( found_as_string ) + { + // Add variable to recursion history before expanding + recursion_history.insert(variable_name); + + // Recursively process expanded value with updated recursion tracking + processTemplate(output_stream, expanded_value, recursion_history); + + // Remove variable from recursion history after recursion returns + recursion_history.erase(variable_name); + } + else + { + // Check if template variable is a stream + // Stream based template variables do not support recursive lookup and tracking + bool found_as_stream = mVariableLookup->lookupStreamVariable(variable_name, output_stream); + } + + pos = end_pos + 1; + } + else + { + output_stream.put(value[pos]); + pos++; + } + } + else + { + output_stream.put(value[pos]); + pos++; + } + } + } + +}; //bin2cpp \ No newline at end of file diff --git a/src/bin2cpp/TemplateProcessor.h b/src/bin2cpp/TemplateProcessor.h new file mode 100644 index 0000000..32e1d5d --- /dev/null +++ b/src/bin2cpp/TemplateProcessor.h @@ -0,0 +1,67 @@ +/********************************************************************************** + * MIT License + * + * Copyright (c) 2018 Antoine Beauchamp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *********************************************************************************/ + +#ifndef TEMPLATEPROCESSOR_H +#define TEMPLATEPROCESSOR_H + +#include +#include +#include "ITemplateVariableLookup.h" + +namespace bin2cpp +{ + + /// + ///A class for processing a template containing template markers variables + ///and replace those to their actual values. + /// + class TemplateProcessor + { + public: + TemplateProcessor(); + TemplateProcessor(const std::string* value); + virtual ~TemplateProcessor(); + virtual void reset(); + + void setTemplateText(const std::string* value); + const std::string* getTemplateText() const; + + void setTemplateVariableLookup(ITemplateVariableLookup* lookup); + ITemplateVariableLookup* getTemplateVariableLookup() const; + + virtual void writeStream(std::ostream& output_stream); + virtual void writeString(std::string& output); + virtual bool writeFile(const std::string& file_path); + + protected: + virtual void processTemplate(std::ostream& output_stream, const std::string& value, std::set& recursion_history); + + //attributes + const std::string* mTemplateText; + ITemplateVariableLookup* mVariableLookup; + }; + +}; //bin2cpp + +#endif //TEMPLATEPROCESSOR_H diff --git a/src/bin2cpp/Win32ResourceGenerator.cpp b/src/bin2cpp/Win32ResourceGenerator.cpp index 574a8f5..df15057 100755 --- a/src/bin2cpp/Win32ResourceGenerator.cpp +++ b/src/bin2cpp/Win32ResourceGenerator.cpp @@ -23,6 +23,7 @@ *********************************************************************************/ #include "Win32ResourceGenerator.h" +#include "TemplateProcessor.h" #include "common.h" #include "crc32.h" @@ -51,144 +52,114 @@ namespace bin2cpp return "win32"; } - bool Win32ResourceGenerator::createCppSourceFile(const char * cpp_file_path) + bool Win32ResourceGenerator::createCppSourceFile(const char * file_path) { - bool resourceFileSuccess = createResourceFile(cpp_file_path); + bool resourceFileSuccess = createResourceFile(file_path); if (!resourceFileSuccess) return false; //check if input file exists - FILE * input = fopen(mContext.inputFilePath.c_str(), "rb"); - if (!input) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Uppercase function identifier - std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(getContext().functionIdentifier); - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(cpp_file_path); - std::string cppPath = cpp_file_path; - - //create cpp file - FILE * cpp = fopen(cppPath.c_str(), "w"); - if (!cpp) - { - fclose(input); - return false; - } - - //determine file properties - //uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); - - //Build class name - std::string className = getClassName(); - - //Build function - std::string getterFunctionName = getGetterFunctionName(); - - //write cpp file heading - fprintf(cpp, "%s", getHeaderTemplate().c_str()); - fprintf(cpp, "#include \"%s\"\n", mContext.headerFilename.c_str() ); - fprintf(cpp, "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n"); - fprintf(cpp, "#define _CRT_SECURE_NO_WARNINGS\n"); - fprintf(cpp, "#endif\n"); - fprintf(cpp, "\n"); - fprintf(cpp, "#include \n"); - fprintf(cpp, "#include \n"); - fprintf(cpp, "#include //for ofstream\n"); - fprintf(cpp, "\n"); - fprintf(cpp, "#ifndef WIN32_LEAN_AND_MEAN\n"); - fprintf(cpp, "#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers\n"); - fprintf(cpp, "#endif\n"); - fprintf(cpp, "#include \n"); - fprintf(cpp, "\n"); - fprintf(cpp, "#include //for EnumProcessModules()\n"); - fprintf(cpp, "#pragma comment( lib, \"psapi.lib\" )\n"); - fprintf(cpp, "\n"); - - fprintf(cpp, "namespace %s\n", getContext().codeNamespace.c_str()); - fprintf(cpp, "{\n"); - fprintf(cpp, " class %s : public virtual %s::%s\n", className.c_str(), getContext().codeNamespace.c_str(), getContext().baseClass.c_str()); - fprintf(cpp, " {\n"); - fprintf(cpp, " public:\n"); - fprintf(cpp, " %s() :\n", className.c_str()); - fprintf(cpp, " hProcess(NULL),\n"); - fprintf(cpp, " hModule(NULL),\n"); - fprintf(cpp, " hResourceInfoBlock(NULL),\n"); - fprintf(cpp, " hResHandle(NULL),\n"); - fprintf(cpp, " mBufferSize(0),\n"); - fprintf(cpp, " mBuffer(NULL)\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " loadResource();\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " virtual ~%s() { unloadResource(); }\n", className.c_str()); - fprintf(cpp, " virtual size_t getSize() const { return mBufferSize; }\n"); - fprintf(cpp, " virtual const char * getFileName() const { %s }\n", getImplOfGetFileName().c_str()); - fprintf(cpp, " virtual const char * getFilePath() const { %s }\n", getImplOfGetFilePath().c_str()); - fprintf(cpp, " virtual const char * getBuffer() const { return mBuffer; }\n"); - fprintf(cpp, " void loadResource()\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " //Get a handle to this process\n"); - fprintf(cpp, " hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId() );\n"); - fprintf(cpp, " if (hProcess)\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " //Find the main HMODULE of the process\n"); - fprintf(cpp, " DWORD cbNeeded;\n"); - fprintf(cpp, " if ( EnumProcessModules( hProcess, &hModule, sizeof(hModule), &cbNeeded) )\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " //Retrieve the resource\n"); - fprintf(cpp, " hResourceInfoBlock = FindResourceA(hModule, \"%s\", \"CUSTOM\");\n", getRandomIdentifier(mContext.inputFilePath.c_str()).c_str()); - fprintf(cpp, " if (hResourceInfoBlock)\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " hResHandle = LoadResource(hModule, hResourceInfoBlock);\n"); - fprintf(cpp, " if (hResHandle)\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " mBuffer = (const char *)LockResource(hResHandle);\n"); - fprintf(cpp, " mBufferSize = SizeofResource(hModule, hResourceInfoBlock);\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " virtual void unloadResource()\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " if (hResHandle)\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " FreeResource(hResHandle);\n"); - fprintf(cpp, " hResHandle = NULL;\n"); - fprintf(cpp, " mBuffer = NULL;\n"); - fprintf(cpp, " mBufferSize = 0;\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " hResourceInfoBlock = NULL;\n"); - fprintf(cpp, " hModule = NULL;\n"); - fprintf(cpp, " if (hProcess)\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " CloseHandle(hProcess);\n"); - fprintf(cpp, " hProcess = NULL;\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, "%s", getSaveMethodTemplate().c_str()); - fprintf(cpp, " private:\n"); - fprintf(cpp, " HANDLE hProcess;\n"); - fprintf(cpp, " HMODULE hModule;\n"); - fprintf(cpp, " HRSRC hResourceInfoBlock;\n"); - fprintf(cpp, " HGLOBAL hResHandle;\n"); - fprintf(cpp, " DWORD mBufferSize;\n"); - fprintf(cpp, " const char * mBuffer;\n"); - fprintf(cpp, " };\n"); - fprintf(cpp, " const %s & %s() { static %s _instance; return _instance; }\n", getContext().baseClass.c_str(), getterFunctionName.c_str(), className.c_str()); - if (mContext.registerFiles) - { - std::string fileManagerTemplate = getCppFileManagerRegistrationImplementationTemplate(); - fprintf(cpp, "%s", fileManagerTemplate.c_str()); - } - fprintf(cpp, "}; //%s\n", getContext().codeNamespace.c_str()); - - fclose(input); - fclose(cpp); - - return true; + const std::string text = "" + "${bin2cpp_output_file_header_template}" + "#include \"${bin2cpp_header_file_include_path}\"\n" + "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n" + "#define _CRT_SECURE_NO_WARNINGS\n" + "#endif\n" + "\n" + "#include \n" + "#include \n" + "#include //for ofstream\n" + "\n" + "#ifndef WIN32_LEAN_AND_MEAN\n" + "#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers\n" + "#endif\n" + "#include \n" + "\n" + "#include //for EnumProcessModules()\n" + "#pragma comment( lib, \"psapi.lib\" )\n" + "\n" + "namespace ${bin2cpp_namespace}\n" + "{\n" + " class ${bin2cpp_classname} : public virtual ${bin2cpp_namespace}::${bin2cpp_baseclass}\n" + " {\n" + " public:\n" + " ${bin2cpp_classname}() :\n" + " hProcess(NULL),\n" + " hModule(NULL),\n" + " hResourceInfoBlock(NULL),\n" + " hResHandle(NULL),\n" + " mBufferSize(0),\n" + " mBuffer(NULL)\n" + " {\n" + " loadResource();\n" + " }\n" + " virtual ~${bin2cpp_classname}() { unloadResource(); }\n" + " virtual size_t getSize() const { return mBufferSize; }\n" + " virtual const char * getFileName() const { return \"${bin2cpp_file_object_file_name}\"; }\n" + " virtual const char * getFilePath() const { return \"${bin2cpp_file_object_file_path}\"; }\n" + " virtual const char * getBuffer() const { return mBuffer; }\n" + " void loadResource()\n" + " {\n" + " //Get a handle to this process\n" + " hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId() );\n" + " if (hProcess)\n" + " {\n" + " //Find the main HMODULE of the process\n" + " DWORD cbNeeded;\n" + " if ( EnumProcessModules( hProcess, &hModule, sizeof(hModule), &cbNeeded) )\n" + " {\n" + " //Retrieve the resource\n" + " hResourceInfoBlock = FindResourceA(hModule, \"${bin2cpp_win32_resource_random_identifier}\", \"CUSTOM\");\n" + " if (hResourceInfoBlock)\n" + " {\n" + " hResHandle = LoadResource(hModule, hResourceInfoBlock);\n" + " if (hResHandle)\n" + " {\n" + " mBuffer = (const char *)LockResource(hResHandle);\n" + " mBufferSize = SizeofResource(hModule, hResourceInfoBlock);\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + " virtual void unloadResource()\n" + " {\n" + " if (hResHandle)\n" + " {\n" + " FreeResource(hResHandle);\n" + " hResHandle = NULL;\n" + " mBuffer = NULL;\n" + " mBufferSize = 0;\n" + " }\n" + " hResourceInfoBlock = NULL;\n" + " hModule = NULL;\n" + " if (hProcess)\n" + " {\n" + " CloseHandle(hProcess);\n" + " hProcess = NULL;\n" + " }\n" + " }\n" + "${bin2cpp_cpp_save_method_template}" + " private:\n" + " HANDLE hProcess;\n" + " HMODULE hModule;\n" + " HRSRC hResourceInfoBlock;\n" + " HGLOBAL hResHandle;\n" + " DWORD mBufferSize;\n" + " const char * mBuffer;\n" + " };\n" + " const ${bin2cpp_baseclass} & ${bin2cpp_file_object_getter_function_name}() { static ${bin2cpp_classname} _instance; return _instance; }\n" + "${bin2cpp_file_manager_cpp_registration_implementation}" + "}; //${bin2cpp_namespace}\n"; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; } bool Win32ResourceGenerator::createCSourceFile(const char* file_path) @@ -198,195 +169,148 @@ namespace bin2cpp return false; //check if input file exists - FILE* input = fopen(mContext.inputFilePath.c_str(), "rb"); - if ( !input ) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Uppercase function identifier - std::string functionIdentifier = ra::strings::Lowercase(mContext.functionIdentifier); - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(file_path); - std::string sourcePath = file_path; - - //create c source file - FILE* fout = fopen(sourcePath.c_str(), "w"); - if ( !fout ) - { - fclose(input); - return false; - } - - //determine file properties - uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); - //long lastSegmentSize = fileSize%chunk_size; - //size_t numSegments = fileSize/chunk_size + (lastSegmentSize == 0 ? 0 : 1); - - //Build class name - std::string className = getClassName(); - - //Build function - std::string getterFunctionName = getGetterFunctionName(); - - //Build FileManager class template - std::string manager = mContext.managerHeaderFilename; - - //write c file heading - fprintf(fout, "%s", getHeaderTemplate().c_str()); - fprintf(fout, "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n"); - fprintf(fout, "#define _CRT_SECURE_NO_WARNINGS\n"); - fprintf(fout, "#endif\n"); - fprintf(fout, "\n"); - fprintf(fout, "#include \"%s\"\n", mContext.headerFilename.c_str()); - fprintf(fout, "#include // for malloc\n"); - fprintf(fout, "#include // for memset\n"); - fprintf(fout, "#include // for fopen\n"); - fprintf(fout, "\n"); - fprintf(fout, "#ifndef WIN32_LEAN_AND_MEAN\n"); - fprintf(fout, "#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers\n"); - fprintf(fout, "#endif\n"); - fprintf(fout, "#include \n"); - fprintf(fout, "\n"); - fprintf(fout, "#include //for EnumProcessModules()\n"); - fprintf(fout, "#pragma comment( lib, \"psapi.lib\" )\n"); - fprintf(fout, "\n"); - fprintf(fout, "static %s %s_file = { 0 };\n", mContext.baseClass.c_str(), functionIdentifier.c_str()); - fprintf(fout, "static bool %s_initialized = false;\n", functionIdentifier.c_str()); - fprintf(fout, "typedef struct %s\n", getLocalInfoStructName().c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " HANDLE hProcess;\n"); - fprintf(fout, " HMODULE hModule;\n"); - fprintf(fout, " HRSRC hResourceInfoBlock;\n"); - fprintf(fout, " HGLOBAL hResHandle;\n"); - fprintf(fout, " DWORD dwBufferSize;\n"); - fprintf(fout, "} %s;\n", getLocalInfoStructName().c_str()); - fprintf(fout, "static %s %s_info = { 0 };\n", getLocalInfoStructName().c_str(), functionIdentifier.c_str()); - fprintf(fout, "\n"); - - // File registration predeclaration code - fprintf(fout, "%s", getCFileManagerRegistrationPredeclarationTemplate().c_str()); - - fprintf(fout, "bool %s_load()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( %s_file.buffer )\n", functionIdentifier.c_str()); - fprintf(fout, " return true;\n"); - fprintf(fout, "\n"); - fprintf(fout, " %s* info = &%s_info;\n", getLocalInfoStructName().c_str(), functionIdentifier.c_str()); - - fprintf(fout, " //Get a handle to this process\n"); - fprintf(fout, " info->hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId() );\n"); - fprintf(fout, " if (info->hProcess)\n"); - fprintf(fout, " {\n"); - fprintf(fout, " //Find the main HMODULE of the process\n"); - fprintf(fout, " DWORD cbNeeded;\n"); - fprintf(fout, " if ( EnumProcessModules( info->hProcess, &info->hModule, sizeof(info->hModule), &cbNeeded) )\n"); - fprintf(fout, " {\n"); - fprintf(fout, " //Retrieve the resource\n"); - fprintf(fout, " info->hResourceInfoBlock = FindResourceA(info->hModule, \"%s\", \"CUSTOM\");\n", getRandomIdentifier(mContext.inputFilePath.c_str()).c_str()); - fprintf(fout, " if (info->hResourceInfoBlock)\n"); - fprintf(fout, " {\n"); - fprintf(fout, " info->hResHandle = LoadResource(info->hModule, info->hResourceInfoBlock);\n"); - fprintf(fout, " if (info->hResHandle)\n"); - fprintf(fout, " {\n"); - fprintf(fout, " %s_file.buffer = (const unsigned char *)LockResource(info->hResHandle);\n", functionIdentifier.c_str()); - fprintf(fout, " info->dwBufferSize = SizeofResource(info->hModule, info->hResourceInfoBlock);\n"); - fprintf(fout, " return true;\n"); - fprintf(fout, " }\n"); - fprintf(fout, " }\n"); - fprintf(fout, " }\n"); - fprintf(fout, " }\n"); - fprintf(fout, " \n"); - fprintf(fout, " return false;\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - - fprintf(fout, "void %s_free()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( %s_file.buffer == NULL)\n", functionIdentifier.c_str()); - fprintf(fout, " return;\n"); - fprintf(fout, " %s* info = &%s_info;\n", getLocalInfoStructName().c_str(), functionIdentifier.c_str()); - fprintf(fout, " if (info->hResHandle)\n"); - fprintf(fout, " {\n"); - fprintf(fout, " FreeResource(info->hResHandle);\n"); - fprintf(fout, " info->hResHandle = NULL;\n"); - fprintf(fout, " %s_file.buffer = NULL;\n", functionIdentifier.c_str()); - fprintf(fout, " info->dwBufferSize = 0;\n"); - fprintf(fout, " }\n"); - fprintf(fout, " info->hResourceInfoBlock = NULL;\n"); - fprintf(fout, " info->hModule = NULL;\n"); - fprintf(fout, " if (info->hProcess)\n"); - fprintf(fout, " {\n"); - fprintf(fout, " CloseHandle(info->hProcess);\n"); - fprintf(fout, " info->hProcess = NULL;\n"); - fprintf(fout, " }\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - - fprintf(fout, "bool %s_save(const char* path)\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " if ( !%s_file.buffer )\n", functionIdentifier.c_str()); - fprintf(fout, " return false;\n"); - fprintf(fout, " FILE* f = fopen(path, \"wb\");\n"); - fprintf(fout, " if ( !f )\n"); - fprintf(fout, " return false;\n"); - fprintf(fout, " size_t write_size = fwrite(%s_file.buffer, 1, %s_file.size, f);\n", functionIdentifier.c_str(), functionIdentifier.c_str()); - fprintf(fout, " fclose(f);\n"); - fprintf(fout, " if ( write_size != %s_file.size )\n", functionIdentifier.c_str()); - fprintf(fout, " return false;\n"); - fprintf(fout, " return true;\n"); - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - - fprintf(fout, "static inline void %s_init()\n", functionIdentifier.c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " // remember we already initialized\n"); - fprintf(fout, " if ( %s_initialized )\n", functionIdentifier.c_str()); - fprintf(fout, " return;\n"); - fprintf(fout, " %s_initialized = true;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - fprintf(fout, " // initialize\n"); - fprintf(fout, " %s* file = &%s_file;\n", mContext.baseClass.c_str(), functionIdentifier.c_str()); - fprintf(fout, " file->size = %uULL;\n", fileSize); - fprintf(fout, " file->file_name = \"%s\";\n", getFileClassFileName().c_str()); - fprintf(fout, " file->file_path = \"%s\";\n", getFileClassFilePath().c_str()); - fprintf(fout, " file->buffer = NULL;\n"); - fprintf(fout, " file->load = %s_load;\n", functionIdentifier.c_str()); - fprintf(fout, " file->unload = %s_free;\n", functionIdentifier.c_str()); - fprintf(fout, " file->save = %s_save;\n", functionIdentifier.c_str()); - fprintf(fout, "\n"); - fprintf(fout, " // load file by default on init as in c++ implementation"); - fprintf(fout, " file->load();\n"); - - if ( mContext.registerFiles ) - { - fprintf(fout, " \n"); - fprintf(fout, " // register\n"); - fprintf(fout, " %s_filemanager_register_file(file);\n", mContext.codeNamespace.c_str()); - } - - fprintf(fout, "}\n"); - fprintf(fout, "\n"); - - fprintf(fout, "%s* %s(void)\n", mContext.baseClass.c_str(), getGetterFunctionName().c_str()); - fprintf(fout, "{\n"); - fprintf(fout, " %s_init();\n", functionIdentifier.c_str()); - fprintf(fout, " return &%s_file;\n", functionIdentifier.c_str()); - fprintf(fout, "}\n"); - - // File registration implementation code - fprintf(fout, "%s", getCFileManagerRegistrationImplementationTemplate().c_str()); - - fclose(input); - fclose(fout); - - return true; + const std::string text = "" + "${bin2cpp_output_file_header_template}" + "#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)\n" + "#define _CRT_SECURE_NO_WARNINGS\n" + "#endif\n" + "\n" + "#include \"${bin2cpp_header_file_include_path}\"\n" + "#include // for malloc\n" + "#include // for memset\n" + "#include // for fopen\n" + "\n" + "#ifndef WIN32_LEAN_AND_MEAN\n" + "#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers\n" + "#endif\n" + "#include \n" + "\n" + "#include //for EnumProcessModules()\n" + "#pragma comment( lib, \"psapi.lib\" )\n" + "\n" + "static ${bin2cpp_baseclass} ${bin2cpp_function_identifier_lowercase}_file = { 0 };\n" + "static bool ${bin2cpp_function_identifier_lowercase}_initialized = false;\n" + "typedef struct ${bin2cpp_win32_local_info_struct_name}\n" + "{\n" + " HANDLE hProcess;\n" + " HMODULE hModule;\n" + " HRSRC hResourceInfoBlock;\n" + " HGLOBAL hResHandle;\n" + " DWORD dwBufferSize;\n" + "} ${bin2cpp_win32_local_info_struct_name};\n" + "static ${bin2cpp_win32_local_info_struct_name} ${bin2cpp_function_identifier_lowercase}_info = { 0 };\n" + "\n" + "${bin2cpp_file_manager_c_registration_predeclaration}" + "bool ${bin2cpp_function_identifier_lowercase}_load()\n" + "{\n" + " if ( ${bin2cpp_function_identifier_lowercase}_file.buffer )\n" + " return true;\n" + "\n" + " ${bin2cpp_win32_local_info_struct_name}* info = &${bin2cpp_function_identifier_lowercase}_info;\n" + " //Get a handle to this process\n" + " info->hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId() );\n" + " if (info->hProcess)\n" + " {\n" + " //Find the main HMODULE of the process\n" + " DWORD cbNeeded;\n" + " if ( EnumProcessModules( info->hProcess, &info->hModule, sizeof(info->hModule), &cbNeeded) )\n" + " {\n" + " //Retrieve the resource\n" + " info->hResourceInfoBlock = FindResourceA(info->hModule, \"${bin2cpp_win32_resource_random_identifier}\", \"CUSTOM\");\n" + " if (info->hResourceInfoBlock)\n" + " {\n" + " info->hResHandle = LoadResource(info->hModule, info->hResourceInfoBlock);\n" + " if (info->hResHandle)\n" + " {\n" + " ${bin2cpp_function_identifier_lowercase}_file.buffer = (const unsigned char *)LockResource(info->hResHandle);\n" + " info->dwBufferSize = SizeofResource(info->hModule, info->hResourceInfoBlock);\n" + " return true;\n" + " }\n" + " }\n" + " }\n" + " }\n" + " \n" + " return false;\n" + "}\n" + "\n" + "void ${bin2cpp_function_identifier_lowercase}_free()\n" + "{\n" + " if ( ${bin2cpp_function_identifier_lowercase}_file.buffer == NULL)\n" + " return;\n" + " ${bin2cpp_win32_local_info_struct_name}* info = &${bin2cpp_function_identifier_lowercase}_info;\n" + " if (info->hResHandle)\n" + " {\n" + " FreeResource(info->hResHandle);\n" + " info->hResHandle = NULL;\n" + " ${bin2cpp_function_identifier_lowercase}_file.buffer = NULL;\n" + " info->dwBufferSize = 0;\n" + " }\n" + " info->hResourceInfoBlock = NULL;\n" + " info->hModule = NULL;\n" + " if (info->hProcess)\n" + " {\n" + " CloseHandle(info->hProcess);\n" + " info->hProcess = NULL;\n" + " }\n" + "}\n" + "\n" + "bool ${bin2cpp_function_identifier_lowercase}_save(const char* path)\n" + "{\n" + " if ( !${bin2cpp_function_identifier_lowercase}_file.buffer )\n" + " return false;\n" + " FILE* f = fopen(path, \"wb\");\n" + " if ( !f )\n" + " return false;\n" + " size_t write_size = fwrite(${bin2cpp_function_identifier_lowercase}_file.buffer, 1, ${bin2cpp_function_identifier_lowercase}_file.size, f);\n" + " fclose(f);\n" + " if ( write_size != ${bin2cpp_function_identifier_lowercase}_file.size )\n" + " return false;\n" + " return true;\n" + "}\n" + "\n" + "static inline void ${bin2cpp_function_identifier_lowercase}_init()\n" + "{\n" + " // remember we already initialized\n" + " if ( ${bin2cpp_function_identifier_lowercase}_initialized )\n" + " return;\n" + " ${bin2cpp_function_identifier_lowercase}_initialized = true;\n" + "\n" + " // initialize\n" + " ${bin2cpp_baseclass}* file = &${bin2cpp_function_identifier_lowercase}_file;\n" + " file->size = ${bin2cpp_input_file_size}ULL;\n" + " file->file_name = \"${bin2cpp_file_object_file_name}\";\n" + " file->file_path = \"${bin2cpp_file_object_file_path}\";\n" + " file->buffer = NULL;\n" + " file->load = ${bin2cpp_function_identifier_lowercase}_load;\n" + " file->unload = ${bin2cpp_function_identifier_lowercase}_free;\n" + " file->save = ${bin2cpp_function_identifier_lowercase}_save;\n" + "\n" + " // load file by default on init as in c++ implementation\n" + " file->load();\n" + "${bin2cpp_file_manager_c_registration_post_init_implementation}" + "}\n" + "\n" + "${bin2cpp_baseclass}* ${bin2cpp_file_object_getter_function_name}(void)\n" + "{\n" + " ${bin2cpp_function_identifier_lowercase}_init();\n" + " return &${bin2cpp_function_identifier_lowercase}_file;\n" + "}\n" + "${bin2cpp_file_manager_c_registration_implementation}"; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; } - std::string Win32ResourceGenerator::getResourceFilePath(const char * cpp_file_path) + std::string Win32ResourceGenerator::getResourceFilePath(const char * file_path) { //Build header file path - std::string resourcePath = cpp_file_path; + std::string resourcePath = file_path; switch ( mContext.code ) { default: @@ -400,10 +324,10 @@ namespace bin2cpp return resourcePath; } - bool Win32ResourceGenerator::createResourceFile(const char * cpp_file_path) + bool Win32ResourceGenerator::createResourceFile(const char * file_path) { //Build resource file path - std::string resourceFilePath = getResourceFilePath(cpp_file_path); + std::string resourceFilePath = getResourceFilePath(file_path); //create resource file FILE * res = fopen(resourceFilePath.c_str(), "w"); @@ -424,14 +348,14 @@ namespace bin2cpp return true; } - std::string Win32ResourceGenerator::getRandomIdentifier(const char * cpp_file_path) + std::string Win32ResourceGenerator::getRandomIdentifier(const char * file_path) { - std::string include_guard = getCppIncludeGuardMacroName(cpp_file_path); + std::string include_guard = getIncludeGuardMacroName(file_path); //append a CRC32 checksum of the file path to allow storing multiple files with the same name in resources uint32_t checksum = 0; crc32Init(&checksum); - crc32Update(&checksum, (unsigned char *)cpp_file_path, (uint32_t)strlen(cpp_file_path)); + crc32Update(&checksum, (unsigned char *)file_path, (uint32_t)strlen(file_path)); crc32Finish(&checksum); std::string checksumString; @@ -452,6 +376,15 @@ namespace bin2cpp return false; // not supported } + bool Win32ResourceGenerator::lookupStringVariable(const std::string& name, std::string& output) + { + if ( name == "bin2cpp_win32_resource_random_identifier" ) { output = getRandomIdentifier(mContext.inputFilePath.c_str()); return true; } + if ( name == "bin2cpp_win32_local_info_struct_name" ) { output = getLocalInfoStructName(); return true; } + + // Unknown name + return this->BaseGenerator::lookupStringVariable(name, output); + } + std::string Win32ResourceGenerator::getLocalInfoStructName() { std::string name = ra::strings::Lowercase(mContext.functionIdentifier); diff --git a/src/bin2cpp/Win32ResourceGenerator.h b/src/bin2cpp/Win32ResourceGenerator.h index a5e29ce..e76a96d 100644 --- a/src/bin2cpp/Win32ResourceGenerator.h +++ b/src/bin2cpp/Win32ResourceGenerator.h @@ -39,13 +39,17 @@ namespace bin2cpp Win32ResourceGenerator(); virtual ~Win32ResourceGenerator(); virtual const char * getName() const; - virtual bool createCppSourceFile(const char * cpp_file_path); + virtual bool createCppSourceFile(const char * file_path); virtual bool createCSourceFile(const char* file_path); virtual bool printFileContent(); + + //ITemplateVariableLookup methods + virtual bool lookupStringVariable(const std::string& name, std::string& output); + protected: - virtual std::string getResourceFilePath(const char * cpp_file_path); - virtual bool createResourceFile(const char * cpp_file_path); - virtual std::string getRandomIdentifier(const char * cpp_file_path); + virtual std::string getResourceFilePath(const char * file_path); + virtual bool createResourceFile(const char * file_path); + virtual std::string getRandomIdentifier(const char * file_path); virtual std::string getLocalInfoStructName(); }; diff --git a/src/bin2cpp/bin2cpp.samples.txt b/src/bin2cpp/bin2cpp.samples.txt index 1f9d63f..9c4dd9f 100644 --- a/src/bin2cpp/bin2cpp.samples.txt +++ b/src/bin2cpp/bin2cpp.samples.txt @@ -1,11 +1,19 @@ +########################################################################################## # C code examples: +########################################################################################## -Test all generators +Test all generators: --file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\test\bin2cpp_unittest\generated_files\testHtml100000 --headerfile=_testHtml100000_C.h --override --code=c --generator=array --file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\test\bin2cpp_unittest\generated_files\testHtml100000 --headerfile=_testHtml100000_C.h --override --code=c --generator=segment --file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\test\bin2cpp_unittest\generated_files\testHtml100000 --headerfile=_testHtml100000_C.h --override --code=c --generator=string --file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\test\bin2cpp_unittest\generated_files\testHtml100000 --headerfile=_testHtml100000_C.h --override --code=c --generator=win32 +Test as much features as possible with all generators: +--file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\temp --headerfile=c_tim_testHtml100000_array.h --identifier=LibFooFOO --chunksize=75 --baseclass=ben --namespace=ray --managerfile=c_tim_filemanager.h --registerfile --reportedfilepath=virtual/folder/testHtml100000.bin --override --code=c --generator=array +--file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\temp --headerfile=c_jim_testHtml100000_segment.h --identifier=LibBarBAR --chunksize=75 --baseclass=tom --namespace=eva --managerfile=c_jim_filemanager.h --registerfile --reportedfilepath=virtual/folder/testHtml100000.bin --override --code=c --generator=segment +--file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\temp --headerfile=c_lou_testHtml100000_string.h --identifier=LibBazBAZ --chunksize=75 --baseclass=sam --namespace=joe --managerfile=c_lou_filemanager.h --registerfile --reportedfilepath=virtual/folder/testHtml100000.bin --override --code=c --generator=string +--file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\temp --headerfile=c_sue_testHtml100000_win32.h --identifier=LibBobBOB --chunksize=75 --baseclass=leo --namespace=jon --managerfile=c_sue_filemanager.h --registerfile --reportedfilepath=virtual/folder/testHtml100000.bin --override --code=c --generator=win32 + Test for: * Segment C generator * filemanager @@ -13,6 +21,8 @@ Test for: --file=..\..\test\bin2cpp_unittest\generated_files\testFileManager_C\testFileManager_C.1.bin --output=..\..\test\bin2cpp_unittest\generated_files\testFileManager_C --headerfile=_testFileManager_C.1.h --identifier=testFileManager1_c --managerfile=filemanager.h --override --code=c --file=..\..\test\bin2cpp_unittest\generated_files\testFileManager_C\testFileManager_C.2.bin --output=..\..\test\bin2cpp_unittest\generated_files\testFileManager_C --headerfile=_testFileManager_C.2.h --identifier=testFileManager2_c --registerfile --override --code=c + + Test directories: --dir=..\..\..\samples\demo_website\www --output=..\..\temp --code=c --dir=..\..\..\samples\demo_website\www --output=..\..\temp --code=c --managerfile=www-file-manager.h @@ -24,7 +34,37 @@ Test for baseclass: --file=..\..\test\bin2cpp_unittest\generated_files\testBaseClass_C\testBaseClass_C.bin --output=..\..\test\bin2cpp_unittest\generated_files\testBaseClass_C --headerfile=testBaseClass_C.h --identifier=testBaseClass_C --managerfile=filemanager.h --override --code=c --baseclass=Resource +########################################################################################## # CPP code examples: +########################################################################################## + +Test all generators +--file=..\..\test\bin2cpp_unittest\generated_files\testGeneratorArray10000\testGeneratorArray10000.bin --output=..\..\test\bin2cpp_unittest\generated_files\testGeneratorArray10000 --headerfile=_testGeneratorArray10000.h --identifier=testGeneratorArray10000 --chunksize=450 --override --generator=array +--file=..\..\test\bin2cpp_unittest\generated_files\testGeneratorSegment10000\testGeneratorSegment10000.bin --output=..\..\test\bin2cpp_unittest\generated_files\testGeneratorSegment10000 --headerfile=_testGeneratorSegment10000.h --identifier=testGeneratorSegment10000 --chunksize=450 --override --generator=segment +--file=..\..\test\bin2cpp_unittest\generated_files\testGeneratorString10000\testGeneratorString10000.bin --output=..\..\test\bin2cpp_unittest\generated_files\testGeneratorString10000 --headerfile=_testGeneratorString10000.h --identifier=testGeneratorString10000 --chunksize=450 --override --generator=string +--file=..\..\test\bin2cpp_unittest\generated_files\testGeneratorWin32\testGeneratorWin32.bin --output=..\..\test\bin2cpp_unittest\generated_files\testGeneratorWin32 --headerfile=_testGeneratorWin32.h --identifier=testGeneratorWin32 --chunksize=450 --override --generator=win32 + +Compare all generators: +--file=..\..\test\bin2cpp_unittest\generated_files\testGeneratorSegment10000\testGeneratorSegment10000.bin --output=..\..\temp --headerfile=cpp_tim_testHtml100000_array.h --identifier=LibArray --chunksize=75 --registerfile --override --generator=array +--file=..\..\test\bin2cpp_unittest\generated_files\testGeneratorSegment10000\testGeneratorSegment10000.bin --output=..\..\temp --headerfile=cpp_jim_testHtml100000_segment.h --identifier=LibSegment --chunksize=75 --registerfile --override --generator=segment +--file=..\..\test\bin2cpp_unittest\generated_files\testGeneratorSegment10000\testGeneratorSegment10000.bin --output=..\..\temp --headerfile=cpp_lou_testHtml100000_string.h --identifier=LibString --chunksize=75 --registerfile --override --generator=string +--file=..\..\test\bin2cpp_unittest\generated_files\testGeneratorSegment10000\testGeneratorSegment10000.bin --output=..\..\temp --headerfile=cpp_sue_testHtml100000_win32.h --identifier=LibWin32 --chunksize=75 --registerfile --override --generator=win32 + +Test as much features as possible with all generators: +--file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\temp --headerfile=cpp_tim_testHtml100000_array.h --identifier=LibFooFOO --chunksize=75 --baseclass=ben --namespace=ray --managerfile=cpp_tim_filemanager.h --registerfile --reportedfilepath=virtual/folder/testHtml100000.bin --override --code=cpp --generator=array +--file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\temp --headerfile=cpp_jim_testHtml100000_segment.h --identifier=LibBarBAR --chunksize=75 --baseclass=tom --namespace=eva --managerfile=cpp_jim_filemanager.h --registerfile --reportedfilepath=virtual/folder/testHtml100000.bin --override --code=cpp --generator=segment +--file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\temp --headerfile=cpp_lou_testHtml100000_string.h --identifier=LibBazBAZ --chunksize=75 --baseclass=sam --namespace=joe --managerfile=cpp_lou_filemanager.h --registerfile --reportedfilepath=virtual/folder/testHtml100000.bin --override --code=cpp --generator=string +--file=..\..\test\bin2cpp_unittest\generated_files\testHtml100000\testHtml100000.bin --output=..\..\temp --headerfile=cpp_sue_testHtml100000_win32.h --identifier=LibBobBOB --chunksize=75 --baseclass=leo --namespace=jon --managerfile=cpp_sue_filemanager.h --registerfile --reportedfilepath=virtual/folder/testHtml100000.bin --override --code=cpp --generator=win32 + +Test plain output: +--plainoutput --chunksize=75 --file=..\..\test\bin2cpp_unittest\generated_files\testSequential1000\testSequential1000.bin --generator=array +--plainoutput --chunksize=75 --file=..\..\test\bin2cpp_unittest\generated_files\testSequential1000\testSequential1000.bin --generator=segment +--plainoutput --chunksize=75 --file=..\..\test\bin2cpp_unittest\generated_files\testSequential1000\testSequential1000.bin --generator=string + + + + + --dir=..\..\..\samples\demo_website\www --output=..\..\temp --managerfile=PagesFileManager.h --namespace=myblog --keepdirs --dir=..\..\..\samples\demo_website\www --output=..\..\temp --dirincludefilter="*\static\*.css:*.jpg" --dir=..\..\..\samples\demo_website\www --output=..\..\temp --dirincludefilter="*\static\*.css:*.jpg" --direxcludefilter="*\light-mode.css" diff --git a/src/bin2cpp/common.cpp b/src/bin2cpp/common.cpp index 796a38e..62c7c01 100755 --- a/src/bin2cpp/common.cpp +++ b/src/bin2cpp/common.cpp @@ -110,7 +110,7 @@ namespace bin2cpp return false; } - std::string getCppIncludeGuardMacroName(const std::string & path) + std::string getIncludeGuardMacroName(const std::string & path) { static const std::string EMPTY_STRING; if (path.empty()) diff --git a/src/bin2cpp/common.h b/src/bin2cpp/common.h index 48aca46..af7eec6 100644 --- a/src/bin2cpp/common.h +++ b/src/bin2cpp/common.h @@ -84,7 +84,7 @@ namespace bin2cpp /// ///An valid file path. ///Returns the macro name for the given c++ header file. - std::string getCppIncludeGuardMacroName(const std::string & path); + std::string getIncludeGuardMacroName(const std::string & path); /// ///Filter a string to only contains the given allowed characters. diff --git a/src/bin2cpp/main.cpp b/src/bin2cpp/main.cpp index d5763f0..c70cdab 100755 --- a/src/bin2cpp/main.cpp +++ b/src/bin2cpp/main.cpp @@ -558,6 +558,9 @@ int main(int argc, char* argv[]) //should we also generate the FileManager class? if (c.hasManagerFile) { + //for the manager, header file name is the same as a normal output file header file name + c.headerFilename = c.managerHeaderFilename; + APP_ERROR_CODES error = processManagerFiles(c); if (error != APP_ERROR_SUCCESS) { @@ -837,6 +840,7 @@ APP_ERROR_CODES processManagerFiles(const Context & c) //configure the generator generator.setContext(c); + //process files bool headerResult = generateOutputFile(c, outputHeaderPath, &generator); if (!headerResult) diff --git a/test/bin2cpp_unittest/CMakeLists.txt b/test/bin2cpp_unittest/CMakeLists.txt index ac6c4ba..c682746 100644 --- a/test/bin2cpp_unittest/CMakeLists.txt +++ b/test/bin2cpp_unittest/CMakeLists.txt @@ -285,6 +285,9 @@ source_group("External Files" FILES ${CMAKE_SOURCE_DIR}/src/bin2cpp/common.h ${CMAKE_SOURCE_DIR}/src/bin2cpp/wildcard.cpp ${CMAKE_SOURCE_DIR}/src/bin2cpp/wildcard.h + ${CMAKE_SOURCE_DIR}/src/bin2cpp/ITemplateVariableLookup.h + ${CMAKE_SOURCE_DIR}/src/bin2cpp/TemplateProcessor.cpp + ${CMAKE_SOURCE_DIR}/src/bin2cpp/TemplateProcessor.h ) # Ensure source files are properly recognized as generated @@ -297,6 +300,9 @@ add_executable(bin2cpp_unittest ${CMAKE_SOURCE_DIR}/src/bin2cpp/common.h ${CMAKE_SOURCE_DIR}/src/bin2cpp/wildcard.cpp ${CMAKE_SOURCE_DIR}/src/bin2cpp/wildcard.h + ${CMAKE_SOURCE_DIR}/src/bin2cpp/ITemplateVariableLookup.h + ${CMAKE_SOURCE_DIR}/src/bin2cpp/TemplateProcessor.cpp + ${CMAKE_SOURCE_DIR}/src/bin2cpp/TemplateProcessor.h application.cpp application.h CMakeLists.txt @@ -310,6 +316,8 @@ add_executable(bin2cpp_unittest TestCommon.h TestExtraction.cpp TestExtraction.h + TestTemplateProcessor.cpp + TestTemplateProcessor.h TestWildcard.cpp TestWildcard.h ${GENERATED_TEST_FILES} diff --git a/test/bin2cpp_unittest/TestExtraction.cpp b/test/bin2cpp_unittest/TestExtraction.cpp index dbde3b8..3e527e6 100755 --- a/test/bin2cpp_unittest/TestExtraction.cpp +++ b/test/bin2cpp_unittest/TestExtraction.cpp @@ -63,10 +63,10 @@ #include "testReportedPathFile2/_testReportedPathFile2.h" #include "testReportedPathDir/generated_sources/FileManagerReportedPathDir.h" -#undef BIN2CPP_EMBEDDEDFILE_CLASS +#undef BIN2CPP_FILE_OBJECT_CLASS #include "testNamespace/_testNamespace.h" -#undef BIN2CPP_EMBEDDEDFILE_CLASS +#undef BIN2CPP_FILE_OBJECT_CLASS #include "testBaseClass/_testBaseClass.h" extern "C" @@ -645,7 +645,7 @@ TEST_F(TestExtraction, testIssue50) std::string path = "generated_files/testIssue50/_testIssue50.h"; ra::filesystem::NormalizePath(path); ASSERT_TRUE( ra::filesystem::FileExists(path.c_str()) ) << "File '" << path.c_str() << "' not found!"; - ASSERT_TRUE( ra::testing::FindInFile(path.c_str(), "BIN2CPP50_EMBEDDEDFILE_CLASS", line, index) ); + ASSERT_TRUE( ra::testing::FindInFile(path.c_str(), "BIN2CPP50_FILE_OBJECT_CLASS", line, index) ); } //FileManager50.h @@ -653,7 +653,7 @@ TEST_F(TestExtraction, testIssue50) std::string path = "generated_files/testIssue50/FileManager50.h"; ra::filesystem::NormalizePath(path); ASSERT_TRUE( ra::filesystem::FileExists(path.c_str()) ) << "File '" << path.c_str() << "' not found!"; - ASSERT_TRUE( ra::testing::FindInFile(path.c_str(), "BIN2CPP50_EMBEDDEDFILE_CLASS", line, index) ); + ASSERT_TRUE( ra::testing::FindInFile(path.c_str(), "BIN2CPP50_FILE_OBJECT_CLASS", line, index) ); ASSERT_TRUE( ra::testing::FindInFile(path.c_str(), "BIN2CPP50_FILEMANAGER_CLASS", line, index) ); } } diff --git a/test/bin2cpp_unittest/TestTemplateProcessor.cpp b/test/bin2cpp_unittest/TestTemplateProcessor.cpp new file mode 100644 index 0000000..77e4571 --- /dev/null +++ b/test/bin2cpp_unittest/TestTemplateProcessor.cpp @@ -0,0 +1,149 @@ +/********************************************************************************** + * MIT License + * + * Copyright (c) 2018 Antoine Beauchamp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *********************************************************************************/ + +#include "TestTemplateProcessor.h" + +#include "TemplateProcessor.h" + +#include "rapidassist/testing.h" +#include "rapidassist/filesystem.h" +#include "rapidassist/testing.h" +#include "rapidassist/user.h" + + // Sample variable lookup implementation +class SampleVariableLookup : public bin2cpp::ITemplateVariableLookup +{ +public: + bool lookupStringVariable(const std::string& name, std::string& output) override + { + if ( name == "first-name" ) { output = "Luke"; return true; } + if ( name == "last-name" ) { output = "Skywalker"; return true; } + if ( name == "full-name" ) { output = "${first-name} ${last-name}"; return true; } + if ( name == "age" ) { output = "53"; return true; } + if ( name == "job" ) { output = "Jedi Knight"; return true; } + if ( name == "children" ) { output = "2"; return true; } + if ( name == "foo" ) { output = "foo is ${bar}"; return true; } + if ( name == "bar" ) { output = "bar is ${baz}"; return true; } + if ( name == "baz" ) { output = "baz is ${foo}"; return true; } + return false; + } + + bool lookupStreamVariable(const std::string& name, std::ostream& output) override + { + return false; + } + +}; + +void TestTemplateProcessor::SetUp() +{ +} + +void TestTemplateProcessor::TearDown() +{ +} + +TEST_F(TestTemplateProcessor, testBaseSingleVariable) +{ + bin2cpp::TemplateProcessor processor; + SampleVariableLookup lookup; + processor.setTemplateVariableLookup(&lookup); + + const std::string actual_input = "I am ${age} years old."; + const std::string expected_output = "I am 53 years old."; + processor.setTemplateText(&actual_input); + std::string actual_output; + processor.writeString(actual_output); + ASSERT_EQ(actual_output, expected_output); +} + +TEST_F(TestTemplateProcessor, testUnknownVariable) +{ + bin2cpp::TemplateProcessor processor; + SampleVariableLookup lookup; + processor.setTemplateVariableLookup(&lookup); + + const std::string actual_input = "My ${father} tried to kill me."; + const std::string expected_output = "My tried to kill me."; + processor.setTemplateText(&actual_input); + std::string actual_output; + processor.writeString(actual_output); + ASSERT_EQ(actual_output, expected_output); +} + +TEST_F(TestTemplateProcessor, testCaseSensitive) +{ + bin2cpp::TemplateProcessor processor; + SampleVariableLookup lookup; + processor.setTemplateVariableLookup(&lookup); + + const std::string actual_input = "The variable '${children}' should expand to a value but '${Children}' should be empty."; + const std::string expected_output = "The variable '2' should expand to a value but '' should be empty."; + processor.setTemplateText(&actual_input); + std::string actual_output; + processor.writeString(actual_output); + ASSERT_EQ(actual_output, expected_output); +} + +TEST_F(TestTemplateProcessor, testRecursive) +{ + bin2cpp::TemplateProcessor processor; + SampleVariableLookup lookup; + processor.setTemplateVariableLookup(&lookup); + + const std::string actual_input = "My name is ${full-name}. I work as a ${job} now."; + const std::string expected_output = "My name is Luke Skywalker. I work as a Jedi Knight now."; + processor.setTemplateText(&actual_input); + std::string actual_output; + processor.writeString(actual_output); + ASSERT_EQ(actual_output, expected_output); +} + +TEST_F(TestTemplateProcessor, testMultipleTwinMarkers) +{ + bin2cpp::TemplateProcessor processor; + SampleVariableLookup lookup; + processor.setTemplateVariableLookup(&lookup); + + const std::string actual_input = "My name is ${first-name} but everyone calls me Lucky-${first-name}."; + const std::string expected_output = "My name is Luke but everyone calls me Lucky-Luke."; + processor.setTemplateText(&actual_input); + std::string actual_output; + processor.writeString(actual_output); + ASSERT_EQ(actual_output, expected_output); +} + +TEST_F(TestTemplateProcessor, testCircularReference) +{ + bin2cpp::TemplateProcessor processor; + SampleVariableLookup lookup; + processor.setTemplateVariableLookup(&lookup); + + const std::string actual_input = "${foo}"; + const std::string expected_output = "foo is bar is baz is "; + processor.setTemplateText(&actual_input); + std::string actual_output; + processor.writeString(actual_output); + ASSERT_EQ(actual_output, expected_output); +} diff --git a/test/bin2cpp_unittest/TestTemplateProcessor.h b/test/bin2cpp_unittest/TestTemplateProcessor.h new file mode 100644 index 0000000..a74fb27 --- /dev/null +++ b/test/bin2cpp_unittest/TestTemplateProcessor.h @@ -0,0 +1,37 @@ +/********************************************************************************** + * MIT License + * + * Copyright (c) 2018 Antoine Beauchamp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *********************************************************************************/ + +#ifndef TESTTEMPLATEPROCESSOR_H +#define TESTTEMPLATEPROCESSOR_H + +#include + +class TestTemplateProcessor : public ::testing::Test +{ +public: + virtual void SetUp(); + virtual void TearDown(); +}; + +#endif //TESTTEMPLATEPROCESSOR_H