├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── modules │ └── cpp_resource.cmake ├── cmake_test ├── CMakeLists.txt └── rc_test_main.cpp ├── data ├── 1.png ├── 1.txt └── test1.rsc ├── src ├── CMakeLists.txt ├── cpp_rsc.cpp ├── rsc_create_files.h └── rsc_file_parse.h └── tests └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | nbproject/ 3 | tmp/ 4 | obsolete/ 5 | 6 | # Compiled Object files 7 | *.slo 8 | *.lo 9 | *.o 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | 15 | # Compiled Static libraries 16 | *.lai 17 | *.la 18 | *.a 19 | 20 | # Backup files 21 | *.backup 22 | *.*~ 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | os: 4 | - linux 5 | - osx 6 | 7 | compiler: 8 | - gcc 9 | - clang 10 | 11 | before_install: 12 | 13 | install: 14 | 15 | before_script: 16 | - mkdir build 17 | - cd build 18 | - cmake ../ 19 | 20 | script: 21 | - make 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | 3 | project(cpp_rsc) 4 | 5 | find_package(Boost 1.46 COMPONENTS unit_test_framework) 6 | 7 | if(Boost_UNIT_TEST_FRAMEWORK_FOUND) 8 | enable_testing() 9 | else() 10 | message(STATUS "No Boost::Test found. All tests have been disabled.") 11 | endif() 12 | 13 | set(CMAKE_BUILD_TYPE Debug) 14 | 15 | add_subdirectory(src) 16 | 17 | if(Boost_UNIT_TEST_FRAMEWORK_FOUND) 18 | add_subdirectory(tests) 19 | endif() 20 | 21 | add_subdirectory(cmake_test) 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, orex 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cpp_rsc 2 | ======= 3 | 4 | C++ resource manager. An arbitrary files to cpp/h resource files converter. 5 | -------------------------------------------------------------------------------- /cmake/modules/cpp_resource.cmake: -------------------------------------------------------------------------------- 1 | include(CMakeParseArguments) 2 | 3 | function(find_resource_compiler) 4 | 5 | if(NOT (COMMAND cpp_rsc)) 6 | include(ExternalProject) 7 | ExternalProject_Add(cpp_rsc_prj 8 | GIT_REPOSITORY https://github.com/orex/cpp_rsc.git 9 | GIT_TAG master 10 | INSTALL_COMMAND "") 11 | 12 | 13 | get_property(RSC_BIN_FOLDER TARGET cpp_rsc_prj PROPERTY _EP_BINARY_DIR) 14 | set_property(GLOBAL PROPERTY CPPRSC_CMD ${RSC_BIN_FOLDER}/src/${CMAKE_CFG_INTDIR}/cpp_rsc) 15 | else() 16 | set_property(GLOBAL PROPERTY CPPRSC_CMD cpp_rsc) 17 | endif() 18 | 19 | get_property(CMDRSC GLOBAL PROPERTY CPPRSC_CMD) 20 | message(STATUS "Resource compiler: " ${CMDRSC}) 21 | 22 | endfunction(find_resource_compiler) 23 | 24 | function(add_resource name) 25 | 26 | set(oneValueArgs OUTPUT RC_WORK_DIR SUFFIX_HEAD SUFFIX_SRC NAMESPACE DATA_WIDTH) 27 | cmake_parse_arguments(ADR "" "${oneValueArgs}" "" ${ARGN} ) 28 | 29 | if("${ADR_OUTPUT}" STREQUAL "") 30 | set(ADR_OUTPUT ${name}) 31 | endif() 32 | 33 | if("${ADR_SUFFIX_HEAD}" STREQUAL "") 34 | set(ADR_SUFFIX_HEAD "h") 35 | endif() 36 | 37 | if("${ADR_SUFFIX_SRC}" STREQUAL "") 38 | set(ADR_SUFFIX_SRC "cpp") 39 | endif() 40 | 41 | set(RSC_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/${name}.rsc) 42 | set(RSC_OUT_H ${CMAKE_CURRENT_BINARY_DIR}/${ADR_OUTPUT}.${ADR_SUFFIX_HEAD}) 43 | set(RSC_OUT_CPP ${CMAKE_CURRENT_BINARY_DIR}/${ADR_OUTPUT}.${ADR_SUFFIX_SRC}) 44 | 45 | file(WRITE ${RSC_FILE_NAME} "[general]\n") 46 | file(APPEND ${RSC_FILE_NAME} "output-file-name=${ADR_OUTPUT}\n") 47 | 48 | if(NOT ("${ADR_RC_WORK_DIR}" STREQUAL "")) 49 | file(APPEND ${RSC_FILE_NAME} "base-path=${ADR_RC_WORK_DIR}\n") 50 | endif() 51 | 52 | file(APPEND ${RSC_FILE_NAME} "suffix-header=${ADR_SUFFIX_HEAD}\n") 53 | file(APPEND ${RSC_FILE_NAME} "suffix-src=${ADR_SUFFIX_SRC}\n") 54 | 55 | if(NOT ("${ADR_NAMESPACE}" STREQUAL "")) 56 | file(APPEND ${RSC_FILE_NAME} "namespace=${ADR_NAMESPACE}\n") 57 | endif() 58 | 59 | if(NOT ("${ADR_DATA_WIDTH}" STREQUAL "")) 60 | file(APPEND ${RSC_FILE_NAME} "data-width=${ADR_DATA_WIDTH}\n\n") 61 | endif() 62 | 63 | add_custom_target(${name} 64 | DEPENDS ${RSC_OUT_H} ${RSC_OUT_CPP}) 65 | 66 | set_property(TARGET ${name} PROPERTY _AR_RSC_FILE ${RSC_FILE_NAME}) 67 | set_property(TARGET ${name} PROPERTY _AR_H_FILE ${RSC_OUT_H}) 68 | set_property(TARGET ${name} PROPERTY _AR_SRC_FILE ${RSC_OUT_CPP}) 69 | set_property(TARGET ${name} PROPERTY _AR_H_DIR ${CMAKE_CURRENT_BINARY_DIR}) 70 | 71 | get_property(CMDRSC GLOBAL PROPERTY CPPRSC_CMD) 72 | if("${CMDRSC}" STREQUAL "") 73 | unset(CMDRSC) 74 | set(CMDRSC "cpp_rsc") 75 | endif() 76 | 77 | if(TARGET cpp_rsc_prj) 78 | add_dependencies(${name} cpp_rsc_prj) 79 | endif() 80 | 81 | add_custom_command(OUTPUT ${RSC_OUT_H} ${RSC_OUT_CPP} 82 | COMMAND ${CMDRSC} ${RSC_FILE_NAME} 83 | DEPENDS ${RSC_FILE_NAME}) 84 | 85 | endfunction(add_resource name) 86 | 87 | function(link_resource_file name) 88 | 89 | set(options TEXT) 90 | set(oneValueArgs FILE VARIABLE) 91 | cmake_parse_arguments(ARL "${options}" "${oneValueArgs}" "" ${ARGN} ) 92 | 93 | get_property(RSC_FILE_NAME TARGET ${name} PROPERTY _AR_RSC_FILE) 94 | 95 | file(APPEND ${RSC_FILE_NAME} "[file]\n") 96 | file(APPEND ${RSC_FILE_NAME} "file-path=${ARL_FILE}\n") 97 | file(APPEND ${RSC_FILE_NAME} "var-name=${ARL_VARIABLE}\n") 98 | file(APPEND ${RSC_FILE_NAME} "text-file=${ARL_TEXT}\n\n") 99 | 100 | set_source_files_properties(${RSC_FILE_NAME} PROPERTIES OBJECT_DEPENDS ${ARL_FILE}) 101 | 102 | endfunction(link_resource_file name) 103 | -------------------------------------------------------------------------------- /cmake_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(test_cpp_rsc) 2 | 3 | set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) 4 | 5 | include(cpp_resource) 6 | 7 | add_resource(rc_test) 8 | link_resource_file(rc_test FILE ${CMAKE_SOURCE_DIR}/data/1.png VARIABLE png1) 9 | link_resource_file(rc_test FILE ${CMAKE_SOURCE_DIR}/data/1.txt VARIABLE txt1 TEXT) 10 | 11 | get_property(RSC_CPP_FILE TARGET rc_test PROPERTY _AR_SRC_FILE) 12 | get_property(RSC_H_DIR TARGET rc_test PROPERTY _AR_H_DIR) 13 | 14 | include_directories(${RSC_H_DIR}) 15 | 16 | add_executable(rc_test_main rc_test_main.cpp ${RSC_CPP_FILE}) -------------------------------------------------------------------------------- /cmake_test/rc_test_main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | 7 | /* 8 | * File: main.cpp 9 | * Author: kirill 10 | * 11 | * Created on February 14, 2016, 2:05 AM 12 | */ 13 | 14 | #include 15 | #include 16 | #include "rc_test.h" 17 | 18 | using namespace std; 19 | 20 | /* 21 | * 22 | */ 23 | int main(int argc, char** argv) 24 | { 25 | cout << txt1 << endl; 26 | 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /data/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orex/cpp_rsc/928ad84e11d768b1c6a3aa427277234b49b53cb5/data/1.png -------------------------------------------------------------------------------- /data/1.txt: -------------------------------------------------------------------------------- 1 | Hello, world12345! -------------------------------------------------------------------------------- /data/test1.rsc: -------------------------------------------------------------------------------- 1 | 2 | [general] 3 | ;output-file-name=test1 4 | ;base-path= 5 | ;suffix-header= 6 | ;suffix-src= 7 | namespace=rc1 8 | ;data-width= 9 | 10 | ;[file] 11 | ;file-path= 12 | ;var-name= 13 | ;text-file= 14 | 15 | [file] 16 | file-path=data/1.png 17 | var-name=png_num1 18 | text-file=false 19 | 20 | [file] 21 | file-path=data/1.txt 22 | var-name=txt_num1 23 | text-file=true 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(cpp_rsc cpp_rsc.cpp) 2 | 3 | install(TARGETS cpp_rsc RUNTIME DESTINATION bin) 4 | -------------------------------------------------------------------------------- /src/cpp_rsc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: cpp_rsc.cpp 3 | * Author: kirill 4 | * 5 | * Created on September 23, 2013, 10:55 AM 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #include "rsc_file_parse.h" 15 | #include "rsc_create_files.h" 16 | 17 | using namespace std; 18 | 19 | /* 20 | * 21 | */ 22 | int main(int argc, char** argv) 23 | { 24 | //cpp_rsc [-h] input_file [-o output_file_base] [-b base_folder] 25 | // [-sh suffix_header] [-sc suffix_source] [-n namespace] 26 | // 27 | string input_file; 28 | map map_opt; 29 | 30 | map_opt["-o"] = map_opt["-b"] = map_opt["-sh"] 31 | = map_opt["-sc"] = map_opt["-n"] 32 | = map_opt["-w"] = ""; 33 | 34 | if(argc < 2) 35 | input_file = ""; 36 | else 37 | input_file = argv[1]; 38 | 39 | if( (input_file == "-h") || (input_file == "") ) 40 | { 41 | cout << "C++ Resource program creator. Command line is" << endl 42 | << " cpp_rsc [-h] input_rsc_file [-o output_file_base] [-b base_path]" << endl 43 | << " [-sh suffix_header] [-sc suffix_source] [-n namespace] [-w data_width]" << endl 44 | << " see manual. man cpp_rsc. for details" << endl; 45 | return 0; 46 | } 47 | 48 | string curr_opt = ""; 49 | for(int i = 2; i < argc; i++) 50 | { 51 | if(curr_opt == "") 52 | { 53 | if(map_opt.count(argv[i]) == 0) 54 | { 55 | cerr << "ERROR: Invalid argument: " << argv[i] << endl; 56 | return 1; 57 | } 58 | else 59 | { 60 | curr_opt = argv[i]; 61 | if( map_opt[curr_opt] != "" ) 62 | { 63 | cerr << "ERROR: Duplicate option: " << curr_opt << endl; 64 | return 1; 65 | } 66 | } 67 | } 68 | else 69 | { 70 | if( map_opt.count(argv[i]) != 0 ) 71 | { 72 | cerr << "ERROR: Missing argument: " << curr_opt << endl; 73 | return 1; 74 | } 75 | else 76 | { 77 | map_opt[curr_opt] = argv[i]; 78 | curr_opt = ""; 79 | } 80 | } 81 | } 82 | 83 | if( curr_opt != "" ) 84 | { 85 | cerr << "ERROR: Missing argument: " << curr_opt << endl; 86 | return 1; 87 | } 88 | 89 | rsc_file_parse rp; 90 | 91 | if(!rp.parse(input_file, map_opt)) 92 | { 93 | cerr << "ERROR: Invalid parsing file " << input_file << endl; 94 | return 2; 95 | } 96 | 97 | rsc_create_files rsc_cf; 98 | 99 | if(!rsc_cf.create(rp)) 100 | return 3; 101 | 102 | return 0; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /src/rsc_create_files.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: rsc_create_files.h 3 | * Author: kirill 4 | * 5 | * Created on September 23, 2013, 4:45 PM 6 | */ 7 | 8 | #ifndef RSC_CREATE_FILES_H 9 | #define RSC_CREATE_FILES_H 10 | 11 | #include "rsc_file_parse.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | class rsc_create_files 21 | { 22 | protected: 23 | rsc_file_parse * rsfp; 24 | 25 | std::map file_sizes; 26 | 27 | void write_title(std::ostream &os, const std::string &extra_info); 28 | 29 | void begin_namespace(std::ostream &os, const std::string &name); 30 | void end_namespace(std::ostream &os, const std::string &name); 31 | 32 | void begin_header_protection(std::ostream &os, const std::string &name); 33 | void end_header_protection(std::ostream &os, const std::string &name); 34 | 35 | void write_variable_def(std::ostream &os, const rsc_item &item, bool header, bool text); 36 | 37 | void write_hex_data(std::istream &is, std::ostream &os, bool text, int &size); 38 | 39 | bool create_header(); 40 | bool create_src(); 41 | public: 42 | bool create(rsc_file_parse &prs); 43 | }; 44 | 45 | bool rsc_create_files::create(rsc_file_parse &prs) 46 | { 47 | rsfp = &prs; 48 | 49 | bool result = create_src(); 50 | 51 | if(result) 52 | result = create_header(); 53 | 54 | return result; 55 | } 56 | 57 | bool rsc_create_files::create_header() 58 | { 59 | using namespace std; 60 | 61 | ofstream f_out((rsfp->output_file_name + "." + rsfp->suffix_header).c_str(), fstream::out); 62 | if(!f_out.is_open()) 63 | return false; 64 | 65 | string hdr_define = rsfp->output_file_name + "_" + rsfp->suffix_header; 66 | 67 | if( isdigit(hdr_define[0]) ) 68 | hdr_define = "_" + hdr_define; 69 | 70 | transform(hdr_define.begin(), hdr_define.end(), hdr_define.begin(), ::toupper); 71 | 72 | for(int i = hdr_define.size() - 1; i >= 0; i--) 73 | { 74 | if( (hdr_define[i] == ' ') || (hdr_define[i] == '.') || (hdr_define[i] == '-')) 75 | hdr_define[i] = '_'; 76 | else if( (hdr_define[i] == '/') || (hdr_define[i] == '\\') ) 77 | { 78 | hdr_define.erase(0, i + 1); 79 | break; 80 | } 81 | } 82 | 83 | write_title(f_out, "This is a header file"); 84 | 85 | f_out << endl; 86 | 87 | begin_header_protection(f_out, hdr_define); 88 | begin_namespace(f_out, rsfp->name_namespace); 89 | 90 | for(int i = 0; i < rsfp->items.size(); i++) 91 | { 92 | write_variable_def(f_out, rsfp->items[i], true, rsfp->items[i].text_data); 93 | f_out << endl; 94 | } 95 | 96 | end_namespace(f_out, rsfp->name_namespace); 97 | end_header_protection(f_out, hdr_define); 98 | 99 | return true; 100 | } 101 | 102 | bool rsc_create_files::create_src() 103 | { 104 | using namespace std; 105 | ofstream f_out((rsfp->output_file_name + "." + rsfp->suffix_src).c_str(), fstream::out); 106 | if(!f_out.is_open()) 107 | return false; 108 | 109 | write_title(f_out, "This is a source file"); 110 | 111 | f_out << "#include \"" << rsfp->output_file_name + "." + rsfp->suffix_header << "\"" << endl << endl; 112 | 113 | begin_namespace(f_out, rsfp->name_namespace); 114 | 115 | for(int i = 0; i < rsfp->items.size(); i++) 116 | { 117 | write_variable_def(f_out, rsfp->items[i], false, rsfp->items[i].text_data); 118 | f_out << " {" << endl; 119 | 120 | std::string in_f_name = rsfp->base_path + "/" + rsfp->items[i].file_path; 121 | 122 | ifstream ifs(in_f_name.c_str(), rsfp->items[i].text_data ? fstream::in : (fstream::binary | fstream::in) ); 123 | 124 | if(!ifs.is_open()) 125 | { 126 | cerr << "ERROR: Resource file \"" << in_f_name << "\" cannot be open." << endl; 127 | return false; 128 | } 129 | write_hex_data(ifs, f_out, rsfp->items[i].text_data, rsfp->items[i].file_size); 130 | f_out << " }; /* End of " << rsfp->items[i].file_path << " */" << endl << endl; 131 | } 132 | 133 | end_namespace(f_out, rsfp->name_namespace); 134 | 135 | return true; 136 | } 137 | 138 | void rsc_create_files::write_variable_def(std::ostream &os, const rsc_item &item, bool header, bool text) 139 | { 140 | using namespace std; 141 | os << " /* Variable " + item.var_name + " from file " + item.file_path + " */\n" + 142 | " " + (header ? "extern ": "") + (text ? "const char " : "const unsigned char ") + item.var_name + "[]" + (header ? ";": " = ") 143 | << endl; 144 | 145 | if(header) 146 | { 147 | os << " /* Variable " + item.var_name + " size. */" << endl; 148 | os << " const int " + item.var_name + "_size = " << item.file_size << "; " << endl; 149 | } 150 | } 151 | 152 | void rsc_create_files::write_hex_data(std::istream &is, std::ostream &os, bool text, int &size) 153 | { 154 | using namespace std; 155 | int sm; 156 | std::stringstream ts; 157 | 158 | std::string line = " "; 159 | 160 | size = 0; 161 | 162 | while(!is.eof()) 163 | { 164 | sm = is.get(); 165 | std::string curr_item; 166 | ts.str(""); 167 | ts << std::hex; 168 | 169 | if(!is.eof()) 170 | { 171 | ts << sm; 172 | curr_item = ts.str(); 173 | if(curr_item.size() == 1) 174 | curr_item = "0" + curr_item; 175 | if( text ) 176 | curr_item = "'\\x" + curr_item + "', "; 177 | else 178 | curr_item = "0x" + curr_item + ", "; 179 | size++; 180 | } 181 | else 182 | { 183 | if(text) 184 | { 185 | curr_item = "'\\x00', "; 186 | size++; 187 | } 188 | } 189 | 190 | 191 | if( (line + curr_item).size() > rsfp->data_width ) 192 | { 193 | os << line << endl; 194 | line = " " + curr_item; 195 | } 196 | else 197 | line += curr_item; 198 | 199 | } 200 | 201 | line.erase(line.size() - 2); 202 | os << line << endl; 203 | } 204 | 205 | void rsc_create_files::write_title(std::ostream &os, const std::string &extra_info) 206 | { 207 | using namespace std; 208 | os << "/* Automatic generated file. DO NOT EDIT." << endl; 209 | os << " The file was generated by cpp_rsc program" << endl; 210 | os << " https://github.com/orex/cpp_rsc" << endl; 211 | os << " Resource file name: " << rsfp->rsc_file_name << endl; 212 | os << " " << extra_info << "*/" << endl << endl; 213 | } 214 | 215 | void rsc_create_files::begin_namespace(std::ostream &os, const std::string &name) 216 | { 217 | if(name != "") 218 | os << "namespace " << name << " {" << std::endl; 219 | } 220 | 221 | void rsc_create_files::end_namespace(std::ostream &os, const std::string &name) 222 | { 223 | if(name != "") 224 | os << "}; /*namespace " << name << " */" << std::endl; 225 | } 226 | 227 | void rsc_create_files::begin_header_protection(std::ostream &os, const std::string &name) 228 | { 229 | os << "#ifndef " << name << std::endl; 230 | os << "#define " << name << std::endl; 231 | } 232 | 233 | void rsc_create_files::end_header_protection(std::ostream &os, const std::string &name) 234 | { 235 | os << "#endif /*" << name << " */" << std::endl; 236 | } 237 | 238 | 239 | 240 | #endif /* RSC_CREATE_FILES_H */ 241 | 242 | -------------------------------------------------------------------------------- /src/rsc_file_parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: rsc_file_parse.h 3 | * Author: kirill 4 | * 5 | * Created on September 23, 2013, 1:43 PM 6 | */ 7 | 8 | #ifndef RSC_FILE_PARSE_H 9 | #define RSC_FILE_PARSE_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class rsc_item 17 | { 18 | public: 19 | std::string file_path; 20 | std::string var_name; 21 | int file_size; //Will be used in file creator. 22 | bool text_data; 23 | public: 24 | rsc_item() 25 | { clear(); } 26 | 27 | void clear() 28 | { 29 | file_path = ""; 30 | var_name = ""; 31 | text_data = false; 32 | } 33 | }; 34 | 35 | //cpp_rsc [-h] input_file [-o output_file_base] [-b base_folder] 36 | // [-sh suffix_header] [-sc suffix_source] [-n namespace] 37 | 38 | 39 | class rsc_file_parse 40 | { 41 | public: 42 | std::string rsc_file_name; 43 | std::string output_file_name; 44 | std::string base_path; 45 | std::string suffix_header; 46 | std::string suffix_src; 47 | std::string name_namespace; 48 | int data_width; 49 | std::vector items; 50 | protected: 51 | enum rsc_line {rcComment, rcData, rcSectionGeneral, rcSectionFile, rcError}; 52 | rsc_line parse_line(std::string line, std::string &name, std::string &val); 53 | void trim(std::string &str); 54 | bool parse_sec_gen(const std::string &name, const std::string &val); 55 | bool parse_sec_file(rsc_item &item, const std::string &name, const std::string &val); 56 | public: 57 | bool parse(std::string rsc_file_name_v, const std::map &map_opt); 58 | static std::string get_file_name(const std::string &full_file_name); 59 | private: 60 | 61 | }; 62 | 63 | std::string rsc_file_parse::get_file_name(const std::string &full_file_name) 64 | { 65 | int pos_dot = full_file_name.size(); 66 | int pos_slash = -1; 67 | for(int i = full_file_name.size() - 1; i >= 0; i-- ) 68 | { 69 | if( (full_file_name[i] == '.') && (pos_dot == full_file_name.size()) ) 70 | { 71 | pos_dot = i; 72 | } else if( (full_file_name[i] == '/') || (full_file_name[i] == '\\') ) 73 | { 74 | pos_slash = i; 75 | break; 76 | } 77 | } 78 | 79 | return full_file_name.substr(pos_slash + 1, pos_dot - pos_slash - 1); 80 | } 81 | 82 | bool rsc_file_parse::parse(std::string rsc_file_name_v, const std::map &map_opt) 83 | { 84 | rsc_file_name = rsc_file_name_v; 85 | 86 | output_file_name = get_file_name(rsc_file_name); 87 | 88 | base_path = ""; 89 | suffix_header = "h"; 90 | suffix_src = "cpp"; 91 | name_namespace = ""; 92 | data_width = 80; 93 | 94 | 95 | using namespace std; 96 | 97 | char buff[300]; 98 | 99 | ifstream rsc_file(rsc_file_name.c_str()); 100 | if(!rsc_file.is_open()) 101 | { 102 | cerr << "ERROR: File " << rsc_file_name << " did not open." << endl; 103 | return false; 104 | } 105 | 106 | rsc_item curr_item; 107 | rsc_line rp = rcComment; 108 | int i = 0; 109 | while(!rsc_file.eof()) 110 | { 111 | i++; 112 | rsc_line rc; 113 | std::string line, name, val; 114 | rsc_file.getline(buff, sizeof(buff) - 2); 115 | rc = parse_line(buff, name, val); 116 | if(rc == rcError) 117 | { 118 | cerr << "ERROR: Line " << i << "\"" << buff << "\" is not valid." 119 | << "File: " << rsc_file_name << endl; 120 | return false; 121 | } 122 | if(rc == rcData) 123 | { 124 | bool good_parse = false; 125 | if(rp == rcSectionGeneral) 126 | { 127 | good_parse = parse_sec_gen(name, val); 128 | } 129 | else if (rp == rcSectionFile) 130 | { 131 | good_parse = parse_sec_file(curr_item, name, val); 132 | } 133 | if(!good_parse) 134 | { 135 | cerr << "ERROR: Line " << i << "\"" << buff << "\" is not parsed." 136 | << "File: " << rsc_file_name << endl; 137 | return false; 138 | } 139 | } 140 | 141 | if( (rc == rcSectionFile) || (rc == rcSectionGeneral) || rsc_file.eof() ) 142 | { 143 | if(rp == rcSectionFile) 144 | { 145 | items.push_back(curr_item); 146 | curr_item.clear(); 147 | } 148 | rp = rc; 149 | } 150 | } 151 | 152 | #define SET_DATA(opt, var) if( map_opt.at(opt) != "" ) var = map_opt.at(opt) 153 | 154 | SET_DATA("-o" , output_file_name); 155 | SET_DATA("-b" , base_path); 156 | SET_DATA("-sh", suffix_header); 157 | SET_DATA("-sc", suffix_src); 158 | SET_DATA("-n" , name_namespace); 159 | 160 | if( map_opt.at("-w") != "" ) data_width = atoi(map_opt.at("-w").c_str()); 161 | 162 | if(data_width == 0) 163 | { 164 | cerr << "ERROR: Data width is incorrect." << endl; 165 | return false; 166 | } 167 | 168 | return true; 169 | } 170 | 171 | void rsc_file_parse::trim(std::string &str) 172 | { 173 | while( (str.size() > 0) && (str[0] == ' ') ) 174 | str.erase(0, 1); 175 | 176 | while( (str.size() > 0) && (str[str.size() - 1] == ' ') ) 177 | str.erase(str.size() - 1); 178 | } 179 | 180 | 181 | rsc_file_parse::rsc_line rsc_file_parse::parse_line(std::string line, std::string &name, std::string &val) 182 | { 183 | using namespace std; 184 | trim(line); 185 | 186 | if( line.size() == 0 ) 187 | return rcComment; 188 | 189 | if( (line[0] == '#') || (line[0] == ';')) 190 | return rcComment; 191 | 192 | for(int i = 0; i < line.size(); i++) 193 | { 194 | if( (line[i] == '#') || (line[i] == ';')) 195 | { 196 | line.erase(i); 197 | break; 198 | } 199 | } 200 | 201 | trim(line); 202 | 203 | if( (line == "[general]" ) || (line == "[General]" ) ) 204 | return rcSectionGeneral; 205 | 206 | if( (line == "[file]" ) || (line == "[File]" ) ) 207 | return rcSectionFile; 208 | 209 | size_t pos = line.find("="); 210 | if(pos == string::npos) 211 | return rcError; 212 | else 213 | { 214 | name = line.substr(0, pos); 215 | trim(name); 216 | val = line.substr(pos + 1); 217 | trim(val); 218 | return rcData; 219 | } 220 | } 221 | 222 | bool rsc_file_parse::parse_sec_gen(const std::string &name, const std::string &val) 223 | { 224 | bool result = true; 225 | if(name == "output-file-name") 226 | output_file_name = val; 227 | else if (name == "base-path") 228 | base_path = val; 229 | else if (name == "suffix-header") 230 | suffix_header = val; 231 | else if (name == "suffix-src") 232 | suffix_src = val; 233 | else if (name == "namespace") 234 | name_namespace = val; 235 | else if (name == "data-width") 236 | { 237 | data_width = atoi(val.c_str()); 238 | result = data_width != 0; 239 | } 240 | else 241 | result = false; 242 | 243 | return result; 244 | } 245 | 246 | bool rsc_file_parse::parse_sec_file(rsc_item &item, const std::string &name, const std::string &val) 247 | { 248 | bool result = true; 249 | if(name == "file-path") 250 | item.file_path = val; 251 | else if (name == "var-name") 252 | item.var_name = val; 253 | else if (name == "text-file") 254 | item.text_data = (val == "true") || (val == "1") || (val == "TRUE"); 255 | else 256 | result = false; 257 | 258 | return result; 259 | } 260 | 261 | 262 | #endif /* RSC_FILE_PARSE_H */ 263 | 264 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orex/cpp_rsc/928ad84e11d768b1c6a3aa427277234b49b53cb5/tests/CMakeLists.txt --------------------------------------------------------------------------------