diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index bb679be..2ba9e07 100755 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -4,7 +4,7 @@ on: [push, pull_request] env: # build Configuration, i.e. Debug, Release, etc. - BIN2CPP_BUILD_TYPE: Release + PRODUCT_BUILD_TYPE: Release # Required for Github Action. Unit test TestProcess.testKillAndTerminate fails to start /bin/nano with the following error: "Error opening terminal: unknown." TERM: xterm @@ -17,7 +17,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Configure GIT working-directory: ${{env.GITHUB_WORKSPACE}} @@ -28,7 +28,7 @@ jobs: git submodule update --init --recursive - name: Setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: '3.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified @@ -48,7 +48,8 @@ jobs: env - name: Deploy 'tests not available' badge before building - uses: exuanbo/actions-deploy-gist@v1 + #uses: exuanbo/actions-deploy-gist@v1 + uses: end2endzone/actions-deploy-gist@main if: github.event_name != 'pull_request' with: token: ${{ secrets.BADGES }} @@ -72,11 +73,13 @@ jobs: run: ./ci/github/install_bin2cpp.sh - name: Run unit tests + id: unit_tests working-directory: ${{env.GITHUB_WORKSPACE}} shell: bash run: ./ci/github/test_script.sh - name: Search unit test report file + if: success() || steps.unit_tests.conclusion == 'failure' working-directory: ${{env.GITHUB_WORKSPACE}} shell: bash run: | @@ -85,12 +88,14 @@ jobs: echo UNITTEST_REPORT_PATH=$UNITTEST_REPORT_PATH >> $GITHUB_ENV - name: Create test badge + if: success() || steps.unit_tests.conclusion == 'failure' working-directory: ${{env.GITHUB_WORKSPACE}} run: python ci/github/maketestbadge.py ${{env.UNITTEST_REPORT_PATH}} - name: Deploy test badge to gist - uses: exuanbo/actions-deploy-gist@v1 - if: github.event_name != 'pull_request' + if: success() || steps.unit_tests.conclusion == 'failure' + #uses: exuanbo/actions-deploy-gist@v1 + uses: end2endzone/actions-deploy-gist@main with: token: ${{ secrets.BADGES }} gist_id: 58cf6c72c08e706335337d5ef9ca48e8 @@ -98,7 +103,8 @@ jobs: file_path: ./badge.json - name: Archive test results - uses: actions/upload-artifact@v2 + if: success() || steps.unit_tests.conclusion == 'failure' + uses: actions/upload-artifact@v4.3.5 with: name: unit-test-results path: build/bin/bin2cpp_unittest.*.xml @@ -111,7 +117,8 @@ jobs: echo BIN2CPP_VERSION=$(cat build/version)>> $GITHUB_ENV - name: Archive installation packages - uses: actions/upload-artifact@v2 + if: success() || steps.unit_tests.conclusion == 'failure' + uses: actions/upload-artifact@v4.3.5 with: name: Installation packages. path: build/bin2cpp-${{env.BIN2CPP_VERSION}}-*.* diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index 0a68770..b6eacdb 100755 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -4,7 +4,7 @@ on: [push, pull_request] env: # build Configuration, i.e. Debug, Release, etc. - BIN2CPP_BUILD_TYPE: Release + PRODUCT_BUILD_TYPE: Release # Required for Github Action. Unit test TestProcess.testKillAndTerminate fails to start /bin/nano with the following error: "Error opening terminal: unknown." TERM: xterm @@ -13,11 +13,11 @@ jobs: build: # For a list of available runner types, refer to # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on - runs-on: macos-10.15 + runs-on: macos-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Configure GIT working-directory: ${{env.GITHUB_WORKSPACE}} @@ -28,7 +28,7 @@ jobs: git submodule update --init --recursive - name: Setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: '3.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified @@ -48,7 +48,8 @@ jobs: env - name: Deploy 'tests not available' badge before building - uses: exuanbo/actions-deploy-gist@v1 + #uses: exuanbo/actions-deploy-gist@v1 + uses: end2endzone/actions-deploy-gist@main if: github.event_name != 'pull_request' with: token: ${{ secrets.BADGES }} @@ -72,11 +73,13 @@ jobs: run: ./ci/github/install_bin2cpp.sh - name: Run unit tests + id: unit_tests working-directory: ${{env.GITHUB_WORKSPACE}} shell: bash run: ./ci/github/test_script.sh - name: Search unit test report file + if: success() || steps.unit_tests.conclusion == 'failure' working-directory: ${{env.GITHUB_WORKSPACE}} shell: bash run: | @@ -85,12 +88,14 @@ jobs: echo UNITTEST_REPORT_PATH=$UNITTEST_REPORT_PATH >> $GITHUB_ENV - name: Create test badge + if: success() || steps.unit_tests.conclusion == 'failure' working-directory: ${{env.GITHUB_WORKSPACE}} run: python ci/github/maketestbadge.py ${{env.UNITTEST_REPORT_PATH}} - name: Deploy test badge to gist - uses: exuanbo/actions-deploy-gist@v1 - if: github.event_name != 'pull_request' + if: success() || steps.unit_tests.conclusion == 'failure' + #uses: exuanbo/actions-deploy-gist@v1 + uses: end2endzone/actions-deploy-gist@main with: token: ${{ secrets.BADGES }} gist_id: 58cf6c72c08e706335337d5ef9ca48e8 @@ -98,7 +103,8 @@ jobs: file_path: ./badge.json - name: Archive test results - uses: actions/upload-artifact@v2 + if: success() || steps.unit_tests.conclusion == 'failure' + uses: actions/upload-artifact@v4.3.5 with: name: unit-test-results path: build/bin/bin2cpp_unittest.*.xml @@ -111,7 +117,8 @@ jobs: echo BIN2CPP_VERSION=$(cat build/version)>> $GITHUB_ENV - name: Archive installation packages - uses: actions/upload-artifact@v2 + if: success() || steps.unit_tests.conclusion == 'failure' + uses: actions/upload-artifact@v4.3.5 with: name: Installation packages. path: build/bin2cpp-${{env.BIN2CPP_VERSION}}-*.* diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index c670654..1a65e4b 100755 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -3,7 +3,7 @@ name: Windows on: [push, pull_request] env: - PlatformToolset: v140 + PlatformToolset: v142 # build platform, i.e. x86, x64, Any CPU. This setting is optional. Platform: x64 @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Configure GIT working-directory: ${{env.GITHUB_WORKSPACE}} @@ -30,7 +30,7 @@ jobs: git submodule update --init --recursive - name: Setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: '3.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified @@ -50,7 +50,8 @@ jobs: set - name: Deploy 'tests not available' badge before building - uses: exuanbo/actions-deploy-gist@v1 + #uses: exuanbo/actions-deploy-gist@v1 + uses: end2endzone/actions-deploy-gist@main if: github.event_name != 'pull_request' with: token: ${{ secrets.BADGES }} @@ -74,11 +75,13 @@ jobs: run: call ci\github\install_bin2cpp.bat - name: Run unit tests + id: unit_tests working-directory: ${{env.GITHUB_WORKSPACE}} shell: cmd run: call ci\github\test_script.bat - name: Search unit test report file + if: success() || steps.unit_tests.conclusion == 'failure' working-directory: ${{env.GITHUB_WORKSPACE}} shell: cmd run: | @@ -87,12 +90,14 @@ jobs: echo UNITTEST_REPORT_PATH=%UNITTEST_REPORT_PATH%>> %GITHUB_ENV% - name: Create test badge + if: success() || steps.unit_tests.conclusion == 'failure' working-directory: ${{env.GITHUB_WORKSPACE}} run: python ci\github\maketestbadge.py ${{env.UNITTEST_REPORT_PATH}} - name: Deploy test badge to gist - uses: exuanbo/actions-deploy-gist@v1 - if: github.event_name != 'pull_request' + if: success() || steps.unit_tests.conclusion == 'failure' + #uses: exuanbo/actions-deploy-gist@v1 + uses: end2endzone/actions-deploy-gist@main with: token: ${{ secrets.BADGES }} gist_id: 58cf6c72c08e706335337d5ef9ca48e8 @@ -100,7 +105,8 @@ jobs: file_path: ./badge.json - name: Archive test results - uses: actions/upload-artifact@v2 + if: success() || steps.unit_tests.conclusion == 'failure' + uses: actions/upload-artifact@v4.3.5 with: name: unit-test-results path: build\bin\${{env.Configuration}}\bin2cpp_unittest.*.xml @@ -114,7 +120,8 @@ jobs: echo BIN2CPP_VERSION=%BIN2CPP_VERSION%>> %GITHUB_ENV% - name: Archive installation packages - uses: actions/upload-artifact@v2 + if: success() || steps.unit_tests.conclusion == 'failure' + uses: actions/upload-artifact@v4.3.5 with: name: Installation packages. path: build/bin2cpp-${{env.BIN2CPP_VERSION}}-*.* diff --git a/.gitignore b/.gitignore index 196cfcb..6efc2c7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ /samples/demo_helloworld/outdir /samples/demo_icons/outdir .DS_Store +/samples/demo_website/outdir +/samples/demo_relative_dir/include/bin2cpp +/desktop.ini diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 04dee38..0000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -dist: trusty -sudo: required -language: cpp -os: -- linux -branches: - only: - - master -env: - global: - - BIN2CPP_BUILD_TYPE=Release - -install: -- cd $TRAVIS_BUILD_DIR/ci/travis; ./install_googletest.sh; -- cd $TRAVIS_BUILD_DIR/ci/travis; ./install_rapidassist.sh; - -script: -- cd $TRAVIS_BUILD_DIR/ci/travis; ./install_bin2cpp.sh; - -after_success: -- cd $TRAVIS_BUILD_DIR/ci/travis; ./test_script.sh; - -notifications: - email: true diff --git a/CHANGES b/CHANGES index d966539..6aa8beb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,46 @@ +Changes for 3.1.1: + +* Fixed issue #82: Use the kernel version as a fallback + +Changes for 3.1.0: + +* New feature: Support for generating C code. +* Fixed issue #29: Create arguments to filter files found with '--dir' argument. +* Fixed issue #53: Generate only C code. +* Fixed issue #63: Context class redesign. Move arguments handling into a Context class. +* 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. +* Fixed issue #78: Move duplicated enums from main.cpp to enums.h. + + +Changes for 3.0.1: + +* Fixed issue #68: Update to RapidAssist version 0.11.0 + + +Changes for 3.0.0: + +Note: This version introduces breaking changes. The public API has changed. See notes about automatic identifiers and deprecated method `getFilename()`. +* New feature: Using RapidAssist version 0.10.2 +* New feature: Modified how automatic identifier are generated. New identifiers now includes the file extension. Existing code that uses bin2cpp generated files may not compile anymore. +* New feature: Deprecated method `getFilename()` in favor to `getFileName()`. This is to be more inline with getFilePath(). +* New feature: Calls to FileManager::saveFiles() is now saving all files as the original input directories. +* Fixed issue #51: Support getfilePath api and handle same function identifier. +* Fixed issue #52: Generate only c++ code. +* Fixed issue #54: Output the encoded string in plain format to stdout. +* Fixed issue #56: Problem with certain filenames. +* Fixed issue #59: Silence warning C4996 about deprecated 'std::tr1' namespace - Windows only. +* Fixed issue #58: Mandatory options `--identifier` and `--headerfile` should be calculated automatically if not specified. + + +Changes for 2.5.0: + +* New feature: Using RapidAssist version 0.10.1 +* Fixed issue #55: Support for large files. + + Changes for 2.4.0: * New feature: Using RapidAssist version 0.10.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6882968..c347185 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,11 @@ MESSAGE( STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR} ) MESSAGE( STATUS "CMAKE_HOST_SYSTEM_PROCESSOR: " ${CMAKE_HOST_SYSTEM_PROCESSOR} ) MESSAGE( STATUS "CMAKE_SYSTEM_INFO_FILE: " ${CMAKE_SYSTEM_INFO_FILE} ) +function(get_major_version VERSION_STRING OUTPUT_VARIABLE) + string(REGEX MATCH "^([0-9]+)" MAJOR_VERSION ${VERSION_STRING}) + set(${OUTPUT_VARIABLE} "${CMAKE_MATCH_1}" PARENT_SCOPE) +endfunction() + # Get OS name and version. include(GetOsReleaseInfo) if (WIN32) @@ -61,13 +66,35 @@ if (WIN32) elseif (APPLE) # Get MacOS release info. GetOsReleaseInfo(MAC_RELEASE_NAME MAC_RELEASE_VER) + + # MAC_RELEASE_NAME used to resolve to something like `macOS Catalina`. Now On Github's Action, + # the output is `macOS Unknown`. If the code name of the OS is Unknown, it is better to remove it completely. + # Replace ` Unknown` by ``. + string(REPLACE " Unknown" "" MAC_RELEASE_NAME "${MAC_RELEASE_NAME}") + + # Extract release MAJOR version + get_major_version(${MAC_RELEASE_VER} MAC_RELEASE_VER_MAJOR) + MESSAGE( STATUS "MAC_RELEASE_NAME: " ${MAC_RELEASE_NAME} ) MESSAGE( STATUS "MAC_RELEASE_VER: " ${MAC_RELEASE_VER} ) + MESSAGE( STATUS "MAC_RELEASE_VER_MAJOR: " ${MAC_RELEASE_VER_MAJOR} ) elseif (UNIX) # Get Linux distribution info. GetOsReleaseInfo(LINUX_DIST_NAME LINUX_DIST_VER ) + + if("${LINUX_DIST_VER}" STREQUAL "") + # Use the kernel version as a fallback + execute_process(COMMAND uname -r + OUTPUT_VARIABLE LINUX_DIST_VER + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + + # Extract distribution MAJOR version + get_major_version("${LINUX_DIST_VER}" LINUX_DIST_VER_MAJOR) + MESSAGE( STATUS "LINUX_DIST_NAME: " ${LINUX_DIST_NAME} ) MESSAGE( STATUS "LINUX_DIST_VER: " ${LINUX_DIST_VER} ) + MESSAGE( STATUS "LINUX_DIST_VER_MAJOR: " ${LINUX_DIST_VER_MAJOR} ) endif() @@ -76,12 +103,19 @@ endif() ############################################################################################################################################## # Product version according to Semantic Versioning v2.0.0 https://semver.org/ -SET(BIN2CPP_VERSION_MAJOR 2) -SET(BIN2CPP_VERSION_MINOR 4) +SET(BIN2CPP_VERSION_MAJOR 3) +SET(BIN2CPP_VERSION_MINOR 1) SET(BIN2CPP_VERSION_PATCH 0) set(BIN2CPP_VERSION ${BIN2CPP_VERSION_MAJOR}.${BIN2CPP_VERSION_MINOR}.${BIN2CPP_VERSION_PATCH}) FILE(WRITE ${CMAKE_BINARY_DIR}/version "${BIN2CPP_VERSION}") +# Force c++ 11 +# https://www.reddit.com/r/cpp_questions/comments/1d4tt8a/comment/l6gqea5/ +# My guess is that you are on mac and using g++ to compile. For godforsaken reasons, g++ by default is an alias to clang++ forced into some crazy C++98 mode. +# https://stackoverflow.com/questions/10851247/how-do-i-activate-c-11-in-cmake +set (CMAKE_CXX_STANDARD 11) +set (CMAKE_CXX_STANDARD_REQUIRED TRUE) + # Create a c++ file header from the project LICENSE file. # The c++ header will be added to all generated files. include(MakeCplusplusHeader) @@ -130,6 +164,7 @@ endif() # Prevents annoying warnings on MSVC if (WIN32) add_definitions(-D_CRT_SECURE_NO_WARNINGS) + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) endif() # Define include directories for source code. @@ -159,6 +194,9 @@ add_subdirectory(src/bin2cpp) # unit tests if(BIN2CPP_BUILD_TEST) + # Create a temp directory under the build directory to output temporary files. + make_directory(${CMAKE_CURRENT_BINARY_DIR}/temp) + add_subdirectory(test/testfilegenerator) add_subdirectory(test/bin2cpp_unittest) endif() @@ -167,6 +205,8 @@ endif() if(BIN2CPP_BUILD_SAMPLES) add_subdirectory(samples/demo_helloworld) add_subdirectory(samples/demo_icons) + add_subdirectory(samples/demo_relative_dir) + add_subdirectory(samples/demo_website) endif() ############################################################################################################################################## @@ -205,7 +245,10 @@ endif() # On Windows, installs to "C:\Program Files (x86)\${PROJECT_NAME}" or to "C:\Program Files\${PROJECT_NAME}" for 64 bit binaries install(DIRECTORY ${CMAKE_SOURCE_DIR}/licenses DESTINATION ${BIN2CPP_INSTALL_ROOT_DIR}) -install(DIRECTORY ${CMAKE_SOURCE_DIR}/samples DESTINATION ${BIN2CPP_INSTALL_ROOT_DIR}) +install(DIRECTORY ${CMAKE_SOURCE_DIR}/samples DESTINATION ${BIN2CPP_INSTALL_ROOT_DIR} + PATTERN "outdir" EXCLUDE + PATTERN "outdir/*" EXCLUDE +) install(FILES ${CMAKE_SOURCE_DIR}/README.md ${CMAKE_SOURCE_DIR}/CONTRIBUTING.md @@ -280,8 +323,8 @@ elseif (APPLE) string(TOLOWER "${MAC_RELEASE_NAME}" MAC_RELEASE_NAME) string(REPLACE " " "." MAC_RELEASE_NAME "${MAC_RELEASE_NAME}") - # Updating the package filename to `bin2cpp-2.4.0-macos.catalina-x86_64.tar.gz`. - set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${MAC_RELEASE_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}") + # Updating the package filename to `bin2cpp-2.4.0-macos.catalina.10-x86_64.tar.gz` or `bin2cpp-3.0.1-macos.14-arm64.tar.gz`. + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${MAC_RELEASE_NAME}.${MAC_RELEASE_VER_MAJOR}-${CMAKE_HOST_SYSTEM_PROCESSOR}") elseif (UNIX) # Default package filename example : `bin2cpp-2.4.0-Linux.tar.gz`. # @@ -294,8 +337,8 @@ elseif (UNIX) string(TOLOWER "${LINUX_DIST_NAME}" LINUX_DIST_NAME) string(REPLACE " " "." LINUX_DIST_NAME "${LINUX_DIST_NAME}") - # Updating the package filename to `bin2cpp-2.4.0-ubuntu-x86_64.tar.gz`. - set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${LINUX_DIST_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}") + # Updating the package filename to `bin2cpp-3.0.1-ubuntu.24-x86_64.tar.gz` or `bin2cpp-3.0.1-centos.10-x86_64.tar.gz`. + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${LINUX_DIST_NAME}.${LINUX_DIST_VER_MAJOR}-${CMAKE_HOST_SYSTEM_PROCESSOR}") endif() diff --git a/INSTALL.md b/INSTALL.md index 6d646b7..35362d3 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -27,7 +27,7 @@ This section explains how to compile and build the software and how to get a dev The following software must be installed on the system for compiling source code: * [Google C++ Testing Framework v1.8.0](https://github.com/google/googletest/tree/release-1.8.0) -* [RapidAssist v0.10.0](https://github.com/end2endzone/RapidAssist/tree/0.10.0) +* [RapidAssist v0.11.0](https://github.com/end2endzone/RapidAssist/tree/0.11.0) * [CMake](http://www.cmake.org/) v3.4.3 (or newer) diff --git a/README.md b/README.md index e00ca03..4bee374 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,11 @@ [![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 or C++ code (a function) that when called allows a program to retrieve the content of the input binary file. + -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. ## Status @@ -16,16 +18,11 @@ Build: | Service/Platform | Build | Tests | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | AppVeyor | [![Build status](https://img.shields.io/appveyor/ci/end2endzone/bin2cpp/master.svg?logo=AppVeyor&logoColor=white)](https://ci.appveyor.com/project/end2endzone/bin2cpp) | [![Tests status](https://img.shields.io/appveyor/tests/end2endzone/bin2cpp/master.svg?logo=AppVeyor&logoColor=white)](https://ci.appveyor.com/project/end2endzone/bin2cpp/branch/master/tests) | -| Travis CI | [![Build Status](https://img.shields.io/travis/end2endzone/bin2cpp/master.svg?logo=Travis-CI&style=flat&logoColor=white)](https://travis-ci.org/end2endzone/bin2cpp) | | | Windows Server 2019 | [![Build on Windows](https://github.com/end2endzone/bin2cpp/actions/workflows/build_windows.yml/badge.svg)](https://github.com/end2endzone/bin2cpp/actions/workflows/build_windows.yml) | [![Tests on Windows](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/end2endzone/58cf6c72c08e706335337d5ef9ca48e8/raw/bin2cpp.master.Windows.json)](https://github.com/end2endzone/bin2cpp/actions/workflows/build_windows.yml) | | 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 @@ -35,22 +32,31 @@ It is designed to be easy to use by developers and to provide easy call function The generated functions that reads and extracts the embedded content does not rely on external libraries so you don't need to setup your projects to use any third party library to start using bin2cpp. All your embedded data can be accessed right away. + + + # Features 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. +* Supports encoding and extracting files with a custom directory structure. * 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. -* File's originals `size` and `filename` properties available from generated source code. -* Source code control: select a custom file interface and namespace. +* Supports different types of code generator: string, segment, array, win32 resources. +* 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 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. @@ -62,44 +68,81 @@ The following list show situations where bin2cpp is useful: * Allowing an executable to be downloaded from an intranet server as a single file. * Distributing an application without an installer package. All configurations files and resources can be embedded and extracted at first launch of the application. + + + # Usage The following section shows how to use bin2cpp with code examples: -## Command Line Usage + +## Command Line Usage ``` -bin2cpp --file= --output= --headerfile= --identifier= +bin2cpp --file= --output= [--headerfile=] [--identifier=] [--generator=] [--encoding=] [--chunksize=] [--namespace=] - [--baseclass=] [--managerfile=] [--namespace=] [--registerfile] + [--baseclass=] [--managerfile=] [--registerfile] [--code] + [--reportedfilepath=] [--plainoutput] [--override] [--noheader] [--quiet] +bin2cpp --dir= --output= [--keepdirs] + [--generator=] [--encoding=] [--chunksize=] [--namespace=] + [--baseclass=] [--managerfile=] [--registerfile] [--code] + [--dirincludefilter=] [--direxcludefilter=] [--override] [--noheader] [--quiet] bin2cpp --help bin2cpp --version ``` -| Argument | Description | -| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| --help | Display this help message. | -| --version | Display this application version. | -| --file= | Path of the input file used for embedding as C++ source code. | -| --dir= | Path of the input directory used for embedding all files of the directory as C++ source code. When specified, the parameters 'headerfile' and 'identifier' are automatically calculated and cannot be manually specified. | -| --output= | Output folder where to create generated code. ie: .\generated_files | -| --headerfile= | File name of the generated C++ header file. ie: SplashScreen.h | -| --generator= | Name of the generator to use. Possible values are 'segment', 'string', 'array' and 'win32'. [default: segment]. | -| --encoding= | Name of the binary to string literal encoding to use. Possible values are 'oct' and 'hex'. [default: oct]. | -| --identifier= | Identifier of the function name that is used to get an instance of the file. ie: SplashScreen | -| --chunksize= | Size in bytes of each string segments (bytes per row). [default: 200]. | -| --baseclass= | The name of the interface for embedded files. [default: File]. | -| --namespace= | The namespace of the generated source code [default: bin2cpp]. | -| --managerfile= | File name of the generated C++ header file for the FileManager class. ie: FileManager.h. | -| --registerfile | Register the generated file to the FileManager class. This flags is automatically set when parameter 'managerfile' is specified. [default: false]. | -| --override | Tells bin2cpp to overwrite the destination files. | -| --noheader | Do not print program header to standard output. | -| --quiet | Do not log any message to standard output. | +| Argument | Description | +|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| --help | Display this help message. | +| --version | Display this application version. | +| --file=<path> | Path of the input file used for embedding as C++ source code. | +| --dir=<path> | Path of the input directory used for embedding all files of the directory as C++ source code. | +| --output=<path> | Path of the output directory where to create generated code.
ie: ./generated_files | +| --headerfile=<name> | File name or relative path of the generated C++ header file. If a relative path from the output directory is specified, the #include statement in the generated cpp file will match the relative path.
ie: SplashScreen.h
Default value: input file name (without extension) | +| --identifier=<name> | Identifier of the function name that is used to get an instance of the file.
ie: SplashScreen
Default value is based on input file with format 'NameExt'. | +| --generator=<name> | Name of the generator to use. Possible values are 'segment', 'string', 'array' and 'win32'.
[default: segment] | +| --encoding=<name> | Name of the binary to string literal encoding to use. Possible values are 'oct' and 'hex'.
[default: oct] | +| --chunksize=<value> | Size in bytes of each string segments (bytes per LoC).
[default: 200] | +| --baseclass=<name> | The name of the interface for embedded files. [default: File]
For C generated code, this parameter is for naming the File structure. [default: Bin2cFile] | +| --namespace=<name> | The namespace of the generated source code. [default: bin2cpp]
For C generated code, this parameter is for setting the prefix of all function names. [default: bin2c] | +| --reportedfilepath=<path> | The relative reported path of the File. Path returned when calling method getFilePath() of the File class. Automatically calculated when --dir mode is used.
ie: images/DCIM/IMG_0001.jpg | +| --managerfile=<path> | File name or relative path of the generated C++ header file for the FileManager class.
ie: FileManager.h. | +| --registerfile | Register the generated file to the FileManager class. This flags is automatically set when parameter 'managerfile' is specified. | +| --dirincludefilter=<value>| Set a positive filter on the input directory to only select files matching the filter. Wildcard characters are accepted. Separate each filter with the character ':'. Valid only when --dir is used. See wildcard characters definition below. | +| --direxcludefilter=<value>| Set a negative filter on the input directory to skip files matching the filter. Wildcard characters are accepted. Separate each filter with the character ':'. Valid only when --dir is used. See wildcard characters definition below. The exclude filter has precedence over the include filter. | +| --keepdirs | Keep the directory structure. Forces the output files to have the same directory structure as the input files. Valid only when --dir is used. | +| --plainoutput | Print the encoded string in plain format to stdout. Useful for scripts and integration with third party application. | +| --code | Define the programming language output for code generation. Supported values are `c`, `cpp` or `c++`. | +| --override | Tells bin2cpp to overwrite the destination files. | +| --noheader | Do not print program header to standard output. | +| --quiet | Do not log any message to standard output. | + +  + +Wildcard characters: +| Wildcard | Description | +|:-----------:|--------------------------------------------------------------| +| `?` | Matches any single character. | +| `*` | Matches zero or more characters. | +| `#` | Matches exactly one numeric digit (0-9). | +| [charlist] | Matches any single character inside the brackets. | +| [a-z] | Matches any single lowercase letter between 'a' and 'z'. | +| [A-Z] | Matches any single uppercase letter between 'A' and 'A'. | +| [0-9] | Matches any single digit between '0' and '9'. | +| [a-zA-Z0-9] | Matches any single letter (uppercase or lowercase) or digit. | + +For example: +* `ker*##.???` matches files that starts with `ker`, and ends with 2 digits, a dot and then 3 characters. +* `--dir-include-filter="*.jpg:*.png"` includes all files whose file extension is `jpg` or `png`. +* `--dir-exclude-filter="*.bak"` excludes all backup files. +* `--dir-include-filter="*.log" --dir-exclude-filter="debug.log"` includes all log files but not the one specificaly named `debug.log`. + ## Example 1 - single file -This examples shows how to use bin2cpp to convert a single html file to c++ source code. +This example shows how to use bin2cpp to convert a single html file to c++ source code. + ### Input file: helloworld.html @@ -117,36 +160,38 @@ Hello World! ``` + ### Command: ``` -bin2cpp.exe --file=helloworld.html --output=.\outdir --headerfile=generated_helloworld.h - --identifier=HelloWorldHtml --chunksize=50 +bin2cpp.exe --file=helloworld.html --output=.\outdir ``` + ### Console output ``` -bin2cpp v2.4.0 - Convert binary files into C++ source code. +bin2cpp v3.0.0 - Convert binary files into C++ source code. Copyright (C) 2013-2021 end2endzone.com. All rights reserved. bin2cpp is open source software, see http://github.com/end2endzone/bin2cpp -Embedding "helloworld.html" using chunks of 50 bytes... -Writing file ".\outdir\generated_helloworld.h"... -Writing file ".\outdir\generated_helloworld.cpp"... +Embedding "helloworld.html"... +Writing file ".\outdir\helloworld.h"... +Writing file ".\outdir\helloworld.cpp"... ``` -### Output file: generated_helloworld.h + +### Output file: helloworld.h ```cpp /** - * This file was generated by bin2cpp v2.4.0 + * This file was generated by bin2cpp v3.0.0 * Copyright (C) 2013-2021 end2endzone.com. All rights reserved. * bin2cpp is open source software, see http://github.com/end2endzone/bin2cpp * Source code for file 'helloworld.html', last modified 1548537787. * Do not modify this file. */ -#ifndef GENERATED_HELLOWORLD_H -#define GENERATED_HELLOWORLD_H +#ifndef HELLOWORLD_H +#define HELLOWORLD_H #include @@ -158,22 +203,24 @@ namespace bin2cpp { public: virtual size_t getSize() const = 0; - virtual const char * getFilename() const = 0; + virtual const char * getFileName() const = 0; + virtual const char * getFilePath() const = 0; virtual const char * getBuffer() const = 0; - virtual bool save(const char * iFilename) const = 0; + virtual bool save(const char * filename) const = 0; }; #endif //BIN2CPP_EMBEDDEDFILE_CLASS - const File & getHelloWorldHtmlFile(); + const File & getHelloworldHtmlFile(); }; //bin2cpp -#endif //GENERATED_HELLOWORLD_H +#endif //HELLOWORLD_H ``` -### Output file: generated_helloworld.cpp + +### Output file: helloworld.cpp ```cpp /** - * This file was generated by bin2cpp v2.4.0 + * This file was generated by bin2cpp v3.0.0 * Copyright (C) 2013-2021 end2endzone.com. All rights reserved. * bin2cpp is open source software, see http://github.com/end2endzone/bin2cpp * Source code for file 'helloworld.html', last modified 1548537787. @@ -182,46 +229,46 @@ namespace bin2cpp #if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS #endif -#include "generated_helloworld.h" -#include //for FILE -#include //for memcpy +#include "helloworld.h" +#include //for std::string +#include +#include //for ofstream namespace bin2cpp { - class HelloWorldHtmlFile : public virtual bin2cpp::File + class HelloworldHtmlFile : public virtual bin2cpp::File { public: - HelloWorldHtmlFile() { build(); } - virtual ~HelloWorldHtmlFile() {} + HelloworldHtmlFile() { build(); } + virtual ~HelloworldHtmlFile() {} virtual size_t getSize() const { return 238; } - virtual const char * getFilename() const { return "helloworld.html"; } + virtual const char * getFileName() const { return "helloworld.html"; } + virtual const char * getFilePath() const { return getFileName(); } virtual const char * getBuffer() const { return mBuffer.c_str(); } void build() { mBuffer.clear(); mBuffer.reserve(getSize()); //allocate all required memory at once to prevent reallocations - mBuffer.append("\r\n\r\n\r\n \r\n \r\n Hello World!\r\n \r\n", 50); + mBuffer.append("\r\n\r\n\r\n \r\n \r\n Hello World!\r\n \r\n", 200); mBuffer.append("\r\nHello World!\r\n\r\n", 38); } - virtual bool save(const char * iFilename) const + virtual bool save(const char * filename) const { - FILE * f = fopen(iFilename, "wb"); - if (!f) return false; + std::ofstream f(filename, std::ios::out | std::ios::binary | std::ios::trunc); + if (f.fail()) return false; size_t fileSize = getSize(); const char * buffer = getBuffer(); - fwrite(buffer, 1, fileSize, f); - fclose(f); + f.write(buffer, fileSize); + f.close(); return true; } private: std::string mBuffer; }; - const File & getHelloWorldHtmlFile() { static HelloWorldHtmlFile _instance; return _instance; } + const File & getHelloworldHtmlFile() { static HelloworldHtmlFile _instance; return _instance; } }; //bin2cpp ``` + ### Code sample (querying the generated code) At runtime, show file properties and save/export data back to a file. @@ -229,36 +276,41 @@ At runtime, show file properties and save/export data back to a file. ```cpp #include #include -#include "generated_helloworld.h" //a single include file is all you need +#include + +#include "helloworld.h" //a single include file is all you need int main(int argc, char* argv[]) { //get a reference to the embedded file - const bin2cpp::File & resource = bin2cpp::getHelloWorldHtmlFile(); + const bin2cpp::File & resource = bin2cpp::getHelloworldhtmlFile(); //print information about the file. - printf("Embedded file '%s' is %lu bytes long.\n", resource.getFilename(), resource.getSize()); + std::cout << "Embedded file '" << resource.getFileName() << "' is " << resource.getSize() << " bytes long.\n"; //Saving content back to a file. - printf("Saving embedded file to 'helloworld_copy.html'...\n"); + std::cout << " Saving embedded file to 'helloworld_copy.html'...\n"; bool saved = resource.save("helloworld_copy.html"); if (saved) - printf("saved\n"); + std::cout << "saved\n"; else - printf("failed\n"); + std::cout << "failed\n"; //Get the internal buffer and do something with the binary data const char * buffer = resource.getBuffer(); size_t bufferSize = resource.getSize(); //... - + return 0; } ``` -## Examples 2 - directory -This examples shows how to use bin2cpp to convert multiple files of the same directory to c++ source code. + +## Example 2 - directory + +This example shows how to use bin2cpp to convert multiple files of the same directory to c++ source code. + ### Input directory: [samples/demo_icons/flat-color-icons](samples/demo_icons/flat-color-icons). @@ -268,16 +320,18 @@ The [samples/demo_icons/flat-color-icons](samples/demo_icons/flat-color-icons) d These icons are from the *Very Basic* set of [Icons8 Flat Color Icons](https://github.com/icons8/flat-color-icons) and are licensed under the [Good Boy License](https://icons8.com/good-boy-license). + ### Command: ``` bin2cpp.exe --dir=flat-color-icons --managerfile=IconsFileManager.h --output=.\outdir --chunksize=50 ``` + ### Console output ``` -bin2cpp v2.4.0 - Convert binary files into C++ source code. +bin2cpp v3.0.0 - Convert binary files into C++ source code. Copyright (C) 2013-2021 end2endzone.com. All rights reserved. bin2cpp is open source software, see http://github.com/end2endzone/bin2cpp Embedding "flat-color-icons\about.png" using chunks of 50 bytes... @@ -297,6 +351,7 @@ Writing file ".\outdir\IconsFileManager.cpp"... Notice that additional files `IconsFileManager.h` and `IconsFileManager.cpp` were also generated and will allow retreiving all files at once. + ### Code sample (querying the generated code) At runtime, show a file listing and save/export the icons files in users temporary directory. @@ -304,6 +359,7 @@ At runtime, show a file listing and save/export the icons files in users tempora ```cpp #include // printf #include // getenv +#include #include "IconsFileManager.h" @@ -313,28 +369,29 @@ int main(int argc, char* argv[]) //Print information about all files generated with "--managerfile" or --registerfile flags. size_t num_files = mgr.getFileCount(); - printf("Found %lu embedded icon files...\n", num_files); + std::cout << "Found " << num_files << " embedded icons...\n"; //Listing files. for(size_t i=0; igetFilename(), file->getSize()); + std::cout << " File '" << file->getFileName() << "', " << file->getSize() << " bytes\n"; } //Saving content back to files. const char * temp_dir = getenv("TEMP"); - printf("Saving embedded icons to directory '%s'...\n", temp_dir); + std::cout << "Saving embedded icons to directory '" << temp_dir << "'...\n"; bool saved = mgr.saveFiles(temp_dir); if (saved) - printf("saved\n"); + std::cout << "saved\n"; else - printf("failed\n"); + std::cout << "failed\n"; return 0; } ``` + ### Console output ``` @@ -362,6 +419,233 @@ Saving embedded icons to directory 'C:\Users\foobar\AppData\Local\Temp'... saved ``` + + +## Example 3 - relative header file (project's *include* directory) + +This example shows how to use bin2cpp to generate files in a relative sub directory based on the project's root directory. + +Many projects has an *include* directory located at the project's root directory. These projects are usually configured to add *$ROOT_DIR/include* to the list of include directories. bin2cpp can be configured to take advantage of this situation. + +If you output files in the *include* directory (with the command `--output=$ROOT_DIR/include --headerfile=foo.h`), the generated `#include "foo.h"` statement will have no problem finding the generated header. However if you want the generated files to be in a sub directory (for example with the command `--output=$ROOT_DIR/include/bin2cpp`), this won't work since you would need the sub directory path in the include statement. + +The solution is to specify a *relative path* for the header file which also changes the generated `#include` statement. For example, the command `--output=$ROOT_DIR/include --headerfile=bin2cpp/foo.h`), generates `#include "bin2cpp/foo.h"` which is perfect since `$ROOT_DIR/include` is already an include directory. + +This example shows how to specify a relative path for the header file. + + + +### Command: + +``` +bin2cpp.exe --file=res/icon.ico --output=include --headerfile=bin2cpp/file_icon.h --identifier=icon +``` + +Note the *bin2cpp* sub directory in `--headerfile=bin2cpp/file_icon.h`. The output sub directory must already exists. + + + +### Console output + +``` +bin2cpp v3.0.0 - Convert binary files into C++ source code. +Copyright (C) 2013-2021 end2endzone.com. All rights reserved. +bin2cpp is open source software, see http://github.com/end2endzone/bin2cpp +Embedding "res/icon.ico"... +Writing file "include/bin2cpp/file_icon.h"... +Writing file "include/bin2cpp/file_icon.cpp"... +``` + + + +### Output file: file_icon.cpp + +Here are the first few generated lines of file `file_icon.cpp`. + +```cpp +/** + * This file was generated by bin2cpp v3.0.0 + * Copyright (C) 2013-2021 end2endzone.com. All rights reserved. + * bin2cpp is open source software, see http://github.com/end2endzone/bin2cpp + * Source code for file 'icon.ico', last modified 1548537787. + * Do not modify this file. + */ +#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "bin2cpp/file_icon.h" +#include //for std::string +#include +#include //for ofstream +... +``` + +Note the `#include "bin2cpp/file_icon.h"` statement which is relative to the project's *include* directory. + + + +## Example 4 - web site (embedding directory structure) + +This example shows how to use bin2cpp to convert files from multiple directories to c++ source code. The input directory structure and file location are preserved. + + +### Input directory: [samples/demo_website/www](samples/demo_website/www). + +The [samples/demo_website/www](samples/demo_website/www) directory contains web pages in the following directory structure : + +``` +www +├── blog +│ ├── how-to-create-a-web-site +│ │ └── index.html +│ ├── index.html +│ └── using-bin2cpp +│ └── index.html +├── contact +│ └── index.html +├── home +│ └── index.html +└── index.html +``` + +The directories above contains multiple files named `index.html`. + +bin2cpp can create unique identifiers for each files. In case of duplicate identifiers, bin2cpp appends a counter that increases by 1 on every duplicate. The pattern `_` is added to the end where `` is the next counter value. For example, the files above create the following identifiers: + * Indexhtml + * Indexhtml_1 + * Indexhtml_2 + * Indexhtml_3 + * Indexhtml_4 + * Indexhtml_5 + +The same strategy is implemented for duplicate file names. + + +### Command: + +``` +bin2cpp.exe --dir=www --managerfile=PagesFileManager.h --namespace=www --output=.\outdir --chunksize=50 --keepdirs +``` + +Note the `--keepdirs` command line option which keep the input directory structure and allows the output files to have the same directory structure as the input files. This prevents duplicate file names. + + +### Console output + +``` +bin2cpp v3.0.0 - Convert binary files into C++ source code. +Copyright (C) 2013-2021 end2endzone.com. All rights reserved. +bin2cpp is open source software, see http://github.com/end2endzone/bin2cpp +Embedding "www\blog\how-to-create-a-web-site\index.html" using chunks of 50 bytes... +Creating directory ".\outdir\blog\how-to-create-a-web-site"... +Writing file ".\outdir\blog\how-to-create-a-web-site\index.h"... +Writing file ".\outdir\blog\how-to-create-a-web-site\index.cpp"... +Embedding "www\blog\index.html" using chunks of 50 bytes... +Writing file ".\outdir\blog\index.h"... +Writing file ".\outdir\blog\index.cpp"... +Embedding "www\blog\using-bin2cpp\index.html" using chunks of 50 bytes... +Creating directory ".\outdir\blog\using-bin2cpp"... +Writing file ".\outdir\blog\using-bin2cpp\index.h"... +Writing file ".\outdir\blog\using-bin2cpp\index.cpp"... +Embedding "www\contact\index.html" using chunks of 50 bytes... +Creating directory ".\outdir\contact"... +Writing file ".\outdir\contact\index.h"... +Writing file ".\outdir\contact\index.cpp"... +Embedding "www\home\index.html" using chunks of 50 bytes... +Creating directory ".\outdir\home"... +Writing file ".\outdir\home\index.h"... +Writing file ".\outdir\home\index.cpp"... +Embedding "www\index.html" using chunks of 50 bytes... +Writing file ".\outdir\index.h"... +Writing file ".\outdir\index.cpp"... +Generating "PagesFileManager.h"... +Writing file ".\outdir\PagesFileManager.h"... +Writing file ".\outdir\PagesFileManager.cpp"... +``` + +Notice that files `PagesFileManager.h` and `PagesFileManager.cpp` were also generated. They provide support for extracting the content of the embedded ***www*** directory. + + +### Code sample (querying the generated code) + +At runtime, show a file listing and save/export all `index.html` files in the right directories. + +```cpp +#include // printf +#include // getenv +#include +#include + +#include "PagesFileManager.h" + +int main(int argc, char* argv[]) +{ + www::FileManager & mgr = www::FileManager::getInstance(); + + //Print information about all files generated with "--managerfile" or --registerfile flags. + size_t num_files = mgr.getFileCount(); + std::cout << "Found " << num_files << " embedded web pages...\n"; + + //Listing files. + for(size_t i=0; igetFilePath() << "', " << file->getSize() << " bytes\n"; + } + + //Saving content back to files preserving the original directory structure. + std::string temp_dir = getenv("TEMP"); +#ifdef _Win32 + temp_dir += "\\"; +#else + temp_dir += "/"; +#endif + temp_dir += "www"; + std::cout << "Saving embedded web pages to directory '" << temp_dir << "'...\n"; + bool saved = mgr.saveFiles(temp_dir.c_str()); + if (saved) + std::cout << "saved\n"; + else + std::cout << "failed\n"; + + return 0; +} +``` + + +### Console output + +``` +Found 6 embedded web pages... + File 'index.html', 241 bytes + File 'blog\index.html', 543 bytes + File 'blog\using-bin2cpp\index.html', 4332 bytes + File 'blog\how-to-create-a-web-site\index.html', 3645 bytes + File 'contact\index.html', 2375 bytes + File 'home\index.html', 1422 bytes +Saving embedded web pages to directory 'C:\Users\foobar\AppData\Local\Temp\www'... +saved +``` + +The executed code above has extracted the files above with the following directory structure: + +``` +C:\Users\username\AppData\Local\Temp\www +├── blog +│ ├── how-to-create-a-web-site +│ │ └── index.html +│ ├── index.html +│ └── using-bin2cpp +│ └── index.html +├── contact +│ └── index.html +├── home +│ └── index.html +└── index.html +``` + + + ## Screenshots [![bin2cpp v2.4.0 Sample](docs/bin2cpp-v2.4.0-sample.png)](docs/bin2cpp-v2.4.0-sample.png) @@ -372,10 +656,16 @@ bin2cpp v2.4.0 Sample Demo extraction sample + + + # Build Please refer to file [INSTALL.md](INSTALL.md) for details on how installing/building the application. + + + # Platform bin2cpp has been tested with the following platform: @@ -384,16 +674,25 @@ bin2cpp has been tested with the following platform: * Windows, 32 and 64 bit * macOS, 32 and 64 bit + + + # Versioning We use [Semantic Versioning 2.0.0](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/end2endzone/bin2cpp/tags). + + + # Authors * **Antoine Beauchamp** - *Initial work* - [end2endzone](https://github.com/end2endzone) See also the list of [contributors](https://github.com/end2endzone/bin2cpp/blob/master/AUTHORS) who participated in this project. + + + # License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details diff --git a/appveyor.yml b/appveyor.yml index c6fbf98..cfcfd16 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,6 +17,7 @@ version: "{branch} (#{build})" branches: only: - master + - /feature-issue.*/ # Do not build on tags (GitHub and BitBucket) skip_tags: true @@ -26,7 +27,7 @@ skip_tags: true #---------------------------------# # Build worker image (VM template) -image: Visual Studio 2015 +image: Visual Studio 2019 # scripts that are called at very beginning, before repo cloning init: @@ -38,7 +39,6 @@ clone_folder: c:\projects\bin2cpp # scripts that run after cloning repository install: -- cmd: echo INSTALL! - cmd: git submodule update --init --recursive #---------------------------------# @@ -46,7 +46,7 @@ install: #---------------------------------# environment: - PlatformToolset: v140 + PlatformToolset: v142 # build platform, i.e. x86, x64, Any CPU. This setting is optional. Platform: x64 diff --git a/ci/linux/build_all_debug.sh b/ci/linux/build_all_debug.sh index 0d7a58b..6e3d1c9 100755 --- a/ci/linux/build_all_debug.sh +++ b/ci/linux/build_all_debug.sh @@ -1,23 +1,23 @@ # Any commands which fail will cause the shell script to exit immediately set -e -# Set BIN2CPP_SOURCE_DIR root directory -if [ "$BIN2CPP_SOURCE_DIR" = "" ]; then +# Set PRODUCT_SOURCE_DIR root directory +if [ "$PRODUCT_SOURCE_DIR" = "" ]; then RESTORE_DIRECTORY="$PWD" cd "$(dirname "$0")" cd ../.. - export BIN2CPP_SOURCE_DIR="$PWD" - echo "BIN2CPP_SOURCE_DIR set to '$BIN2CPP_SOURCE_DIR'." + export PRODUCT_SOURCE_DIR="$PWD" + echo "PRODUCT_SOURCE_DIR set to '$PRODUCT_SOURCE_DIR'." cd "$RESTORE_DIRECTORY" unset RESTORE_DIRECTORY fi # Set debug or release build type -export BIN2CPP_BUILD_TYPE=Debug -echo "BIN2CPP_BUILD_TYPE set to '$BIN2CPP_BUILD_TYPE'." +export PRODUCT_BUILD_TYPE=Debug +echo "PRODUCT_BUILD_TYPE set to '$PRODUCT_BUILD_TYPE'." # Call all build scripts one by one. -cd "$BIN2CPP_SOURCE_DIR/ci/linux" && ./install_googletest.sh; -cd "$BIN2CPP_SOURCE_DIR/ci/linux" && ./install_rapidassist.sh; -cd "$BIN2CPP_SOURCE_DIR/ci/linux" && ./install_bin2cpp.sh; -cd "$BIN2CPP_SOURCE_DIR/ci/linux" && ./test_script.sh; +cd "$PRODUCT_SOURCE_DIR/ci/linux" && ./install_googletest.sh; +cd "$PRODUCT_SOURCE_DIR/ci/linux" && ./install_rapidassist.sh; +cd "$PRODUCT_SOURCE_DIR/ci/linux" && ./install_bin2cpp.sh; +cd "$PRODUCT_SOURCE_DIR/ci/linux" && ./test_script.sh; diff --git a/ci/linux/build_all_release.sh b/ci/linux/build_all_release.sh index 2e738a8..aced567 100755 --- a/ci/linux/build_all_release.sh +++ b/ci/linux/build_all_release.sh @@ -1,23 +1,23 @@ # Any commands which fail will cause the shell script to exit immediately set -e -# Set BIN2CPP_SOURCE_DIR root directory -if [ "$BIN2CPP_SOURCE_DIR" = "" ]; then +# Set PRODUCT_SOURCE_DIR root directory +if [ "$PRODUCT_SOURCE_DIR" = "" ]; then RESTORE_DIRECTORY="$PWD" cd "$(dirname "$0")" cd ../.. - export BIN2CPP_SOURCE_DIR="$PWD" - echo "BIN2CPP_SOURCE_DIR set to '$BIN2CPP_SOURCE_DIR'." + export PRODUCT_SOURCE_DIR="$PWD" + echo "PRODUCT_SOURCE_DIR set to '$PRODUCT_SOURCE_DIR'." cd "$RESTORE_DIRECTORY" unset RESTORE_DIRECTORY fi # Set debug or release build type -export BIN2CPP_BUILD_TYPE=Release -echo "BIN2CPP_BUILD_TYPE set to '$BIN2CPP_BUILD_TYPE'." +export PRODUCT_BUILD_TYPE=Release +echo "PRODUCT_BUILD_TYPE set to '$PRODUCT_BUILD_TYPE'." # Call all build scripts one by one. -cd "$BIN2CPP_SOURCE_DIR/ci/linux" && ./install_googletest.sh; -cd "$BIN2CPP_SOURCE_DIR/ci/linux" && ./install_rapidassist.sh; -cd "$BIN2CPP_SOURCE_DIR/ci/linux" && ./install_bin2cpp.sh; -cd "$BIN2CPP_SOURCE_DIR/ci/linux" && ./test_script.sh; +cd "$PRODUCT_SOURCE_DIR/ci/linux" && ./install_googletest.sh; +cd "$PRODUCT_SOURCE_DIR/ci/linux" && ./install_rapidassist.sh; +cd "$PRODUCT_SOURCE_DIR/ci/linux" && ./install_bin2cpp.sh; +cd "$PRODUCT_SOURCE_DIR/ci/linux" && ./test_script.sh; diff --git a/ci/linux/install_bin2cpp.sh b/ci/linux/install_bin2cpp.sh index 2ad72af..1f32401 100755 --- a/ci/linux/install_bin2cpp.sh +++ b/ci/linux/install_bin2cpp.sh @@ -2,35 +2,35 @@ set -e # Validate mandatory environment variables -if [ "$BIN2CPP_BUILD_TYPE" = "" ]; then - echo "Please define 'BIN2CPP_BUILD_TYPE' environment variable."; +if [ "$PRODUCT_BUILD_TYPE" = "" ]; then + echo "Please define 'PRODUCT_BUILD_TYPE' environment variable."; exit 1; fi -# Set BIN2CPP_SOURCE_DIR root directory -if [ "$BIN2CPP_SOURCE_DIR" = "" ]; then +# Set PRODUCT_SOURCE_DIR root directory +if [ "$PRODUCT_SOURCE_DIR" = "" ]; then RESTORE_DIRECTORY="$PWD" cd "$(dirname "$0")" cd ../.. - export BIN2CPP_SOURCE_DIR="$PWD" - echo "BIN2CPP_SOURCE_DIR set to '$BIN2CPP_SOURCE_DIR'." + export PRODUCT_SOURCE_DIR="$PWD" + echo "PRODUCT_SOURCE_DIR set to '$PRODUCT_SOURCE_DIR'." cd "$RESTORE_DIRECTORY" unset RESTORE_DIRECTORY fi # Prepare CMAKE parameters -export CMAKE_INSTALL_PREFIX="$BIN2CPP_SOURCE_DIR/install" +export CMAKE_INSTALL_PREFIX="$PRODUCT_SOURCE_DIR/install" unset CMAKE_PREFIX_PATH -export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH;$BIN2CPP_SOURCE_DIR/third_parties/googletest/install" -export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH;$BIN2CPP_SOURCE_DIR/third_parties/RapidAssist/install" +export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH;$PRODUCT_SOURCE_DIR/third_parties/googletest/install" +export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH;$PRODUCT_SOURCE_DIR/third_parties/RapidAssist/install" echo ============================================================================ echo Generating bin2cpp... echo ============================================================================ -cd "$BIN2CPP_SOURCE_DIR" +cd "$PRODUCT_SOURCE_DIR" mkdir -p build cd build -cmake -DCMAKE_BUILD_TYPE=$BIN2CPP_BUILD_TYPE -DBIN2CPP_BUILD_TEST=ON -DBIN2CPP_BUILD_SAMPLES=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_PREFIX" -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" .. +cmake -Wno-dev -DCMAKE_BUILD_TYPE=$PRODUCT_BUILD_TYPE -DBIN2CPP_BUILD_TEST=ON -DBIN2CPP_BUILD_SAMPLES=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_PREFIX" -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" .. echo ============================================================================ echo Compiling bin2cpp... @@ -39,7 +39,7 @@ cmake --build . -- -j4 echo echo ============================================================================ -echo Installing bin2cpp into $BIN2CPP_SOURCE_DIR/install +echo Installing bin2cpp into $PRODUCT_SOURCE_DIR/install echo ============================================================================ make install echo diff --git a/ci/linux/install_googletest.sh b/ci/linux/install_googletest.sh index b41cbfe..146ec31 100755 --- a/ci/linux/install_googletest.sh +++ b/ci/linux/install_googletest.sh @@ -2,32 +2,32 @@ set -e # Validate mandatory environment variables -if [ "$BIN2CPP_BUILD_TYPE" = "" ]; then - echo "Please define 'BIN2CPP_BUILD_TYPE' environment variable."; +if [ "$PRODUCT_BUILD_TYPE" = "" ]; then + echo "Please define 'PRODUCT_BUILD_TYPE' environment variable."; exit 1; fi -# Set BIN2CPP_SOURCE_DIR root directory -if [ "$BIN2CPP_SOURCE_DIR" = "" ]; then +# Set PRODUCT_SOURCE_DIR root directory +if [ "$PRODUCT_SOURCE_DIR" = "" ]; then RESTORE_DIRECTORY="$PWD" cd "$(dirname "$0")" cd ../.. - export BIN2CPP_SOURCE_DIR="$PWD" - echo "BIN2CPP_SOURCE_DIR set to '$BIN2CPP_SOURCE_DIR'." + export PRODUCT_SOURCE_DIR="$PWD" + echo "PRODUCT_SOURCE_DIR set to '$PRODUCT_SOURCE_DIR'." cd "$RESTORE_DIRECTORY" unset RESTORE_DIRECTORY fi # Prepare CMAKE parameters -export CMAKE_INSTALL_PREFIX="$BIN2CPP_SOURCE_DIR/third_parties/googletest/install" +export CMAKE_INSTALL_PREFIX="$PRODUCT_SOURCE_DIR/third_parties/googletest/install" unset CMAKE_PREFIX_PATH export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH;" echo ============================================================================ -echo Cloning googletest into $BIN2CPP_SOURCE_DIR/third_parties/googletest +echo Cloning googletest into $PRODUCT_SOURCE_DIR/third_parties/googletest echo ============================================================================ -mkdir -p "$BIN2CPP_SOURCE_DIR/third_parties" -cd "$BIN2CPP_SOURCE_DIR/third_parties" +mkdir -p "$PRODUCT_SOURCE_DIR/third_parties" +cd "$PRODUCT_SOURCE_DIR/third_parties" git clone "https://github.com/google/googletest.git" cd googletest echo @@ -37,16 +37,20 @@ git -c advice.detachedHead=false checkout release-1.8.0 echo echo ============================================================================ -echo Compiling googletest... +echo Generating googletest... echo ============================================================================ mkdir -p build cd build -cmake -DCMAKE_BUILD_TYPE=$BIN2CPP_BUILD_TYPE -DBUILD_SHARED_LIBS=OFF -DBUILD_GMOCK=OFF -DBUILD_GTEST=ON -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_PREFIX" -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" .. +cmake -Wno-dev -DCMAKE_BUILD_TYPE=$PRODUCT_BUILD_TYPE -DBUILD_SHARED_LIBS=OFF -DBUILD_GMOCK=OFF -DBUILD_GTEST=ON -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_PREFIX" -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" .. + +echo ============================================================================ +echo Compiling googletest... +echo ============================================================================ cmake --build . -- -j4 echo echo ============================================================================ -echo Installing googletest into $BIN2CPP_SOURCE_DIR/third_parties/googletest/install +echo Installing googletest into $PRODUCT_SOURCE_DIR/third_parties/googletest/install echo ============================================================================ make install echo diff --git a/ci/linux/install_rapidassist.sh b/ci/linux/install_rapidassist.sh index ba3e0e0..34fd393 100755 --- a/ci/linux/install_rapidassist.sh +++ b/ci/linux/install_rapidassist.sh @@ -2,51 +2,55 @@ set -e # Validate mandatory environment variables -if [ "$BIN2CPP_BUILD_TYPE" = "" ]; then - echo "Please define 'BIN2CPP_BUILD_TYPE' environment variable."; +if [ "$PRODUCT_BUILD_TYPE" = "" ]; then + echo "Please define 'PRODUCT_BUILD_TYPE' environment variable."; exit 1; fi -# Set BIN2CPP_SOURCE_DIR root directory -if [ "$BIN2CPP_SOURCE_DIR" = "" ]; then +# Set PRODUCT_SOURCE_DIR root directory +if [ "$PRODUCT_SOURCE_DIR" = "" ]; then RESTORE_DIRECTORY="$PWD" cd "$(dirname "$0")" cd ../.. - export BIN2CPP_SOURCE_DIR="$PWD" - echo "BIN2CPP_SOURCE_DIR set to '$BIN2CPP_SOURCE_DIR'." + export PRODUCT_SOURCE_DIR="$PWD" + echo "PRODUCT_SOURCE_DIR set to '$PRODUCT_SOURCE_DIR'." cd "$RESTORE_DIRECTORY" unset RESTORE_DIRECTORY fi # Prepare CMAKE parameters -export CMAKE_INSTALL_PREFIX="$BIN2CPP_SOURCE_DIR/third_parties/RapidAssist/install" +export CMAKE_INSTALL_PREFIX="$PRODUCT_SOURCE_DIR/third_parties/RapidAssist/install" unset CMAKE_PREFIX_PATH -export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH;$BIN2CPP_SOURCE_DIR/third_parties/googletest/install" +export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH;$PRODUCT_SOURCE_DIR/third_parties/googletest/install" echo ============================================================================ -echo Cloning RapidAssist into $BIN2CPP_SOURCE_DIR/third_parties/RapidAssist +echo Cloning RapidAssist into $PRODUCT_SOURCE_DIR/third_parties/RapidAssist echo ============================================================================ -mkdir -p "$BIN2CPP_SOURCE_DIR/third_parties" -cd "$BIN2CPP_SOURCE_DIR/third_parties" +mkdir -p "$PRODUCT_SOURCE_DIR/third_parties" +cd "$PRODUCT_SOURCE_DIR/third_parties" git clone "https://github.com/end2endzone/RapidAssist.git" cd RapidAssist echo -echo Checking out version v0.10.0... -git -c advice.detachedHead=false checkout 0.10.0 +echo Checking out version v0.11.0... +git -c advice.detachedHead=false checkout 0.11.0 echo echo ============================================================================ -echo Compiling RapidAssist... +echo Generating RapidAssist... echo ============================================================================ mkdir -p build cd build -cmake -DCMAKE_BUILD_TYPE=$BIN2CPP_BUILD_TYPE -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_PREFIX" -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" .. +cmake -Wno-dev -DCMAKE_BUILD_TYPE=$PRODUCT_BUILD_TYPE -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_PREFIX" -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" .. + +echo ============================================================================ +echo Compiling RapidAssist... +echo ============================================================================ cmake --build . -- -j4 echo echo ============================================================================ -echo Installing RapidAssist into $BIN2CPP_SOURCE_DIR/third_parties/RapidAssist/install +echo Installing RapidAssist into $PRODUCT_SOURCE_DIR/third_parties/RapidAssist/install echo ============================================================================ make install echo diff --git a/ci/linux/test_script.sh b/ci/linux/test_script.sh index e13227f..2d6f30e 100755 --- a/ci/linux/test_script.sh +++ b/ci/linux/test_script.sh @@ -2,18 +2,18 @@ set -e # Validate mandatory environment variables -if [ "$BIN2CPP_BUILD_TYPE" = "" ]; then - echo "Please define 'BIN2CPP_BUILD_TYPE' environment variable."; +if [ "$PRODUCT_BUILD_TYPE" = "" ]; then + echo "Please define 'PRODUCT_BUILD_TYPE' environment variable."; exit 1; fi -# Set BIN2CPP_SOURCE_DIR root directory -if [ "$BIN2CPP_SOURCE_DIR" = "" ]; then +# Set PRODUCT_SOURCE_DIR root directory +if [ "$PRODUCT_SOURCE_DIR" = "" ]; then RESTORE_DIRECTORY="$PWD" cd "$(dirname "$0")" cd ../.. - export BIN2CPP_SOURCE_DIR="$PWD" - echo "BIN2CPP_SOURCE_DIR set to '$BIN2CPP_SOURCE_DIR'." + export PRODUCT_SOURCE_DIR="$PWD" + echo "PRODUCT_SOURCE_DIR set to '$PRODUCT_SOURCE_DIR'." cd "$RESTORE_DIRECTORY" unset RESTORE_DIRECTORY fi @@ -21,9 +21,9 @@ fi echo ============================================================================ echo Testing bin2cpp... echo ============================================================================ -cd "$BIN2CPP_SOURCE_DIR/build/bin" +cd "$PRODUCT_SOURCE_DIR/build/bin" ./generate_test_files.sh -if [ "$BIN2CPP_BUILD_TYPE" = "Debug" ]; then +if [ "$PRODUCT_BUILD_TYPE" = "Debug" ]; then ./bin2cpp_unittest-d || true; #do not fail build even if a test fails. else ./bin2cpp_unittest || true; #do not fail build even if a test fails. diff --git a/ci/travis/emulate_travis.sh b/ci/travis/emulate_travis.sh index b3b02ca..fa24025 100755 --- a/ci/travis/emulate_travis.sh +++ b/ci/travis/emulate_travis.sh @@ -2,6 +2,6 @@ restore_dir=$PWD cd ../.. export TRAVIS=true export TRAVIS_BUILD_DIR=$PWD -export BIN2CPP_BUILD_TYPE=Release +export PRODUCT_BUILD_TYPE=Release echo "TRAVIS_BUILD_DIR set to $TRAVIS_BUILD_DIR" cd $restore_dir diff --git a/ci/windows/build_all_debug.bat b/ci/windows/build_all_debug.bat index f4596d7..11e48db 100644 --- a/ci/windows/build_all_debug.bat +++ b/ci/windows/build_all_debug.bat @@ -1,35 +1,36 @@ @echo off -:: Set BIN2CPP_SOURCE_DIR root directory +:: Set build configuration parameters +set CONFIGURATION=Debug +set PLATFORM=x64 +set PLATFORMTOOLSET="" +echo Building bin2cpp for Windows in %CONFIGURATION%, %PLATFORM% configuration... +echo. + +:: Set PRODUCT_SOURCE_DIR root directory setlocal enabledelayedexpansion -if "%BIN2CPP_SOURCE_DIR%"=="" ( +if "%PRODUCT_SOURCE_DIR%"=="" ( :: Delayed expansion is required within parentheses https://superuser.com/questions/78496/variables-in-batch-file-not-being-set-when-inside-if cd /d "%~dp0" cd ..\.. - set BIN2CPP_SOURCE_DIR=!CD! + set PRODUCT_SOURCE_DIR=!CD! cd ..\.. - echo BIN2CPP_SOURCE_DIR set to '!BIN2CPP_SOURCE_DIR!'. + echo PRODUCT_SOURCE_DIR set to '!PRODUCT_SOURCE_DIR!'. ) -endlocal & set BIN2CPP_SOURCE_DIR=%BIN2CPP_SOURCE_DIR% - -:: Set build configuration parameters -set CONFIGURATION=Debug -set PLATFORM=x64 -set PLATFORMTOOLSET="" -echo Building RapidAssist for Windows in %CONFIGURATION%, %Platform% configuration... +endlocal & set PRODUCT_SOURCE_DIR=%PRODUCT_SOURCE_DIR% echo. :: Return back to scripts folder cd /d "%~dp0" :: Call windows scripts one by one. -call "%BIN2CPP_SOURCE_DIR%\ci\windows\install_googletest.bat" +call "%PRODUCT_SOURCE_DIR%\ci\windows\install_googletest.bat" if %errorlevel% neq 0 pause && exit /b %errorlevel% -call "%BIN2CPP_SOURCE_DIR%\ci\windows\install_rapidassist.bat" +call "%PRODUCT_SOURCE_DIR%\ci\windows\install_rapidassist.bat" if %errorlevel% neq 0 pause && exit /b %errorlevel% -call "%BIN2CPP_SOURCE_DIR%\ci\windows\install_bin2cpp.bat" +call "%PRODUCT_SOURCE_DIR%\ci\windows\install_bin2cpp.bat" if %errorlevel% neq 0 pause && exit /b %errorlevel% -call "%BIN2CPP_SOURCE_DIR%\ci\windows\test_script.bat" +call "%PRODUCT_SOURCE_DIR%\ci\windows\test_script.bat" if %errorlevel% neq 0 pause && exit /b %errorlevel% :: Press a key to continue diff --git a/ci/windows/build_all_release.bat b/ci/windows/build_all_release.bat index 3d91241..84a16df 100644 --- a/ci/windows/build_all_release.bat +++ b/ci/windows/build_all_release.bat @@ -1,35 +1,36 @@ @echo off -:: Set BIN2CPP_SOURCE_DIR root directory +:: Set build configuration parameters +set CONFIGURATION=Release +set PLATFORM=x64 +set PLATFORMTOOLSET="" +echo Building bin2cpp for Windows in %CONFIGURATION%, %PLATFORM% configuration... +echo. + +:: Set PRODUCT_SOURCE_DIR root directory setlocal enabledelayedexpansion -if "%BIN2CPP_SOURCE_DIR%"=="" ( +if "%PRODUCT_SOURCE_DIR%"=="" ( :: Delayed expansion is required within parentheses https://superuser.com/questions/78496/variables-in-batch-file-not-being-set-when-inside-if cd /d "%~dp0" cd ..\.. - set BIN2CPP_SOURCE_DIR=!CD! + set PRODUCT_SOURCE_DIR=!CD! cd ..\.. - echo BIN2CPP_SOURCE_DIR set to '!BIN2CPP_SOURCE_DIR!'. + echo PRODUCT_SOURCE_DIR set to '!PRODUCT_SOURCE_DIR!'. ) -endlocal & set BIN2CPP_SOURCE_DIR=%BIN2CPP_SOURCE_DIR% - -:: Set build configuration parameters -set CONFIGURATION=Release -set PLATFORM=x64 -set PLATFORMTOOLSET="" -echo Building RapidAssist for Windows in %CONFIGURATION%, %Platform% configuration... +endlocal & set PRODUCT_SOURCE_DIR=%PRODUCT_SOURCE_DIR% echo. :: Return back to scripts folder cd /d "%~dp0" :: Call windows scripts one by one. -call "%BIN2CPP_SOURCE_DIR%\ci\windows\install_googletest.bat" +call "%PRODUCT_SOURCE_DIR%\ci\windows\install_googletest.bat" if %errorlevel% neq 0 pause && exit /b %errorlevel% -call "%BIN2CPP_SOURCE_DIR%\ci\windows\install_rapidassist.bat" +call "%PRODUCT_SOURCE_DIR%\ci\windows\install_rapidassist.bat" if %errorlevel% neq 0 pause && exit /b %errorlevel% -call "%BIN2CPP_SOURCE_DIR%\ci\windows\install_bin2cpp.bat" +call "%PRODUCT_SOURCE_DIR%\ci\windows\install_bin2cpp.bat" if %errorlevel% neq 0 pause && exit /b %errorlevel% -call "%BIN2CPP_SOURCE_DIR%\ci\windows\test_script.bat" +call "%PRODUCT_SOURCE_DIR%\ci\windows\test_script.bat" if %errorlevel% neq 0 pause && exit /b %errorlevel% :: Press a key to continue diff --git a/ci/windows/install_bin2cpp.bat b/ci/windows/install_bin2cpp.bat index 496008b..c32083e 100755 --- a/ci/windows/install_bin2cpp.bat +++ b/ci/windows/install_bin2cpp.bat @@ -5,37 +5,39 @@ if "%CONFIGURATION%"=="" ( echo Please define 'Configuration' environment variable. exit /B 1 ) -if "%Platform%"=="" ( +if "%PLATFORM%"=="" ( echo Please define 'Platform' environment variable. exit /B 1 ) -:: Set BIN2CPP_SOURCE_DIR root directory +:: Set PRODUCT_SOURCE_DIR root directory setlocal enabledelayedexpansion -if "%BIN2CPP_SOURCE_DIR%"=="" ( +if "%PRODUCT_SOURCE_DIR%"=="" ( :: Delayed expansion is required within parentheses https://superuser.com/questions/78496/variables-in-batch-file-not-being-set-when-inside-if cd /d "%~dp0" cd ..\.. - set BIN2CPP_SOURCE_DIR=!CD! + set PRODUCT_SOURCE_DIR=!CD! cd ..\.. - echo BIN2CPP_SOURCE_DIR set to '!BIN2CPP_SOURCE_DIR!'. + echo PRODUCT_SOURCE_DIR set to '!PRODUCT_SOURCE_DIR!'. ) -endlocal & set BIN2CPP_SOURCE_DIR=%BIN2CPP_SOURCE_DIR% +endlocal & set PRODUCT_SOURCE_DIR=%PRODUCT_SOURCE_DIR% +echo. :: Prepare CMAKE parameters -set CMAKE_INSTALL_PREFIX=%BIN2CPP_SOURCE_DIR%\install +set CMAKE_INSTALL_PREFIX=%PRODUCT_SOURCE_DIR%\install set CMAKE_PREFIX_PATH= -set CMAKE_PREFIX_PATH=%CMAKE_PREFIX_PATH%;%BIN2CPP_SOURCE_DIR%\third_parties\googletest\install -set CMAKE_PREFIX_PATH=%CMAKE_PREFIX_PATH%;%BIN2CPP_SOURCE_DIR%\third_parties\RapidAssist\install +set CMAKE_PREFIX_PATH=%CMAKE_PREFIX_PATH%;%PRODUCT_SOURCE_DIR%\third_parties\googletest\install +set CMAKE_PREFIX_PATH=%CMAKE_PREFIX_PATH%;%PRODUCT_SOURCE_DIR%\third_parties\RapidAssist\install echo ============================================================================ echo Generating bin2cpp... echo ============================================================================ -cd /d "%BIN2CPP_SOURCE_DIR%" +cd /d "%PRODUCT_SOURCE_DIR%" mkdir build >NUL 2>NUL cd build -cmake -DCMAKE_GENERATOR_PLATFORM=%Platform% -T %PlatformToolset% -DBIN2CPP_BUILD_TEST=ON -DBIN2CPP_BUILD_SAMPLES=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="%CMAKE_INSTALL_PREFIX%" -DCMAKE_PREFIX_PATH="%CMAKE_PREFIX_PATH%" .. +cmake -Wno-dev -DCMAKE_GENERATOR_PLATFORM=%PLATFORM% -T %PLATFORMTOOLSET% -DBIN2CPP_BUILD_TEST=ON -DBIN2CPP_BUILD_SAMPLES=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="%CMAKE_INSTALL_PREFIX%" -DCMAKE_PREFIX_PATH="%CMAKE_PREFIX_PATH%" .. if %errorlevel% neq 0 exit /b %errorlevel% +echo. echo ============================================================================ echo Compiling bin2cpp library... @@ -45,7 +47,7 @@ if %errorlevel% neq 0 exit /b %errorlevel% echo. echo ============================================================================ -echo Installing bin2cpp library into %BIN2CPP_SOURCE_DIR%\install +echo Installing bin2cpp library into %PRODUCT_SOURCE_DIR%\install echo ============================================================================ cmake --build . --config %CONFIGURATION% --target INSTALL if %errorlevel% neq 0 exit /b %errorlevel% @@ -54,7 +56,7 @@ echo. echo ============================================================================ echo Creating bin2cpp install package echo ============================================================================ -cmake --build . --config %Configuration% --target PACKAGE +cmake --build . --config %CONFIGURATION% --target PACKAGE if %errorlevel% neq 0 exit /b %errorlevel% echo. diff --git a/ci/windows/install_googletest.bat b/ci/windows/install_googletest.bat index 707da64..132b3e1 100644 --- a/ci/windows/install_googletest.bat +++ b/ci/windows/install_googletest.bat @@ -5,33 +5,34 @@ if "%CONFIGURATION%"=="" ( echo Please define 'Configuration' environment variable. exit /B 1 ) -if "%Platform%"=="" ( +if "%PLATFORM%"=="" ( echo Please define 'Platform' environment variable. exit /B 1 ) -:: Set BIN2CPP_SOURCE_DIR root directory +:: Set PRODUCT_SOURCE_DIR root directory setlocal enabledelayedexpansion -if "%BIN2CPP_SOURCE_DIR%"=="" ( +if "%PRODUCT_SOURCE_DIR%"=="" ( :: Delayed expansion is required within parentheses https://superuser.com/questions/78496/variables-in-batch-file-not-being-set-when-inside-if cd /d "%~dp0" cd ..\.. - set BIN2CPP_SOURCE_DIR=!CD! + set PRODUCT_SOURCE_DIR=!CD! cd ..\.. - echo BIN2CPP_SOURCE_DIR set to '!BIN2CPP_SOURCE_DIR!'. + echo PRODUCT_SOURCE_DIR set to '!PRODUCT_SOURCE_DIR!'. ) -endlocal & set BIN2CPP_SOURCE_DIR=%BIN2CPP_SOURCE_DIR% +endlocal & set PRODUCT_SOURCE_DIR=%PRODUCT_SOURCE_DIR% +echo. :: Prepare CMAKE parameters -set CMAKE_INSTALL_PREFIX=%BIN2CPP_SOURCE_DIR%\third_parties\googletest\install +set CMAKE_INSTALL_PREFIX=%PRODUCT_SOURCE_DIR%\third_parties\googletest\install set CMAKE_PREFIX_PATH= set CMAKE_PREFIX_PATH=%CMAKE_PREFIX_PATH%; echo ============================================================================ -echo Cloning googletest into %BIN2CPP_SOURCE_DIR%\third_parties\googletest +echo Cloning googletest into %PRODUCT_SOURCE_DIR%\third_parties\googletest echo ============================================================================ -mkdir "%BIN2CPP_SOURCE_DIR%\third_parties" >NUL 2>NUL -cd "%BIN2CPP_SOURCE_DIR%\third_parties" +mkdir "%PRODUCT_SOURCE_DIR%\third_parties" >NUL 2>NUL +cd "%PRODUCT_SOURCE_DIR%\third_parties" git clone "https://github.com/google/googletest.git" cd googletest echo. @@ -41,18 +42,36 @@ git -c advice.detachedHead=false checkout release-1.8.0 echo. echo ============================================================================ -echo Compiling googletest... +echo Generating googletest... echo ============================================================================ mkdir build >NUL 2>NUL cd build -cmake -DCMAKE_GENERATOR_PLATFORM=%Platform% -T %PlatformToolset% -Dgtest_force_shared_crt=ON -DBUILD_GMOCK=OFF -DBUILD_GTEST=ON -DCMAKE_INSTALL_PREFIX="%CMAKE_INSTALL_PREFIX%" -DCMAKE_PREFIX_PATH="%CMAKE_PREFIX_PATH%" -DCMAKE_CXX_FLAGS=/D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING .. +cmake -Wno-dev -DCMAKE_GENERATOR_PLATFORM=%PLATFORM% -T %PLATFORMTOOLSET% -Dgtest_force_shared_crt=ON -DBUILD_GMOCK=OFF -DBUILD_GTEST=ON -DCMAKE_INSTALL_PREFIX="%CMAKE_INSTALL_PREFIX%" -DCMAKE_PREFIX_PATH="%CMAKE_PREFIX_PATH%" .. if %errorlevel% neq 0 exit /b %errorlevel% +echo. + +echo. +echo. +echo ================================================================================== +echo Patching googletest to silence MSVC warning C4996 about deprecated 'std::tr1' namespace +echo ================================================================================== +echo add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)>>..\googletest\CMakeLists.txt +echo add_definitions(-D_CRT_SECURE_NO_WARNINGS)>>..\googletest\CMakeLists.txt +cmake .. 1>NUL 2>NUL +echo Done patching. +echo. +echo. + +:: Continue with compilation +echo ============================================================================ +echo Compiling googletest... +echo ============================================================================ cmake --build . --config %CONFIGURATION% -- -maxcpucount /m if %errorlevel% neq 0 exit /b %errorlevel% echo. echo ============================================================================ -echo Installing googletest into %BIN2CPP_SOURCE_DIR%\third_parties\googletest\install +echo Installing googletest into %PRODUCT_SOURCE_DIR%\third_parties\googletest\install echo ============================================================================ cmake --build . --config %CONFIGURATION% --target INSTALL if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/ci/windows/install_rapidassist.bat b/ci/windows/install_rapidassist.bat index ba07f7b..8055760 100644 --- a/ci/windows/install_rapidassist.bat +++ b/ci/windows/install_rapidassist.bat @@ -5,54 +5,60 @@ if "%CONFIGURATION%"=="" ( echo Please define 'Configuration' environment variable. exit /B 1 ) -if "%Platform%"=="" ( +if "%PLATFORM%"=="" ( echo Please define 'Platform' environment variable. exit /B 1 ) -:: Set BIN2CPP_SOURCE_DIR root directory +:: Set PRODUCT_SOURCE_DIR root directory setlocal enabledelayedexpansion -if "%BIN2CPP_SOURCE_DIR%"=="" ( +if "%PRODUCT_SOURCE_DIR%"=="" ( :: Delayed expansion is required within parentheses https://superuser.com/questions/78496/variables-in-batch-file-not-being-set-when-inside-if cd /d "%~dp0" cd ..\.. - set BIN2CPP_SOURCE_DIR=!CD! + set PRODUCT_SOURCE_DIR=!CD! cd ..\.. - echo BIN2CPP_SOURCE_DIR set to '!BIN2CPP_SOURCE_DIR!'. + echo PRODUCT_SOURCE_DIR set to '!PRODUCT_SOURCE_DIR!'. ) -endlocal & set BIN2CPP_SOURCE_DIR=%BIN2CPP_SOURCE_DIR% +endlocal & set PRODUCT_SOURCE_DIR=%PRODUCT_SOURCE_DIR% +echo. :: Prepare CMAKE parameters -set CMAKE_INSTALL_PREFIX=%BIN2CPP_SOURCE_DIR%\third_parties\RapidAssist\install +set CMAKE_INSTALL_PREFIX=%PRODUCT_SOURCE_DIR%\third_parties\RapidAssist\install set CMAKE_PREFIX_PATH= -set CMAKE_PREFIX_PATH=%CMAKE_PREFIX_PATH%%BIN2CPP_SOURCE_DIR%\third_parties\googletest\install; +set CMAKE_PREFIX_PATH=%CMAKE_PREFIX_PATH%;%PRODUCT_SOURCE_DIR%\third_parties\googletest\install; echo ============================================================================ -echo Cloning RapidAssist into %BIN2CPP_SOURCE_DIR%\third_parties\RapidAssist +echo Cloning RapidAssist into %PRODUCT_SOURCE_DIR%\third_parties\RapidAssist echo ============================================================================ -mkdir "%BIN2CPP_SOURCE_DIR%\third_parties" >NUL 2>NUL -cd "%BIN2CPP_SOURCE_DIR%\third_parties" +mkdir "%PRODUCT_SOURCE_DIR%\third_parties" >NUL 2>NUL +cd "%PRODUCT_SOURCE_DIR%\third_parties" git clone "https://github.com/end2endzone/RapidAssist.git" cd RapidAssist echo. -echo Checking out version v0.10.0... -git -c advice.detachedHead=false checkout 0.10.0 +echo Checking out version v0.11.0... +git -c advice.detachedHead=false checkout 0.11.0 echo. echo ============================================================================ -echo Compiling RapidAssist... +echo Generating RapidAssist... echo ============================================================================ mkdir build >NUL 2>NUL cd build -cmake -DCMAKE_GENERATOR_PLATFORM=%Platform% -T %PlatformToolset% -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="%CMAKE_INSTALL_PREFIX%" -DCMAKE_PREFIX_PATH="%CMAKE_PREFIX_PATH%" .. +cmake -Wno-dev -DCMAKE_GENERATOR_PLATFORM=%PLATFORM% -T %PLATFORMTOOLSET% -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="%CMAKE_INSTALL_PREFIX%" -DCMAKE_PREFIX_PATH="%CMAKE_PREFIX_PATH%" .. if %errorlevel% neq 0 exit /b %errorlevel% +echo. + +echo ============================================================================ +echo Compiling RapidAssist... +echo ============================================================================ cmake --build . --config %CONFIGURATION% -- -maxcpucount /m if %errorlevel% neq 0 exit /b %errorlevel% echo. echo ============================================================================ -echo Installing RapidAssist into %BIN2CPP_SOURCE_DIR%\third_parties\RapidAssist\install +echo Installing RapidAssist into %PRODUCT_SOURCE_DIR%\third_parties\RapidAssist\install echo ============================================================================ cmake --build . --config %CONFIGURATION% --target INSTALL if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/ci/windows/test_script.bat b/ci/windows/test_script.bat index f701563..f193172 100644 --- a/ci/windows/test_script.bat +++ b/ci/windows/test_script.bat @@ -10,22 +10,23 @@ if "%PLATFORM%"=="" ( exit /B 1 ) -:: Set BIN2CPP_SOURCE_DIR root directory +:: Set PRODUCT_SOURCE_DIR root directory setlocal enabledelayedexpansion -if "%BIN2CPP_SOURCE_DIR%"=="" ( +if "%PRODUCT_SOURCE_DIR%"=="" ( :: Delayed expansion is required within parentheses https://superuser.com/questions/78496/variables-in-batch-file-not-being-set-when-inside-if cd /d "%~dp0" cd ..\.. - set BIN2CPP_SOURCE_DIR=!CD! + set PRODUCT_SOURCE_DIR=!CD! cd ..\.. - echo BIN2CPP_SOURCE_DIR set to '!BIN2CPP_SOURCE_DIR!'. + echo PRODUCT_SOURCE_DIR set to '!PRODUCT_SOURCE_DIR!'. ) -endlocal & set BIN2CPP_SOURCE_DIR=%BIN2CPP_SOURCE_DIR% +endlocal & set PRODUCT_SOURCE_DIR=%PRODUCT_SOURCE_DIR% +echo. echo ======================================================================= echo Testing bin2cpp... echo ======================================================================= -cd /d "%BIN2CPP_SOURCE_DIR%\build\bin\%CONFIGURATION%" +cd /d "%PRODUCT_SOURCE_DIR%\build\bin\%CONFIGURATION%" call generate_test_files.bat if "%CONFIGURATION%"=="Debug" ( bin2cpp_unittest-d.exe diff --git a/samples/demo_helloworld/CMakeLists.txt b/samples/demo_helloworld/CMakeLists.txt index 89a5f82..1c6ab50 100644 --- a/samples/demo_helloworld/CMakeLists.txt +++ b/samples/demo_helloworld/CMakeLists.txt @@ -1,6 +1,6 @@ set(GENERATED_TEST_FILES - ${CMAKE_CURRENT_BINARY_DIR}/generated_helloworld.h - ${CMAKE_CURRENT_BINARY_DIR}/generated_helloworld.cpp + ${CMAKE_CURRENT_BINARY_DIR}/helloworld.h + ${CMAKE_CURRENT_BINARY_DIR}/helloworld.cpp ) add_custom_command( OUTPUT ${GENERATED_TEST_FILES} @@ -8,9 +8,6 @@ add_custom_command( OUTPUT ${GENERATED_TEST_FILES} COMMAND $ --file=${CMAKE_CURRENT_SOURCE_DIR}/helloworld.html --output=${CMAKE_CURRENT_BINARY_DIR} - --headerfile=generated_helloworld.h - --identifier=HelloWorldHtml - --chunksize=50 ) # Show all generated files in a common folder @@ -19,7 +16,7 @@ source_group("Generated Files" FILES ${GENERATED_TEST_FILES}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_executable(demo_helloworld - helloworld.cpp + demo_helloworld.cpp ${GENERATED_TEST_FILES} ) diff --git a/samples/demo_helloworld/helloworld.cpp b/samples/demo_helloworld/demo_helloworld.cpp similarity index 53% rename from samples/demo_helloworld/helloworld.cpp rename to samples/demo_helloworld/demo_helloworld.cpp index 1dd9f34..b72c41a 100644 --- a/samples/demo_helloworld/helloworld.cpp +++ b/samples/demo_helloworld/demo_helloworld.cpp @@ -1,22 +1,24 @@ #include #include -#include "generated_helloworld.h" //a single include file is all you need +#include + +#include "helloworld.h" //a single include file is all you need int main(int argc, char* argv[]) { //get a reference to the embedded file - const bin2cpp::File & resource = bin2cpp::getHelloWorldHtmlFile(); + const bin2cpp::File & resource = bin2cpp::getHelloworldHtmlFile(); //print information about the file. - printf("Embedded file '%s' is %lu bytes long.\n", resource.getFilename(), resource.getSize()); + std::cout << "Embedded file '" << resource.getFileName() << "' is " << resource.getSize() << " bytes long.\n"; //Saving content back to a file. - printf("Saving embedded file to 'helloworld_copy.html'...\n"); + std::cout << " Saving embedded file to 'helloworld_copy.html'...\n"; bool saved = resource.save("helloworld_copy.html"); if (saved) - printf("saved\n"); + std::cout << "saved\n"; else - printf("failed\n"); + std::cout << "failed\n"; //Get the internal buffer and do something with the binary data const char * buffer = resource.getBuffer(); diff --git a/samples/demo_helloworld/helloworld.bat b/samples/demo_helloworld/helloworld.bat index d3bb71a..6b30304 100644 --- a/samples/demo_helloworld/helloworld.bat +++ b/samples/demo_helloworld/helloworld.bat @@ -3,8 +3,8 @@ rmdir /S /Q outdir 1>NUL 2>NUL mkdir outdir 1>NUL 2>NUL -set path=%cd%\..\..\build\bin\Release;%PATH% +set path=%cd%\..\..\build\bin\Release;%cd%\..\..\build\bin\Debug;%PATH% -bin2cpp.exe --file=helloworld.html --output=.\outdir --headerfile=generated_helloworld.h --identifier=HelloWorldHtml --chunksize=50 +bin2cpp.exe --file=helloworld.html --output=.\outdir pause diff --git a/samples/demo_icons/demo_icons.bat b/samples/demo_icons/demo_icons.bat index eaa8749..b7b9d06 100644 --- a/samples/demo_icons/demo_icons.bat +++ b/samples/demo_icons/demo_icons.bat @@ -3,7 +3,7 @@ rmdir /S /Q outdir 1>NUL 2>NUL mkdir outdir 1>NUL 2>NUL -set path=%cd%\..\..\build\bin\Release;%PATH% +set path=%cd%\..\..\build\bin\Release;%cd%\..\..\build\bin\Debug;%PATH% bin2cpp.exe --dir=flat-color-icons --managerfile=IconsFileManager.h --output=.\outdir --chunksize=50 diff --git a/samples/demo_icons/demo_icons.cpp b/samples/demo_icons/demo_icons.cpp index c361920..3a9b823 100644 --- a/samples/demo_icons/demo_icons.cpp +++ b/samples/demo_icons/demo_icons.cpp @@ -1,5 +1,6 @@ #include // printf #include // getenv +#include #include "IconsFileManager.h" @@ -9,23 +10,23 @@ int main(int argc, char* argv[]) //Print information about all files generated with "--managerfile" or --registerfile flags. size_t num_files = mgr.getFileCount(); - printf("Found %lu embedded icons...\n", num_files); + std::cout << "Found " << num_files << " embedded icons...\n"; //Listing files. for(size_t i=0; igetFilename(), file->getSize()); + std::cout << " File '" << file->getFileName() << "', " << file->getSize() << " bytes\n"; } //Saving content back to files. const char * temp_dir = getenv("TEMP"); - printf("Saving embedded icons to directory '%s'...\n", temp_dir); + std::cout << "Saving embedded icons to directory '" << temp_dir << "'...\n"; bool saved = mgr.saveFiles(temp_dir); if (saved) - printf("saved\n"); + std::cout << "saved\n"; else - printf("failed\n"); + std::cout << "failed\n"; return 0; } diff --git a/samples/demo_relative_dir/CMakeLists.txt b/samples/demo_relative_dir/CMakeLists.txt new file mode 100644 index 0000000..bdd47db --- /dev/null +++ b/samples/demo_relative_dir/CMakeLists.txt @@ -0,0 +1,55 @@ +set(GENERATED_TEST_FILES + ${CMAKE_CURRENT_BINARY_DIR}/include/bin2cpp/file_icon.h + ${CMAKE_CURRENT_BINARY_DIR}/include/bin2cpp/file_icon.cpp + ${CMAKE_CURRENT_BINARY_DIR}/include/bin2cpp/file_sinus.h + ${CMAKE_CURRENT_BINARY_DIR}/include/bin2cpp/file_sinus.cpp + ${CMAKE_CURRENT_BINARY_DIR}/include/bin2cpp/file_splashscreen.h + ${CMAKE_CURRENT_BINARY_DIR}/include/bin2cpp/file_splashscreen.cpp +) + + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/bin2cpp) + +add_custom_command( OUTPUT ${GENERATED_TEST_FILES} + # Execute bin2cpp generator + COMMAND $ + --file=${CMAKE_CURRENT_SOURCE_DIR}/res/icon.ico + --output=${CMAKE_CURRENT_BINARY_DIR}/include + --headerfile=bin2cpp/file_icon.h + --identifier=icon + --chunksize=50 + COMMAND $ + --file=${CMAKE_CURRENT_SOURCE_DIR}/res/sinus.dat + --output=${CMAKE_CURRENT_BINARY_DIR}/include + --headerfile=bin2cpp/file_sinus.h + --identifier=SinusTable + --chunksize=50 + COMMAND $ + --file=${CMAKE_CURRENT_SOURCE_DIR}/res/splashscreen.png + --output=${CMAKE_CURRENT_BINARY_DIR}/include + --headerfile=bin2cpp/file_splashscreen.h + --identifier=splashscreen + --chunksize=50 +) + +# Show all generated files in a common folder +source_group("Generated Files" FILES ${GENERATED_TEST_FILES}) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_BINARY_DIR}/include +) + +add_executable(demo_relative_dir + include/libtrigo/sincos.h + src/sincos.cpp + src/main.cpp + # src/generate_sinus_table.cpp + ${GENERATED_TEST_FILES} +) + +# Force CMAKE_DEBUG_POSTFIX for executables +set_target_properties(demo_relative_dir PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +# This is normally not required if bin2cpp is installed and in PATH. +add_dependencies(demo_relative_dir bin2cpp) diff --git a/samples/demo_relative_dir/demo_relative_dir.bat b/samples/demo_relative_dir/demo_relative_dir.bat new file mode 100644 index 0000000..e17de09 --- /dev/null +++ b/samples/demo_relative_dir/demo_relative_dir.bat @@ -0,0 +1,12 @@ +@echo off + +rmdir /S /Q include\bin2cpp 1>NUL 2>NUL +mkdir include\bin2cpp 1>NUL 2>NUL + +set path=%cd%\..\..\build\bin\Release;%cd%\..\..\build\bin\Debug;%PATH% + +bin2cpp.exe --file=res\icon.ico --output=include --headerfile=bin2cpp\file_icon.h --identifier=icon +bin2cpp.exe --file=res\sinus.dat --output=include --headerfile=bin2cpp\file_sinus.h --identifier=SinusTable +bin2cpp.exe --file=res\splashscreen.png --output=include --headerfile=bin2cpp\file_splashscreen.h --identifier=splashscreen + +pause diff --git a/samples/demo_relative_dir/include/libtrigo/sincos.h b/samples/demo_relative_dir/include/libtrigo/sincos.h new file mode 100644 index 0000000..3cf8320 --- /dev/null +++ b/samples/demo_relative_dir/include/libtrigo/sincos.h @@ -0,0 +1,36 @@ +/********************************************************************************** + * 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 LIBTRIGO_H +#define LIBTRIGO_H + +#define LIBTRIGO_PI (3.14159265359f) +#define LIBTRIGO_INVALID (99999999.9999f) +#define DEG2RAD(value) ((value*LIBTRIGO_PI)/180.0f) +#define RAD2DEG(value) ((value*180.0f)/LIBTRIGO_PI) + +float sindeg(float degrees); +float cosdeg(float degrees); + +#endif //LIBTRIGO_H diff --git a/samples/demo_relative_dir/res/icon.ico b/samples/demo_relative_dir/res/icon.ico new file mode 100644 index 0000000..1d8891e Binary files /dev/null and b/samples/demo_relative_dir/res/icon.ico differ diff --git a/samples/demo_relative_dir/res/sinus.dat b/samples/demo_relative_dir/res/sinus.dat new file mode 100644 index 0000000..09acdc4 Binary files /dev/null and b/samples/demo_relative_dir/res/sinus.dat differ diff --git a/samples/demo_relative_dir/res/splashscreen.png b/samples/demo_relative_dir/res/splashscreen.png new file mode 100644 index 0000000..8e93ee2 Binary files /dev/null and b/samples/demo_relative_dir/res/splashscreen.png differ diff --git a/samples/demo_relative_dir/src/generate_sinus_table.cpp b/samples/demo_relative_dir/src/generate_sinus_table.cpp new file mode 100644 index 0000000..490e2a5 --- /dev/null +++ b/samples/demo_relative_dir/src/generate_sinus_table.cpp @@ -0,0 +1,47 @@ +#include +#include +#include + +#include "libtrigo/sincos.h" + +enum APP_ERROR_CODES +{ + APP_ERROR_SUCCESS = 0, + APP_ERROR_OPERATION_FAILED, + APP_ERROR_UNKNOWN_SYMBOL, +}; + +int generate_sinus_table(const char * filename) +{ + FILE * f = fopen(filename, "wb"); + if (!f) + return APP_ERROR_OPERATION_FAILED; + + const float DEGREES_MIN = 0.0f; + const float DEGREES_MAX = 180.0f; + const size_t NUM_DIVISIONS = 10000; + + for(size_t i=0; i +#include +#include + +#include "libtrigo/sincos.h" + +enum APP_ERROR_CODES +{ + APP_ERROR_SUCCESS = 0, + APP_ERROR_OPERATION_FAILED, + APP_ERROR_UNKNOWN_SYMBOL, +}; + +int main(int argc, char* argv[]) +{ + float degrees; + + printf("Enter a value in degrees: "); + scanf ("%f",°rees); + + float sin_value = sindeg(degrees); + float cos_value = cosdeg(degrees); + if (sin_value == LIBTRIGO_INVALID || cos_value == LIBTRIGO_INVALID) + { + printf("Error. Unable to compute sin() or cos() value for %f degrees.\n", degrees); + return APP_ERROR_OPERATION_FAILED; + } + + printf("sin( %10.8f deg ) = %f\n", degrees, sin_value); + printf("cos( %10.8f deg ) = %f\n", degrees, cos_value); + + return APP_ERROR_SUCCESS; +} diff --git a/samples/demo_relative_dir/src/sincos.cpp b/samples/demo_relative_dir/src/sincos.cpp new file mode 100644 index 0000000..a1b2c97 --- /dev/null +++ b/samples/demo_relative_dir/src/sincos.cpp @@ -0,0 +1,87 @@ +/********************************************************************************** + * 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 "libtrigo/sincos.h" +#include "bin2cpp/file_sinus.h" + +struct SINUS_TABLE_ENTRY +{ + float degrees; + float value; +}; + +inline float map(float x, float in_min, float in_max, float out_min, float out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +float sindeg(float degrees) +{ + float result; + if (degrees < 0) + { + result = -sindeg(-degrees); + return result; + } + if (degrees > 360.0f) + { + int count = (int)(degrees/360.0f); + degrees -= count*360.0f; + } + if (degrees > 180.0f) + { + result = -sindeg(degrees-180.0f); + return result; + } + if (degrees == 0.0f) + return 0.0f; + else if (degrees == 90.0f) + return 1.0f; + else if (degrees == 180.0f) + return 0.0f; + + // resolve the sinus value from a table + const bin2cpp::File & sinus_table = bin2cpp::getSinusTableFile(); + const SINUS_TABLE_ENTRY * entries = (const SINUS_TABLE_ENTRY*)sinus_table.getBuffer(); + size_t num_entries = sinus_table.getSize()/sizeof(SINUS_TABLE_ENTRY); + + for(size_t i=0; i<(num_entries-1); i++) + { + const SINUS_TABLE_ENTRY & low = entries[i]; + const SINUS_TABLE_ENTRY & high = entries[i+1]; + if (low.degrees <= degrees && degrees <= high.degrees) + { + // proceed with linear interpolation + result = map(degrees, low.degrees, high.degrees, low.value, high.value); + return result; + } + } + + result = LIBTRIGO_INVALID; + return result; +} + +float cosdeg(float degrees) +{ + return sindeg(degrees + 90.0f); +} diff --git a/samples/demo_website/CMakeLists.txt b/samples/demo_website/CMakeLists.txt new file mode 100644 index 0000000..7f602ed --- /dev/null +++ b/samples/demo_website/CMakeLists.txt @@ -0,0 +1,48 @@ +set(GENERATED_TEST_FILES_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated_files) +file(MAKE_DIRECTORY ${GENERATED_TEST_FILES_DIR}) + +set(GENERATED_TEST_FILES + ${GENERATED_TEST_FILES_DIR}/index.h + ${GENERATED_TEST_FILES_DIR}/index.cpp + ${GENERATED_TEST_FILES_DIR}/blog/index.h + ${GENERATED_TEST_FILES_DIR}/blog/index.cpp + ${GENERATED_TEST_FILES_DIR}/blog/using-bin2cpp/index.h + ${GENERATED_TEST_FILES_DIR}/blog/using-bin2cpp/index.cpp + ${GENERATED_TEST_FILES_DIR}/blog/how-to-create-a-web-site/index.h + ${GENERATED_TEST_FILES_DIR}/blog/how-to-create-a-web-site/index.cpp + ${GENERATED_TEST_FILES_DIR}/contact/index.h + ${GENERATED_TEST_FILES_DIR}/contact/index.cpp + ${GENERATED_TEST_FILES_DIR}/home/index.h + ${GENERATED_TEST_FILES_DIR}/home/index.cpp + + ${GENERATED_TEST_FILES_DIR}/PagesFileManager.h + ${GENERATED_TEST_FILES_DIR}/PagesFileManager.cpp +) + + +add_custom_command( OUTPUT ${GENERATED_TEST_FILES} + # Execute bin2cpp generator + COMMAND $ + --dir=${CMAKE_CURRENT_SOURCE_DIR}/www + --managerfile=PagesFileManager.h + --output=${GENERATED_TEST_FILES_DIR} + --chunksize=50 + --namespace=www + --keepdirs +) + +# Show all generated files in a common folder +source_group("Generated Files" FILES ${GENERATED_TEST_FILES}) + +include_directories(${GENERATED_TEST_FILES_DIR}) + +add_executable(demo_website + demo_website.cpp + ${GENERATED_TEST_FILES} +) + +# Force CMAKE_DEBUG_POSTFIX for executables +set_target_properties(demo_website PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +# This is normally not required if bin2cpp is installed and in PATH. +add_dependencies(demo_website bin2cpp) diff --git a/samples/demo_website/demo_website.bat b/samples/demo_website/demo_website.bat new file mode 100644 index 0000000..7bd039e --- /dev/null +++ b/samples/demo_website/demo_website.bat @@ -0,0 +1,10 @@ +@echo off + +rmdir /S /Q outdir 1>NUL 2>NUL +mkdir outdir 1>NUL 2>NUL + +set path=%cd%\..\..\build\bin\Release;%cd%\..\..\build\bin\Debug;%PATH% + +bin2cpp.exe --dir=www --managerfile=PagesFileManager.h --namespace=www --output=.\outdir --chunksize=50 --keepdirs + +pause diff --git a/samples/demo_website/demo_website.cpp b/samples/demo_website/demo_website.cpp new file mode 100644 index 0000000..e495e6f --- /dev/null +++ b/samples/demo_website/demo_website.cpp @@ -0,0 +1,39 @@ +#include // printf +#include // getenv +#include +#include + +#include "PagesFileManager.h" + +int main(int argc, char* argv[]) +{ + www::FileManager & mgr = www::FileManager::getInstance(); + + //Print information about all files generated with "--managerfile" or --registerfile flags. + size_t num_files = mgr.getFileCount(); + std::cout << "Found " << num_files << " embedded web pages...\n"; + + //Listing files. + for(size_t i=0; igetFilePath() << "', " << file->getSize() << " bytes\n"; + } + + //Saving content back to files preserving the original directory structure. + std::string temp_dir = getenv("TEMP"); +#ifdef _WIN32 + temp_dir += "\\"; +#else + temp_dir += "/"; +#endif + temp_dir += "www"; + std::cout << "Saving embedded web pages to directory '" << temp_dir << "'...\n"; + bool saved = mgr.saveFiles(temp_dir.c_str()); + if (saved) + std::cout << "saved\n"; + else + std::cout << "failed\n"; + + return 0; +} diff --git a/samples/demo_website/www/blog/how-to-create-a-web-site/index.html b/samples/demo_website/www/blog/how-to-create-a-web-site/index.html new file mode 100644 index 0000000..93f1f59 --- /dev/null +++ b/samples/demo_website/www/blog/how-to-create-a-web-site/index.html @@ -0,0 +1,31 @@ + + + + + + How to create a web site + + +
+
+

What is Lorem Ipsum?

+

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.

+
+
+

Why do we use it?

+

It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).

+
+
+
+

Where does it come from?

+

Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.

+

The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.

+
+
+

Where can I get some?

+

There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.

+
+
+
+ + diff --git a/samples/demo_website/www/blog/index.html b/samples/demo_website/www/blog/index.html new file mode 100644 index 0000000..c99952f --- /dev/null +++ b/samples/demo_website/www/blog/index.html @@ -0,0 +1,15 @@ + + + + + + Blog index + + +

Blog index:

+ + + diff --git a/samples/demo_website/www/blog/using-bin2cpp/index.html b/samples/demo_website/www/blog/using-bin2cpp/index.html new file mode 100644 index 0000000..ccc5e4f --- /dev/null +++ b/samples/demo_website/www/blog/using-bin2cpp/index.html @@ -0,0 +1,37 @@ + + + + + + Using bin2cpp + + +
+

Lorem Ipsum

+

"Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."

+
"There is no one who loves pain itself, who seeks after it and wants to have it, simply because it is pain..."
+
+
+
+
+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque faucibus justo nec scelerisque porta. Vivamus sed nibh sit amet felis sagittis aliquam sodales ac lectus. Donec ullamcorper risus nec feugiat varius. Quisque aliquet sit amet mi at pharetra. Quisque accumsan est nec dolor blandit, ut porttitor libero pellentesque. Sed id tempor nibh. Cras in lorem eu justo pretium eleifend ut vitae dolor. Quisque nisi urna, congue eu erat id, vestibulum dignissim diam. Donec non felis quam. Cras finibus venenatis odio vitae tempus. Suspendisse potenti. Maecenas nunc purus, iaculis eget libero at, pretium finibus nisi. Proin felis ipsum, consequat at nulla nec, tempor hendrerit tortor. Aenean at lectus diam. +

+

+ Praesent aliquam dui sed dolor tincidunt iaculis. Nullam varius diam nec hendrerit vulputate. Phasellus sed ipsum magna. Aenean non varius lorem, in gravida odio. Fusce maximus velit vel suscipit consectetur. Praesent efficitur nibh et ante lobortis, nec consectetur leo tincidunt. Morbi dapibus, tellus ut cursus mollis, leo ipsum semper mi, vitae tincidunt leo lorem a est. Vestibulum aliquet efficitur diam quis pretium. Vestibulum id rhoncus tellus, ac venenatis sapien. Etiam tempus turpis quis dui faucibus eleifend. +

+

+ Quisque velit ligula, eleifend ut scelerisque sed, ornare vulputate nulla. Praesent vitae aliquet lectus. Nullam in aliquet urna, sed ullamcorper lacus. Aenean eget sodales velit. Morbi purus lacus, euismod eget maximus a, fringilla ac urna. Ut vehicula ante in nibh elementum, maximus dignissim dolor imperdiet. In eget turpis in eros fermentum viverra. Etiam sit amet nisl lobortis, scelerisque ante in, vulputate nunc. Aenean facilisis, libero id tempor placerat, est elit fermentum nisi, at dictum nibh ex vel lectus. Suspendisse rhoncus eu augue a volutpat. Vestibulum sed massa eu mauris maximus commodo euismod nec libero. In consequat libero lacus. Morbi vitae magna congue, blandit ante quis, commodo eros. In eu sapien ac est auctor blandit. Cras sit amet aliquam metus. Morbi aliquam ligula sed mi posuere malesuada. +

+

+ Integer faucibus enim in est faucibus, vel semper ligula varius. Phasellus purus justo, rhoncus id nunc eu, aliquam tempus nibh. Morbi ut mattis quam. Ut auctor eget odio vel semper. Vestibulum ultrices dolor a erat blandit, nec sodales dolor tincidunt. Duis accumsan tincidunt augue ut condimentum. Nulla sollicitudin magna augue, ut mollis urna ultrices eu. Maecenas aliquet sit amet mi quis auctor. Integer at convallis sapien. Phasellus viverra mollis massa id tempor. Etiam tortor enim, finibus sed venenatis ac, venenatis volutpat magna. Proin ac aliquam arcu, scelerisque tristique metus. +

+

+ Cras eu risus quis massa posuere molestie. Praesent sed imperdiet mauris. Fusce a dolor pellentesque, convallis urna vel, fermentum eros. Aenean iaculis porttitor nunc, id imperdiet erat condimentum luctus. Cras eget lectus odio. Aliquam nec erat enim. Aliquam ullamcorper augue eget nibh cursus ultricies. Duis imperdiet viverra nisl quis tempor. Cras sodales congue risus, at ultrices ligula pellentesque vel. Praesent vestibulum vulputate orci, nec porttitor risus fringilla nec. Maecenas imperdiet augue sagittis, dictum lectus et, suscipit nisi. Ut nec erat condimentum, euismod purus sed, rhoncus velit. Curabitur commodo, lacus et tempor pharetra, velit urna consequat augue, at euismod est libero vel metus. +

+
+
+
+
+ + diff --git a/samples/demo_website/www/contact/background.jpg b/samples/demo_website/www/contact/background.jpg new file mode 100644 index 0000000..79a2596 Binary files /dev/null and b/samples/demo_website/www/contact/background.jpg differ diff --git a/samples/demo_website/www/contact/index.html b/samples/demo_website/www/contact/index.html new file mode 100644 index 0000000..7ff78ad --- /dev/null +++ b/samples/demo_website/www/contact/index.html @@ -0,0 +1,52 @@ + + + + + + Contact Us + + + + +
+

Contact Me

+
+ +
+
+

Your Name (required)
+ +

+

Your Email (required)
+ +

+

Subject
+ +

+

Your Message
+ +

+

Are you human?

+

+ +

+

+ +
+
+ + + diff --git a/samples/demo_website/www/favicon.ico b/samples/demo_website/www/favicon.ico new file mode 100644 index 0000000..1d8891e Binary files /dev/null and b/samples/demo_website/www/favicon.ico differ diff --git a/samples/demo_website/www/home/index.html b/samples/demo_website/www/home/index.html new file mode 100644 index 0000000..88c9ab6 --- /dev/null +++ b/samples/demo_website/www/home/index.html @@ -0,0 +1,27 @@ + + + + + + Home! + + +Welcome to my home page. + +How to write a Website Welcome Message +On your homepage, you need to make it obvious to your visitors:- + +What your website offers them +What they can find and achieve on your website +You can achieve this in a number of ways:- + +If it is not immediately obvious to your visitors what your website is about, you are going to need to write a welcome message which makes the purpose of your website clear. +If your website is simple, it may not be necessary to write a welcome message. You may be able to display some sample previews of your content which, in combination with your menu, will make it obvious to your visitors what they can find on your website. +The modern trend is towards the second option – with no formal welcome message or statement of purpose. However, when a site is complex, it becomes essential to explain to your users, in as few simple words as possible, what they can find on your site and how they can get started. + +The key to writing a good welcome message is to make it focused on your users’ wants and needs, and make it extremely simple. + +Before you read further, a good starting point can be to read four simple homepage tips. + + + diff --git a/samples/demo_website/www/index.html b/samples/demo_website/www/index.html new file mode 100644 index 0000000..17e0d60 --- /dev/null +++ b/samples/demo_website/www/index.html @@ -0,0 +1,76 @@ + + + + + + Nature & Outdoors Blog + + + + + + + +
+

Welcome to the Nature & Outdoors Blog

+

Immerse yourself in the beauty of nature. Discover breathtaking landscapes, essential hiking tips, and the wonders of wildlife.

+ +

Our goal is to inspire adventure and share knowledge on preserving the great outdoors. From national parks to hidden gems, we've got it all.

+ +

Whether you're a seasoned explorer or a beginner, join us in appreciating the natural world like never before.

+
+ + + + + diff --git a/samples/demo_website/www/static/banner.jpg b/samples/demo_website/www/static/banner.jpg new file mode 100644 index 0000000..66dbca7 Binary files /dev/null and b/samples/demo_website/www/static/banner.jpg differ diff --git a/samples/demo_website/www/static/dark-mode.css b/samples/demo_website/www/static/dark-mode.css new file mode 100644 index 0000000..61ba07a --- /dev/null +++ b/samples/demo_website/www/static/dark-mode.css @@ -0,0 +1,41 @@ +body { + font-family: 'Arial', sans-serif; + background-color: #1B1F22; /* Deep charcoal */ + color: #E3E6D5; /* Soft cream text */ + margin: 0; + padding: 0; +} + +.container { + max-width: 800px; + margin: auto; + padding: 20px; +} + +h1, h2, h3 { + color: #A5C882; /* Muted pastel green */ +} + +a { + color: #CFAE6D; /* Warm golden brown for links */ + text-decoration: none; + transition: color 0.3s ease; +} + +a:hover { + color: #E0C085; /* Lightened golden shade */ +} + +.button { + background-color: #689F38; /* Earthy green */ + color: white; + padding: 10px 15px; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background 0.3s ease; +} + +.button:hover { + background-color: #4E7931; /* Slightly darker green */ +} diff --git a/samples/demo_website/www/static/light-mode.css b/samples/demo_website/www/static/light-mode.css new file mode 100644 index 0000000..f811c0d --- /dev/null +++ b/samples/demo_website/www/static/light-mode.css @@ -0,0 +1,41 @@ +body { + font-family: 'Arial', sans-serif; + background-color: #F8F5E1; /* Soft earthy tone */ + color: #2E4B30; /* Deep forest green */ + margin: 0; + padding: 0; +} + +.container { + max-width: 800px; + margin: auto; + padding: 20px; +} + +h1, h2, h3 { + color: #4D6B3C; /* Muted green for headers */ +} + +a { + color: #A15F34; /* Warm brown for links */ + text-decoration: none; + transition: color 0.3s ease; +} + +a:hover { + color: #C47C45; /* Lightened brown on hover */ +} + +.button { + background-color: #8BC34A; /* Nature-inspired green */ + color: white; + padding: 10px 15px; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background 0.3s ease; +} + +.button:hover { + background-color: #689F38; /* Slightly deeper green */ +} diff --git a/samples/demo_website/www/static/logo.svg b/samples/demo_website/www/static/logo.svg new file mode 100644 index 0000000..db73c68 --- /dev/null +++ b/samples/demo_website/www/static/logo.svg @@ -0,0 +1,809 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/demo_website/www/static/profile-picture.jpg b/samples/demo_website/www/static/profile-picture.jpg new file mode 100644 index 0000000..08500a9 Binary files /dev/null and b/samples/demo_website/www/static/profile-picture.jpg differ diff --git a/src/bin2cpp/ArrayGenerator.cpp b/src/bin2cpp/ArrayGenerator.cpp index 500c332..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,106 +49,170 @@ 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(getInputFilePath(), "rb"); - if (!input) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Uppercase function identifier - std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(mFunctionIdentifier); - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(cpp_file_path); - std::string cppPath = cpp_file_path; + 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; + } - //create cpp file - FILE * cpp = fopen(cppPath.c_str(), "w"); - if (!cpp) - { - fclose(input); + bool ArrayGenerator::printFileContent() + { + //check if input file exists + if (!ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - } - - //determine file properties - uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(getInputFilePath()); - - //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", getHeaderFilename() ); - fprintf(cpp, "#include //for FILE\n"); - fprintf(cpp, "#include //for memcpy\n"); - fprintf(cpp, "namespace %s\n", mNamespace.c_str()); - fprintf(cpp, "{\n"); - fprintf(cpp, " class %s : public virtual %s::%s\n", className.c_str(), mNamespace.c_str(), mBaseClass.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 { return \"%s\"; }\n", ra::filesystem::GetFilename(getInputFilePath()).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[mChunkSize]; - while(!feof(input)) - { - //read a chunk of the file - size_t readSize = fread(buffer, 1, mChunkSize, input); - - bool isLastChunk = !(readSize == mChunkSize); - - 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 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", mBaseClass.c_str(), getterFunctionName.c_str(), className.c_str()); - if (isRegisterFileEnabled()) - { - std::string fileManagerTemplate = getFileManagerRegistrationTemplate(); - fprintf(cpp, "%s", fileManagerTemplate.c_str()); - } - fprintf(cpp, "}; //%s\n", mNamespace.c_str()); - - fclose(input); - fclose(cpp); + + std::ostringstream output_stream; + writeInputFileDataAsCode(output_stream); + std::string str = output_stream.str(); + + printf("\"%s\"", str.c_str()); return true; } + bool ArrayGenerator::createCSourceFile(const char* file_path) + { + //check if input file exists + 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; + } + + 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 5e33912..7093a9d 100644 --- a/src/bin2cpp/ArrayGenerator.h +++ b/src/bin2cpp/ArrayGenerator.h @@ -40,7 +40,10 @@ namespace bin2cpp ArrayGenerator(); virtual ~ArrayGenerator(); 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(); + 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 84636c4..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 @@ -33,12 +34,11 @@ #include "rapidassist/strings.h" #include "rapidassist/filesystem.h" #include "rapidassist/timing.h" +#include "rapidassist/code_cpp.h" namespace bin2cpp { - BaseGenerator::BaseGenerator() : - mCppEncoder(IGenerator::CPP_ENCODER_OCT), - mManagerEnabled(false) + BaseGenerator::BaseGenerator() { } @@ -46,115 +46,88 @@ namespace bin2cpp { } - void BaseGenerator::setInputFilePath(const char * path) + void BaseGenerator::setContext(const Context& c) { - if (path) - mInputFilePath = path; + mContext = c; } - const char * BaseGenerator::getInputFilePath() const + const Context& BaseGenerator::getContext() const { - return mInputFilePath.c_str(); + return mContext; } - void BaseGenerator::setHeaderFilename(const char * path) + bool BaseGenerator::lookupStringVariable(const std::string& name, std::string& output) { - if (path) - mHeaderFilename = path; - } - - const char * BaseGenerator::getHeaderFilename() const - { - return mHeaderFilename.c_str(); - } + 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; } - void BaseGenerator::setFunctionIdentifier(const char * function_identifier) - { - if (function_identifier) - mFunctionIdentifier = function_identifier; - } - - const char * BaseGenerator::getFunctionIdentifier() const - { - return mFunctionIdentifier.c_str(); - } - - void BaseGenerator::setChunkSize(size_t chunk_size) - { - mChunkSize = chunk_size; - } - - size_t BaseGenerator::getChunkSize() const - { - return mChunkSize; - } - - void BaseGenerator::setNamespace(const char * name) - { - if (name) - mNamespace = name; - } - - const char * BaseGenerator::getNamespace() const - { - return mNamespace.c_str(); - } - - void BaseGenerator::setBaseClass(const char * name) - { - if (name) - mBaseClass = name; - } - - const char * BaseGenerator::getBaseClass() const - { - return mBaseClass.c_str(); - } - - void BaseGenerator::setCppEncoder(const IGenerator::CppEncoderEnum & cpp_encoder) - { - mCppEncoder = cpp_encoder; + // Unknown name + return false; } - IGenerator::CppEncoderEnum BaseGenerator::getCppEncoder() const + bool BaseGenerator::lookupStreamVariable(const std::string& name, std::ostream& output) { - return mCppEncoder; - } - - void BaseGenerator::setManagerHeaderFilename(const char * manager_file) - { - if (manager_file) - mManagerHeaderFilename = manager_file; - } - - const char * BaseGenerator::getManagerHeaderFilename() const - { - return mManagerHeaderFilename.c_str(); - } - - void BaseGenerator::setRegisterFileEnabled(bool register_file_enabled) - { - mManagerEnabled = register_file_enabled; - } + if ( name == "bin2cpp_insert_input_file_as_code" ) + { + writeInputFileDataAsCode(output); + return true; + } - bool BaseGenerator::isRegisterFileEnabled() const - { - return mManagerEnabled; + return false; } //------------------------------- //protected methods //------------------------------- - std::string BaseGenerator::getGetterFunctionName() + std::string BaseGenerator::getFileObjectGetterFunctionName() { - //Uppercase function identifier - std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(mFunctionIdentifier); std::string getter; - getter.append("get"); - getter.append(functionIdentifier); - getter.append("File"); + switch ( mContext.code ) + { + default: + case CODE_GENERATION_CPP: + { + //Uppercase function identifier + std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(mContext.functionIdentifier); + + getter.append("get"); + getter.append(functionIdentifier); + getter.append("File"); + } + break; + case CODE_GENERATION_C: + { + //Uppercase function identifier + std::string functionIdentifier = ra::strings::Lowercase(mContext.functionIdentifier); + + getter.append(mContext.codeNamespace); + getter.append("_get_file_"); + getter.append(functionIdentifier); + } + break; + }; + return getter; } @@ -162,7 +135,17 @@ namespace bin2cpp { //Build header file path std::string headerPath = cpp_file_path; - ra::strings::Replace(headerPath, ".cpp", ".h"); + switch ( mContext.code ) + { + default: + case CODE_GENERATION_CPP: + ra::strings::Replace(headerPath, ".cpp", ".h"); + break; + case CODE_GENERATION_C: + ra::strings::Replace(headerPath, ".c", ".h"); + break; + }; + return headerPath; } @@ -170,7 +153,17 @@ namespace bin2cpp { //Build header file path std::string cppPath = header_file_path; - ra::strings::Replace(cppPath, ".cpp", ".h"); + switch ( mContext.code ) + { + default: + case CODE_GENERATION_CPP: + ra::strings::Replace(cppPath, ".cpp", ".h"); + break; + case CODE_GENERATION_C: + ra::strings::Replace(cppPath, ".c", ".h"); + break; + }; + return cppPath; } @@ -189,8 +182,8 @@ namespace bin2cpp header << " * bin2cpp is open source software, see http://github.com/end2endzone/bin2cpp\n"; if (include_source_file) { - std::string filename = ra::filesystem::GetFilename(mInputFilePath.c_str()); - uint64_t lastModifiedDate = ra::filesystem::GetFileModifiedDate(mInputFilePath); + std::string filename = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); + uint64_t lastModifiedDate = ra::filesystem::GetFileModifiedDate(mContext.inputFilePath); header << " * Source code for file '" << filename << "', last modified " << lastModifiedDate << ".\n"; } header << " * Do not modify this file.\n"; @@ -198,40 +191,86 @@ namespace bin2cpp return header; } - std::string BaseGenerator::getSaveMethodTemplate() + std::string BaseGenerator::getCppSaveMethodTemplate() { std::string output; - output << " virtual bool save(const char * iFilename) const\n"; + output << " virtual bool save(const char * filename) const\n"; output << " {\n"; - output << " FILE * f = fopen(iFilename, \"wb\");\n"; - output << " if (!f) return false;\n"; + output << " std::ofstream f(filename, std::ios::out | std::ios::binary | std::ios::trunc);\n"; + output << " if (f.fail()) return false;\n"; output << " size_t fileSize = getSize();\n"; output << " const char * buffer = getBuffer();\n"; - output << " fwrite(buffer, 1, fileSize, f);\n"; - output << " fclose(f);\n"; + output << " f.write(buffer, fileSize);\n"; + output << " f.close();\n"; output << " return true;\n"; output << " }\n"; return output; } - std::string BaseGenerator::getFileManagerRegistrationTemplate() + std::string BaseGenerator::getCppFileManagerRegistrationImplementationTemplate() { - if (!this->isRegisterFileEnabled()) + if (!mContext.registerFiles) return std::string(); //Build class name std::string className = getClassName(); std::string output; - output << " typedef const " << mBaseClass << " & (*t_func)();\n"; + output << " typedef const " << mContext.baseClass << " & (*t_func)();\n"; output << " extern bool RegisterFile(t_func iFunctionPointer);\n"; - output << " static bool k" << className << "Registered = " << mNamespace << "::RegisterFile(&" << getGetterFunctionName() << ");\n"; + output << " static bool k" << className << "Registered = " << mContext.codeNamespace << "::RegisterFile(&" << getFileObjectGetterFunctionName() << ");\n"; + output << " \n"; + return output; + } + + std::string BaseGenerator::getCFileManagerRegistrationPredeclarationImplementation() + { + if ( !mContext.registerFiles ) + return std::string(); + + std::string output; + output << "extern bool " << mContext.codeNamespace << "_filemanager_register_file(" << mContext.baseClass << " * file); \n"; + output << "\n"; + return output; + } + + std::string BaseGenerator::getCFileManagerStaticFileRegistrationImplementation() + { + if ( !mContext.registerFiles ) + return std::string(); + + //Lowercase function identifier + 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 << "_" << 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_" << 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(mFunctionIdentifier); + std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(mContext.functionIdentifier); std::string className; className.append(functionIdentifier.c_str()); className.append("File"); @@ -240,7 +279,7 @@ namespace bin2cpp std::string BaseGenerator::getClassMacroGuardPrefix() { - std::string macroGuardPrefix = ra::strings::Uppercase(mNamespace); + std::string macroGuardPrefix = ra::strings::Uppercase(mContext.codeNamespace); //remove namespace separators ra::strings::Replace(macroGuardPrefix, "::", "_"); @@ -248,178 +287,242 @@ namespace bin2cpp return macroGuardPrefix; } - bool BaseGenerator::createCppHeaderFile(const char * header_file_path) + std::string BaseGenerator::getFileManagerMacroGuardPrefix() { - FILE * header = fopen(header_file_path, "w"); - if (!header) - return false; + //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; + } - //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", mNamespace.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", mBaseClass.c_str()); - fprintf(header, " {\n"); - fprintf(header, " public:\n"); - fprintf(header, " virtual size_t getSize() const = 0;\n"); - fprintf(header, " virtual const char * getFilename() const = 0;\n"); - fprintf(header, " virtual const char * getBuffer() const = 0;\n"); - fprintf(header, " virtual bool save(const char * iFilename) const = 0;\n"); - fprintf(header, " };\n"); - fprintf(header, " #endif //%s_EMBEDDEDFILE_CLASS\n", classMacroGuardPrefix.c_str()); - fprintf(header, " const %s & %s();\n", mBaseClass.c_str(), getGetterFunctionName().c_str()); - fprintf(header, "}; //%s\n", mNamespace.c_str()); - fprintf(header, "\n"); - fprintf(header, "#endif //%s\n", macroGuard.c_str()); - - fclose(header); + std::string BaseGenerator::getFileObjectFileName() + { + std::string output; - return true; + std::string inputFileName = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); + + //return default implementation + output += inputFileName; + return output; } - bool BaseGenerator::createManagerHeaderFile(const char * header_file_path) + std::string BaseGenerator::getFileObjectFilePath() { - FILE * header = fopen(header_file_path, "w"); - if (!header) - return false; + std::string output; - //define macro guard a macro matching the filename - std::string macroGuard; - macroGuard += getCppIncludeGuardMacroName(mNamespace.c_str()); //prefix the custom namespace for the file manager - if (!macroGuard.empty()) - macroGuard += "_"; - macroGuard += getCppIncludeGuardMacroName(header_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", mNamespace.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", mBaseClass.c_str()); - fprintf(header, " {\n"); - fprintf(header, " public:\n"); - fprintf(header, " virtual size_t getSize() const = 0;\n"); - fprintf(header, " virtual const char * getFilename() const = 0;\n"); - fprintf(header, " virtual const char * getBuffer() const = 0;\n"); - fprintf(header, " virtual bool save(const char * iFilename) 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", mBaseClass.c_str()); - fprintf(header, " static FileManager & getInstance();\n"); - fprintf(header, " void registerFile(t_func iFunctionPtr);\n"); - fprintf(header, " size_t getFileCount() const;\n"); - fprintf(header, " const %s * getFile(const size_t & index) const;\n", mBaseClass.c_str()); - fprintf(header, " bool saveFiles(const char * iDirectory) 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", mNamespace.c_str()); - fprintf(header, "\n"); - fprintf(header, "#endif //%s\n", macroGuard.c_str()); - - fclose(header); + //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 + + //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 + { + //if reported path is not specified ? + //report the same as getFileName() + output = getFileObjectFileName(); + return output; + } - return true; + //return default implementation + output += path; + return output; + } + + std::string BaseGenerator::getHeaderFileIncludePath() + { + return mContext.headerFilename; + } + + void BaseGenerator::writeInputFileDataAsCode(std::ostream& output) + { + //check if input file exists + FILE* fin = fopen(mContext.inputFilePath.c_str(), "rb"); + if ( !fin ) + return; + + uint64_t fileSize = ra::filesystem::GetFileSize64(mContext.inputFilePath.c_str()); + size_t chunkCount = fileSize / mContext.chunkSize; + if ( fileSize % mContext.chunkSize > 0 ) + chunkCount++; + + //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) ) + { + //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; + + fclose(fin); + } + + void BaseGenerator::writeInputFileChunkAsCode(const unsigned char* buffer, size_t buffer_size, size_t index, size_t count, bool is_last_chunk, std::ostream& output) + { } - bool BaseGenerator::createManagerSourceFile(const char * cpp_file_path) + bool BaseGenerator::createCppHeaderFile(const char * header_file_path) { - FILE * cpp = fopen(cpp_file_path, "w"); - if (!cpp) + 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() + { + //check if input file exists + FILE * input = fopen(mContext.inputFilePath.c_str(), "rb"); + if (!input) 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", getManagerHeaderFilename()); - fprintf(cpp, "#include \n"); - fprintf(cpp, "\n"); - fprintf(cpp, "namespace %s\n", mNamespace.c_str()); - fprintf(cpp, "{\n"); - fprintf(cpp, " bool RegisterFile(FileManager::t_func iFunctionPointer)\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " if (iFunctionPointer == NULL)\n"); - fprintf(cpp, " return false;\n"); - fprintf(cpp, " FileManager::getInstance().registerFile(iFunctionPointer);\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 iFunctionPtr) { functions_.push_back(iFunctionPtr); }\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", mNamespace.c_str()); - fprintf(cpp, " return &resource;\n"); - fprintf(cpp, " }\n"); - fprintf(cpp, " bool FileManager::saveFiles(const char * iDirectory) const\n"); - fprintf(cpp, " {\n"); - fprintf(cpp, " if (iDirectory == NULL)\n"); - fprintf(cpp, " return false;\n"); - fprintf(cpp, " size_t count = getFileCount();\n"); - fprintf(cpp, " for(size_t i=0; igetFilename());\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, "}; //%s\n", mNamespace.c_str()); - - fclose(cpp); + //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[mContext.chunkSize]; + while(!feof(input)) + { + //read a chunk of the file + size_t readSize = fread(buffer, 1, mContext.chunkSize, input); + + bool isLastChunk = !(readSize == mContext.chunkSize); + + if (readSize > 0) + { + if (numLinePrinted > 0) + { + //end previous line + printf("\n"); + } + + //output + std::string text; + switch(mContext.cppEncoder) + { + case CPP_ENCODER_HEX: + text = ra::code::cpp::ToHexString(buffer, readSize); + break; + case CPP_ENCODER_OCT: + default: + text = ra::code::cpp::ToOctString(buffer, readSize, false); + break; + }; + printf("\"%s\"", text.c_str()); + numLinePrinted++; + } + } + delete[] buffer; + buffer = NULL; + + fclose(input); return true; } + bool BaseGenerator::createCHeaderFile(const char* 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" + "#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) + { + // not supported yet + return false; + } + }; //bin2cpp \ No newline at end of file diff --git a/src/bin2cpp/BaseGenerator.h b/src/bin2cpp/BaseGenerator.h index d9a3182..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 { @@ -40,52 +41,42 @@ namespace bin2cpp virtual ~BaseGenerator(); //IGenerator methods - virtual void setInputFilePath(const char * path); - virtual const char * getInputFilePath() const; - virtual void setHeaderFilename(const char * path); - virtual const char * getHeaderFilename() const; - virtual void setFunctionIdentifier(const char * function_identifier); - virtual const char * getFunctionIdentifier() const; - virtual void setChunkSize(size_t chunk_size); - virtual size_t getChunkSize() const; - virtual void setNamespace(const char * name); - virtual const char * getNamespace() const; - virtual void setBaseClass(const char * name); - virtual const char * getBaseClass() const; - virtual void setCppEncoder(const CppEncoderEnum & cpp_encoder); - virtual CppEncoderEnum getCppEncoder() const; - virtual void setManagerHeaderFilename(const char * manager_file); - virtual const char * getManagerHeaderFilename() const; - virtual void setRegisterFileEnabled(bool register_file_enabled); - virtual bool isRegisterFileEnabled() const; + 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 createManagerHeaderFile(const char * header_file_path); - virtual bool createManagerSourceFile(const char * cpp_file_path); + virtual bool printFileContent(); + virtual bool createCHeaderFile(const char* file_path); + virtual bool createCSourceFile(const char* file_path); 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 getFileManagerRegistrationTemplate(); + virtual std::string getCppSaveMethodTemplate(); + virtual std::string getCppFileManagerRegistrationImplementationTemplate(); + virtual std::string getCFileManagerRegistrationPredeclarationImplementation(); + virtual std::string getCFileManagerStaticFileRegistrationImplementation(); + virtual std::string getCFileManagerRegistrationPostInitImplementation(); virtual std::string getClassName(); virtual std::string getClassMacroGuardPrefix(); + 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 - std::string mInputFilePath; - std::string mHeaderFilename; - std::string mFunctionIdentifier; - size_t mChunkSize; - std::string mNamespace; - std::string mBaseClass; - std::string mManagerHeaderFilename; - IGenerator::CppEncoderEnum mCppEncoder; - bool mManagerEnabled; + Context mContext; }; }; //bin2cpp diff --git a/src/bin2cpp/CMakeLists.txt b/src/bin2cpp/CMakeLists.txt index d3689e1..c21f1b5 100644 --- a/src/bin2cpp/CMakeLists.txt +++ b/src/bin2cpp/CMakeLists.txt @@ -15,14 +15,28 @@ add_executable(bin2cpp bin2cpp.samples.txt common.cpp common.h + Context.cpp + Context.h crc32.cpp crc32.h + enums.h IGenerator.h + INameProvider.h + ITemplateVariableLookup.h + LegacyNameProvider.cpp + LegacyNameProvider.h main.cpp + ManagerGenerator.cpp + ManagerGenerator.h SegmentGenerator.cpp SegmentGenerator.h StringGenerator.cpp StringGenerator.h + TemplateProcessor.cpp + TemplateProcessor.h + types.h + wildcard.cpp + wildcard.h Win32ResourceGenerator.cpp Win32ResourceGenerator.h ) diff --git a/src/bin2cpp/Context.cpp b/src/bin2cpp/Context.cpp new file mode 100644 index 0000000..dee7bbc --- /dev/null +++ b/src/bin2cpp/Context.cpp @@ -0,0 +1,114 @@ +/********************************************************************************** + * 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 "Context.h" + +namespace bin2cpp +{ + Context::Context() + { + reset(); + } + + Context::Context(const Context& other) + { + (*this) = other; + } + + Context::~Context() + { + } + + Context& Context::operator=(const Context& other) + { + if ( this != &other ) + { + this->hasInputFile = other.hasInputFile ; + this->hasInputDir = other.hasInputDir ; + this->hasOutputDir = other.hasOutputDir ; + this->hasReportedFilePath = other.hasReportedFilePath ; + this->hasManagerFile = other.hasManagerFile ; + this->hasDirectoryIncludeFilters = other.hasDirectoryIncludeFilters ; + this->hasDirectoryExcludeFilters = other.hasDirectoryExcludeFilters ; + this->keepDirectoryStructure = other.keepDirectoryStructure ; + this->overrideExistingFiles = other.overrideExistingFiles ; + this->registerFiles = other.registerFiles ; + this->plainOutput = other.plainOutput ; + this->inputFilePath = other.inputFilePath ; + this->inputDirPath = other.inputDirPath ; + this->outputDirPath = other.outputDirPath ; + this->headerFilename = other.headerFilename ; + this->functionIdentifier = other.functionIdentifier ; + this->reportedFilePath = other.reportedFilePath ; + this->chunkSize = other.chunkSize ; + this->codeNamespace = other.codeNamespace ; + this->baseClass = other.baseClass ; + this->managerHeaderFilename = other.managerHeaderFilename ; + this->cppEncoder = other.cppEncoder ; + this->generatorName = other.generatorName ; + this->directoryIncludeFilters = other.directoryIncludeFilters ; + this->directoryExcludeFilters = other.directoryExcludeFilters ; + this->code = other.code ; + } + return *this; + } + + void Context::reset() + { + hasInputFile = false; + hasInputDir = false; + hasOutputDir = false; + hasReportedFilePath = false; + hasManagerFile = false; + keepDirectoryStructure = false; + overrideExistingFiles = false; + registerFiles = false; + plainOutput = false; + hasDirectoryIncludeFilters = false; + hasDirectoryExcludeFilters = false; + + inputFilePath.clear(); + inputDirPath.clear(); + outputDirPath.clear(); + headerFilename.clear(); + functionIdentifier.clear(); + reportedFilePath.clear(); + chunkSize = 0; + codeNamespace.clear(); + baseClass.clear(); + managerHeaderFilename.clear(); + cppEncoder = CppEncoderEnum::CPP_ENCODER_HEX; + generatorName.clear(); + directoryIncludeFilters.clear(); + directoryExcludeFilters.clear(); + code = CodeGenerationEnum::CODE_GENERATION_CPP; + } + + + //------------------------------- + //protected methods + //------------------------------- + + +}; //bin2cpp \ No newline at end of file diff --git a/src/bin2cpp/Context.h b/src/bin2cpp/Context.h new file mode 100644 index 0000000..3262713 --- /dev/null +++ b/src/bin2cpp/Context.h @@ -0,0 +1,87 @@ +/********************************************************************************** + * 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 CONTEXT_H +#define CONTEXT_H + +#include +#include +#include "enums.h" + +namespace bin2cpp +{ + + /// + ///This is the command line context for generating code. + /// + class Context + { + public: + Context(); + Context(const Context & other); + virtual ~Context(); + + Context& operator=(const Context& other); + + // flags + bool hasInputFile; // true if 'inputFilePath' is set. + bool hasInputDir; // true if 'inputDirPath' is set. + bool hasOutputDir; // true if 'outputDirPath' is set. + bool hasReportedFilePath; // true if 'reportedFilePath' is set. + bool hasManagerFile; // true if 'managerHeaderFilename' is set. + bool keepDirectoryStructure; // true if the output files must have the same directory structure as the input files. Valid only when --dir is used. + bool overrideExistingFiles; + bool registerFiles; + bool plainOutput; + bool hasDirectoryIncludeFilters; + bool hasDirectoryExcludeFilters; + + // public attributes + std::string inputFilePath; // The path of the input file (resource) to embeded as C++ source code. + std::string inputDirPath; + std::string outputDirPath; + std::string headerFilename; // The path of the input file (resource) to embeded as C++ source code. + std::string functionIdentifier; + std::string reportedFilePath; // path reported in the public api when calling getFilePath(); + size_t chunkSize; + std::string codeNamespace; + std::string baseClass; + std::string managerHeaderFilename; + CppEncoderEnum cppEncoder; + std::string generatorName; + std::vector directoryIncludeFilters; + std::vector directoryExcludeFilters; + CodeGenerationEnum code; + + void reset(); + + protected: + + //attributes + + }; + +}; //bin2cpp + +#endif //BASEGENERATOR_H diff --git a/src/bin2cpp/IGenerator.h b/src/bin2cpp/IGenerator.h index 44cf417..da7ca54 100644 --- a/src/bin2cpp/IGenerator.h +++ b/src/bin2cpp/IGenerator.h @@ -26,137 +26,27 @@ #define IGENERATOR_H #include - +#include "Context.h" +#include "ITemplateVariableLookup.h" + namespace bin2cpp { - class IGenerator + class IGenerator : public virtual ITemplateVariableLookup { public: /// - ///Get the name of the generator. - /// - ///Returns the name of the generator - virtual const char * getName() const = 0; - - /// - ///Defines the path of the binary input file. - /// - ///The path of the input file (resource) to embeded as C++ source code. - virtual void setInputFilePath(const char * path) = 0; - - /// - ///Provides the path of the binary input file. - /// - ///Returns the path of the binary input file. Returns an empty string if not defined. - virtual const char * getInputFilePath() const = 0; - - /// - ///Defines the filename of the generated header. - /// - ///The path of the input file (resource) to embeded as C++ source code. - virtual void setHeaderFilename(const char * path) = 0; - - /// - ///Provides the filename of the generated header. - /// - ///Returns the path of the binary input file. Returns an empty string if not defined. - virtual const char * getHeaderFilename() const = 0; - - /// - ///Defines the unique identifier name for the File class getter function. - /// - ///The unique identifier name for the File class getter function. - virtual void setFunctionIdentifier(const char * function_identifier) = 0; - - /// - ///Provides the unique identifier name for the File class getter function. - /// - ///Returns the unique identifier name for the File class getter function. Returns an empty string if not defined. - virtual const char * getFunctionIdentifier() const = 0; - - /// - ///Defines the size in bytes of each chunk of data. - /// - ///The size in bytes of each chunk of data. - virtual void setChunkSize(size_t chunk_size) = 0; - - /// - ///Provides the size in bytes of each chunk of data. - /// - ///Returns the unique identifier name for the File class getter function. Returns an empty string if not defined. - virtual size_t getChunkSize() const = 0; - - /// - ///Defines the namespace of the generated code. - /// - ///The name of the namespace of the generated code. - virtual void setNamespace(const char * name) = 0; - - /// - ///Provides the namespace of the generated code. - /// - ///Returns the name of the namespace of the generated code. Returns an empty string if not defined. - virtual const char * getNamespace() const = 0; - - /// - ///Defines the base class of the generated code. - /// - ///The name of the base class of the generated code. - virtual void setBaseClass(const char * name) = 0; - - /// - ///Provides the base class of the generated code. + ///Sets the current context for the generator. /// - ///Returns the name of the base class of the generated code. Returns an empty string if not defined. - virtual const char * getBaseClass() const = 0; + ///The new context. + virtual void setContext(const Context& c) = 0; /// - ///Defines the filename of the FileManager generated header. + ///Get the current context set for the generator. /// - ///The path of the FileManager output file. - virtual void setManagerHeaderFilename(const char * path) = 0; - - /// - ///Provides the filename of the FileManager generated header. - /// - ///Returns the path of the FileManager output file. Returns an empty string if not defined. - virtual const char * getManagerHeaderFilename() const = 0; - - /// - ///Enable or disable the registration of the generated file to the FileManager. - /// - ///The new value of the flag. - virtual void setRegisterFileEnabled(bool register_file_enabled) = 0; - - /// - ///Returns true if the generated file should be registated FileManager should be used in generated code. - /// - ///Returns true if the FileManager should be used in generated code. Returns false otherwise. - virtual bool isRegisterFileEnabled() const = 0; - - /// - ///Defines the different type of cpp encoding. - ///See setCppEncoder() and getCppEncoder() functions. - /// - enum CppEncoderEnum - { - CPP_ENCODER_OCT, - CPP_ENCODER_HEX, - }; - - /// - ///Defines the type of cpp encoder to use. See CppEncoderEnum for details. - /// - ///The type of cpp encoder to use - virtual void setCppEncoder(const CppEncoderEnum & cpp_encoder) = 0; - - /// - ///Provides the type of cpp encoder to use. See CppEncoderEnum for details. - /// - ///Returns the type of cpp encoder to use. - virtual CppEncoderEnum getCppEncoder() const = 0; + ///Returns the current context set for the generator. + virtual const Context& getContext() const = 0; /// ///Creates a header file for embedding a given file into C++ source code. @@ -173,18 +63,24 @@ namespace bin2cpp virtual bool createCppSourceFile(const char * cpp_file_path) = 0; /// - ///Creates a FileManager header file. + ///Creates a header file for embedding a given file into C source code. /// - ///The path of the header file (*.h). + ///The path of the header file (*.h) to generate. ///Returns true when the file was created. Returns false otherwise. - virtual bool createManagerHeaderFile(const char * header_file_path) = 0; + virtual bool createCHeaderFile(const char* file_path) = 0; /// - ///Creates a FileManager cpp file. + ///Creates a C source file for embedding a given file into C source code. /// - ///The path of the cpp file (*.h). + ///The path of the source file (*.c) to generate. ///Returns true when the file was created. Returns false otherwise. - virtual bool createManagerSourceFile(const char * cpp_file_path) = 0; + virtual bool createCSourceFile(const char* file_path) = 0; + + /// + ///Print the encoded file content to stdout + /// + ///Returns true when the operation is succesful. Returns false otherwise. + virtual bool printFileContent() = 0; }; diff --git a/src/bin2cpp/INameProvider.h b/src/bin2cpp/INameProvider.h new file mode 100644 index 0000000..173e233 --- /dev/null +++ b/src/bin2cpp/INameProvider.h @@ -0,0 +1,53 @@ +/********************************************************************************** + * 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 INAME_PROVIDER_H +#define INAME_PROVIDER_H + +#include "types.h" + +namespace bin2cpp +{ + + class INameProvider + { + public: + + /// + ///Get the name of a function identifier based on a given file path. + /// + ///The new context. + virtual std::string getDefaultFunctionIdentifier(const std::string & path, Dictionary & dict) = 0; + + /// + ///Get the name of a function identifier based on a given file path. + /// + ///The new context. + virtual std::string getDefaultHeaderFile(const std::string& path) = 0; + + }; + +}; //bin2cpp + +#endif //INAME_PROVIDER_H 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/LegacyNameProvider.cpp b/src/bin2cpp/LegacyNameProvider.cpp new file mode 100644 index 0000000..5020242 --- /dev/null +++ b/src/bin2cpp/LegacyNameProvider.cpp @@ -0,0 +1,64 @@ +/********************************************************************************** + * 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 "LegacyNameProvider.h" + +#include "common.h" + +#include "rapidassist/strings.h" +#include "rapidassist/filesystem.h" + +namespace bin2cpp +{ + LegacyNameProvider::LegacyNameProvider() + { + } + + LegacyNameProvider::~LegacyNameProvider() + { + } + + std::string LegacyNameProvider::getDefaultFunctionIdentifier(const std::string& path, Dictionary& dict) + { + std::string output; + + //use the file name without extension as 'identifier'. + output = getUniqueFunctionIdentifierFromPath(path.c_str(), dict); + output = ra::strings::CapitalizeFirstCharacter(output); + + return output; + } + + std::string LegacyNameProvider::getDefaultHeaderFile(const std::string& path) + { + std::string output; + + //use the file name without extension as 'headerfile'. + output = ra::filesystem::GetFilenameWithoutExtension(path.c_str()); + output += ".h"; + + return output; + } + +}; //bin2cpp \ No newline at end of file diff --git a/src/bin2cpp/LegacyNameProvider.h b/src/bin2cpp/LegacyNameProvider.h new file mode 100644 index 0000000..29a1bd0 --- /dev/null +++ b/src/bin2cpp/LegacyNameProvider.h @@ -0,0 +1,48 @@ +/********************************************************************************** + * 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 LEGACYNAMEPROVIDER_H +#define LEGACYNAMEPROVIDER_H + +#include "INameProvider.h" + +namespace bin2cpp +{ + /// + ///This is the legacy name generator which generates names for version 3.0.1 and before. + /// + class LegacyNameProvider : public virtual INameProvider + { + public: + LegacyNameProvider(); + virtual ~LegacyNameProvider(); + + //INameProvider methods + virtual std::string getDefaultFunctionIdentifier(const std::string& path, Dictionary& dict); + virtual std::string getDefaultHeaderFile(const std::string& path); + }; + +}; //bin2cpp + +#endif //LEGACYNAMEPROVIDER_H diff --git a/src/bin2cpp/ManagerGenerator.cpp b/src/bin2cpp/ManagerGenerator.cpp new file mode 100644 index 0000000..e5825ae --- /dev/null +++ b/src/bin2cpp/ManagerGenerator.cpp @@ -0,0 +1,443 @@ +/********************************************************************************** + * 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 "ManagerGenerator.h" +#include "TemplateProcessor.h" +#include +#include +#include +#include + +#include "common.h" + +namespace bin2cpp +{ + ManagerGenerator::ManagerGenerator() + { + } + + ManagerGenerator::~ManagerGenerator() + { + } + + const char * ManagerGenerator::getName() const + { + return "manager"; + } + + bool ManagerGenerator::createCppHeaderFile(const char* file_path) + { + 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" + ; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; + } + + bool ManagerGenerator::createCppSourceFile(const char* file_path) + { + const std::string text = "" + "${bin2cpp_file_manager_file_header}" + "#include \"${bin2cpp_file_manager_header_file_name}\"\n" + "#include \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" + ; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; + } + + bool ManagerGenerator::createCSourceFile(const char* file_path) + { + 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" + ; + + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); + + return write_success; + } + + bool ManagerGenerator::printFileContent() + { + return false; + } + +}; //bin2cpp \ No newline at end of file diff --git a/src/bin2cpp/ManagerGenerator.h b/src/bin2cpp/ManagerGenerator.h new file mode 100644 index 0000000..7bad555 --- /dev/null +++ b/src/bin2cpp/ManagerGenerator.h @@ -0,0 +1,51 @@ +/********************************************************************************** + * 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 MANAGERGENERATOR_H +#define MANAGERGENERATOR_H + +#include "BaseGenerator.h" + +namespace bin2cpp +{ + + /// + ///This generator generate the File Manager class files. + /// + class ManagerGenerator : public BaseGenerator + { + public: + ManagerGenerator(); + virtual ~ManagerGenerator(); + virtual const char * getName() const; + 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(); + }; + +}; //bin2cpp + +#endif //ARRAYGENERATOR_H diff --git a/src/bin2cpp/SegmentGenerator.cpp b/src/bin2cpp/SegmentGenerator.cpp old mode 100644 new mode 100755 index a4b82f9..d01f52f --- a/src/bin2cpp/SegmentGenerator.cpp +++ b/src/bin2cpp/SegmentGenerator.cpp @@ -23,6 +23,7 @@ *********************************************************************************/ #include "SegmentGenerator.h" +#include "TemplateProcessor.h" #include #include #include @@ -47,115 +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(getInputFilePath(), "rb"); - if (!input) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Uppercase function identifier - std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(mFunctionIdentifier); + 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 + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) + return false; - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(cpp_file_path); - std::string cppPath = cpp_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 cpp file - FILE * cpp = fopen(cppPath.c_str(), "w"); - if (!cpp) + 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(getInputFilePath()); - //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 = getManagerHeaderFilename(); - - //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", getHeaderFilename() ); - fprintf(cpp, "#include //for FILE\n"); - fprintf(cpp, "#include //for memcpy\n"); - fprintf(cpp, "namespace %s\n", mNamespace.c_str()); - fprintf(cpp, "{\n"); - fprintf(cpp, " class %s : public virtual %s::%s\n", className.c_str(), mNamespace.c_str(), mBaseClass.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 { return \"%s\"; }\n", ra::filesystem::GetFilename(getInputFilePath()).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[mChunkSize]; - while(!feof(input)) + else if ( mContext.code == CodeGenerationEnum::CODE_GENERATION_CPP ) { - //read a chunk of the file - size_t readSize = fread(buffer, 1, mChunkSize, 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(mCppEncoder) - { - case IGenerator::CPP_ENCODER_HEX: - cppEncoder = ra::code::cpp::ToHexString(buffer, readSize); - break; - case IGenerator::CPP_ENCODER_OCT: - default: - cppEncoder = ra::code::cpp::ToOctString(buffer, readSize, false); - break; - }; - - //output - fprintf(cpp, " mBuffer.append(\"%s\", %lu);\n", cppEncoder.c_str(), readSize); + str += "mBuffer.append(\""; + str += code; + str += "\", "; + str += ra::strings::ToString(buffer_size); + str += ");"; } - delete[] buffer; - buffer = NULL; - - //write cpp 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", mBaseClass.c_str(), getterFunctionName.c_str(), className.c_str()); - if (isRegisterFileEnabled()) + else if ( mContext.code == CodeGenerationEnum::CODE_GENERATION_C ) { - std::string fileManagerTemplate = getFileManagerRegistrationTemplate(); - fprintf(cpp, "%s", fileManagerTemplate.c_str()); + str += "memcpy(next, \""; + str += code; + str += "\", "; + str += ra::strings::ToString(buffer_size); + str += "); next += "; + str += ra::strings::ToString(buffer_size); + str += ";"; } - fprintf(cpp, "}; //%s\n", mNamespace.c_str()); - fclose(input); - fclose(cpp); + 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 92757db..d86f896 100644 --- a/src/bin2cpp/SegmentGenerator.h +++ b/src/bin2cpp/SegmentGenerator.h @@ -40,7 +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 old mode 100644 new mode 100755 index 72f4cb3..214609b --- a/src/bin2cpp/StringGenerator.cpp +++ b/src/bin2cpp/StringGenerator.cpp @@ -23,6 +23,7 @@ *********************************************************************************/ #include "StringGenerator.h" +#include "TemplateProcessor.h" #include #include #include @@ -47,118 +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(getInputFilePath(), "rb"); - if (!input) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Uppercase function identifier - std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(mFunctionIdentifier); - - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(cpp_file_path); - std::string cppPath = cpp_file_path; + 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; + } - //create cpp file - FILE * cpp = fopen(cppPath.c_str(), "w"); - if (!cpp) - { - fclose(input); + bool StringGenerator::createCSourceFile(const char* file_path) + { + //check if input file exists + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - } - - //determine file properties - uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(getInputFilePath()); - - //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", getHeaderFilename() ); - fprintf(cpp, "#include //for FILE\n"); - fprintf(cpp, "#include //for memcpy\n"); - fprintf(cpp, "namespace %s\n", mNamespace.c_str()); - fprintf(cpp, "{\n"); - fprintf(cpp, " class %s : public virtual %s::%s\n", className.c_str(), mNamespace.c_str(), mBaseClass.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 { return \"%s\"; }\n", ra::filesystem::GetFilename(getInputFilePath()).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[mChunkSize]; - while(!feof(input)) - { - //read a chunk of the file - size_t readSize = fread(buffer, 1, mChunkSize, input); - - bool isLastChunk = !(readSize == mChunkSize); - - if (readSize > 0) - { - if (numLinePrinted > 0) - { - //end previous line - fprintf(cpp, "\n"); - } - - //convert to cpp string - std::string cppEncoder; - switch(mCppEncoder) - { - case IGenerator::CPP_ENCODER_HEX: - cppEncoder = ra::code::cpp::ToHexString(buffer, readSize); - break; - case IGenerator::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 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", mBaseClass.c_str(), getterFunctionName.c_str(), className.c_str()); - if (isRegisterFileEnabled()) - { - std::string fileManagerTemplate = getFileManagerRegistrationTemplate(); - fprintf(cpp, "%s", fileManagerTemplate.c_str()); - } - fprintf(cpp, "}; //%s\n", mNamespace.c_str()); - fclose(input); - fclose(cpp); + 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; + } + + 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; + + 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; - return true; + std::string str; + if ( indentation ) + str += std::string(indentation, ' '); + + str += "\""; + + //convert to cpp string + switch ( mContext.cppEncoder ) + { + 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 9d84551..2947d45 100644 --- a/src/bin2cpp/StringGenerator.h +++ b/src/bin2cpp/StringGenerator.h @@ -39,7 +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 c4686f9..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,152 +52,282 @@ 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(getInputFilePath(), "rb"); - if (!input) + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) return false; - //Uppercase function identifier - std::string functionIdentifier = ra::strings::CapitalizeFirstCharacter(mFunctionIdentifier); + 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"; - //Build header and cpp file path - std::string headerPath = getHeaderFilePath(cpp_file_path); - std::string cppPath = cpp_file_path; + TemplateProcessor processor(&text); + processor.setTemplateVariableLookup(this); + bool write_success = processor.writeFile(file_path); - //create cpp file - FILE * cpp = fopen(cppPath.c_str(), "w"); - if (!cpp) - { - fclose(input); + return write_success; + } + + bool Win32ResourceGenerator::createCSourceFile(const char* file_path) + { + bool resourceFileSuccess = createResourceFile(file_path); + if ( !resourceFileSuccess ) return false; - } - //determine file properties - //uint32_t fileSize = ra::filesystem::GetFileSize(input); - std::string filename = ra::filesystem::GetFilename(getInputFilePath()); - - //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", getHeaderFilename() ); - fprintf(cpp, "#include //for FILE\n"); - fprintf(cpp, "#include \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", mNamespace.c_str()); - fprintf(cpp, "{\n"); - fprintf(cpp, " class %s : public virtual %s::%s\n", className.c_str(), mNamespace.c_str(), mBaseClass.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 { return \"%s\"; }\n", ra::filesystem::GetFilename(getInputFilePath()).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 = FindResource(hModule, \"%s\", \"CUSTOM\");\n", getRandomIdentifier(getInputFilePath()).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", mBaseClass.c_str(), getterFunctionName.c_str(), className.c_str()); - if (isRegisterFileEnabled()) - { - std::string fileManagerTemplate = getFileManagerRegistrationTemplate(); - fprintf(cpp, "%s", fileManagerTemplate.c_str()); - } - fprintf(cpp, "}; //%s\n", mNamespace.c_str()); + //check if input file exists + if ( !ra::filesystem::FileExists(mContext.inputFilePath.c_str()) ) + return false; - fclose(input); - fclose(cpp); + 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}"; - return true; + 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; - ra::strings::Replace(resourcePath, ".cpp", ".rc"); + std::string resourcePath = file_path; + switch ( mContext.code ) + { + default: + case CODE_GENERATION_CPP: + ra::strings::Replace(resourcePath, ".cpp", ".rc"); + break; + case CODE_GENERATION_C: + ra::strings::Replace(resourcePath, ".c", ".rc"); + break; + }; 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"); @@ -205,26 +336,26 @@ namespace bin2cpp return false; } - std::string filename = ra::filesystem::GetFilename(getInputFilePath()); + std::string filename = ra::filesystem::GetFilename(mContext.inputFilePath.c_str()); //write res file heading fprintf(res, "%s", getHeaderTemplate().c_str()); fprintf(res, "#include \n"); - fprintf(res, "%s CUSTOM \"%s\"\n", getRandomIdentifier(getInputFilePath()).c_str(), filename.c_str()); + fprintf(res, "%s CUSTOM \"%s\"\n", getRandomIdentifier(mContext.inputFilePath.c_str()).c_str(), filename.c_str()); fclose(res); 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; @@ -240,4 +371,25 @@ namespace bin2cpp return id; } + bool Win32ResourceGenerator::printFileContent() + { + 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); + name = ra::strings::Uppercase(name) + "_INFO"; + return name; + } + }; //bin2cpp \ No newline at end of file diff --git a/src/bin2cpp/Win32ResourceGenerator.h b/src/bin2cpp/Win32ResourceGenerator.h index d526e57..e76a96d 100644 --- a/src/bin2cpp/Win32ResourceGenerator.h +++ b/src/bin2cpp/Win32ResourceGenerator.h @@ -39,11 +39,18 @@ 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(); }; }; //bin2cpp diff --git a/src/bin2cpp/bin2cpp.samples.txt b/src/bin2cpp/bin2cpp.samples.txt index 7967f1c..9c4dd9f 100644 --- a/src/bin2cpp/bin2cpp.samples.txt +++ b/src/bin2cpp/bin2cpp.samples.txt @@ -1,11 +1,100 @@ +########################################################################################## +# C code examples: +########################################################################################## + +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 + * registerfile +--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 + +Test for namespace: +--file=..\..\test\bin2cpp_unittest\generated_files\testNamespace_C\testNamespace_C.bin --output=..\..\test\bin2cpp_unittest\generated_files\testNamespace_C --headerfile=testNamespace_C.h --identifier=testNamespace_C --managerfile=filemanager.h --override --code=c --namespace=foobar + +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" +--dir=..\..\..\samples\demo_website\www --output=..\..\temp --direxcludefilter="*.html" + +--file=..\..\test\bin2cpp_unittest\generated_files\testText1000\testText1000.bin --output=..\..\temp --override +--noheader --dir=..\..\test\bin2cpp_unittest\generated_files\testIssue56a\input_files --output=..\..\test\bin2cpp_unittest\generated_files\testIssue56a\compiled_sources --chunksize=200 --managerfile=FileManager56a.h --registerfile --namespace=issue56a --override +--plainoutput --chunksize=9999 --file=..\..\test\bin2cpp_unittest\generated_files\testSequential1000\testSequential1000.bin + + + +# old code examples: --file=.\generated_files\testText1000\testText1000.bin --output=.\generated_files\testText1000 --headerfile=_testText1000.h --identifier=testText1000 --chunksize=450 --override --file=.\generated_files\testSequential1000\testSequential1000.bin --output=.\generated_files\testSequential1000 --headerfile=_testSequential1000.h --identifier=testSequential1000 --chunksize=180 --override ---file=C:\Temp\foobar.bin --output=C:\Temp --headerfile=_testFoo.h --identifier=testFoo --override ---file=C:\Temp\foobar.bin --output=C:\Temp --headerfile=_testFoo.h --identifier=testFoo --override --noheader ---dir=D:\Temp\foobar --output=C:\Temp\foobar --override –noheader --file=..\..\test\bin2cpp_unittest\generated_files\testIssue28\testIssue28.bin --output=..\..\test\bin2cpp_unittest\generated_files\testIssue28 --headerfile=_testIssue28.h --identifier=testIssue28 --managerfile=FileManager.h --override --file=..\..\test\bin2cpp_unittest\generated_files\testIssue28\testIssue28.bin --output=..\..\test\bin2cpp_unittest\generated_files\testIssue28 --headerfile=_testIssue28.h --identifier=testIssue28 --managerfile=FileManager.h --override --file=..\..\test\bin2cpp_unittest\generated_files\testSequential1000\testSequential1000.bin --headerfile="generated/foo-data.h" --output=. --identifier=TestLongPath --file=..\..\test\bin2cpp_unittest\generated_files\testIssue28\testIssue28.bin --headerfile="generated/foo-data.h" --output=. --identifier=TestLongPath --managerfile=generated/foo-manager47.h --registerfile --namespace=myspace47 --file=..\..\test\bin2cpp_unittest\generated_files\testIssue47\testIssue47.bin --output=..\..\test\bin2cpp_unittest\generated_files\testIssue47 --headerfile=generated/_testIssue47.h --identifier=testIssue47 --managerfile=generated/FileManager47.h --registerfile --namespace=myspace47 --override --file=..\..\test\bin2cpp_unittest\generated_files\testIssue50\testIssue50.bin --output=..\..\test\bin2cpp_unittest\generated_files\testIssue50 --headerfile=_testIssue50.h --identifier=testIssue50 --managerfile=FileManager50.h --registerfile --namespace=myspace50 --override + +--file=..\..\test\bin2cpp_unittest\generated_files\testSequential1000\testSequential1000.bin --headerfile="generated/foo-data.h" --output=. --identifier=TestLongPath --managerfile=generated/foo-manager47.h --registerfile --namespace=myspace47 + +--dir=D:\Temp\issue56\css --output=D:\Temp\issue56\output +--dir=..\..\test\bin2cpp_unittest\generated_files\testIssue56a\input_files --output=..\..\test\bin2cpp_unittest\generated_files\testIssue56a\compiled_sources +--dir=..\..\test\bin2cpp_unittest\generated_files\testIssue56b\input_files\www --output=..\..\test\bin2cpp_unittest\generated_files\testIssue56b\generated_sources --namespace=issue56b --override +--dir=..\..\test\bin2cpp_unittest\generated_files\testKeepDirectories\input_files\www --output=..\..\test\bin2cpp_unittest\generated_files\testKeepDirectories\generated_sources --override --keepdirs + +--file=D:\Temp\bin2cpp\issue51\input_files\IMG_0001.jpg --output=D:\Temp\bin2cpp\issue51\generated_sources --headerfile="IMG_0001.h" --identifier=testIssue51 --namespace=testIssue51 --managerfile=FileManager51.h --override --reportedfilepath=foo\bar\IMG_0001.h +--dir=D:\Temp\bin2cpp\testIssue56b\input_files\www --output=D:\Temp\bin2cpp\testIssue56b\generated_sources --namespace=testIssue51 --managerfile=FileManager51.h --override + +--file=..\..\test\bin2cpp_unittest\generated_files\testSequential1000\testSequential1000.bin --plainoutput --chunksize=50 +--managerfile=MyManager.h --output=generated_files --override diff --git a/src/bin2cpp/common.cpp b/src/bin2cpp/common.cpp index d7ac142..eb4300e 100755 --- a/src/bin2cpp/common.cpp +++ b/src/bin2cpp/common.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "rapidassist/strings.h" #include "rapidassist/filesystem.h" @@ -40,6 +41,59 @@ namespace bin2cpp return BIN2CPP_VERSION; } + const char* getErrorCodeDescription(const APP_ERROR_CODES& error_code) + { + switch ( error_code ) + { + case APP_ERROR_SUCCESS: + return "Success"; + break; + case APP_ERROR_MISSINGARGUMENTS: + return "Missing arguments"; + break; + case APP_ERROR_INPUTFILENOTFOUND: + return "Unable to open input file"; + break; + case APP_ERROR_UNABLETOCREATEOUTPUTFILES: + return "Unable to create output files"; + break; + case APP_ERROR_TOOMANYARGUMENTS: + return "Too many arguments"; + break; + case APP_ERROR_INPUTDIRNOTFOUND: + return "Input directory not found"; + break; + case AAP_ERROR_NOTSUPPORTED: + return "Operation not supported"; + break; + case APP_ERROR_OPERATIONHASFAILED: + return "Operation has failed"; + break; + case APP_ERROR_INVALIDVALUE: + return "Invalid value"; + break; + default: + return "Unknown error"; + }; + } + + const char* getUpdateModeText(const FILE_UPDATE_MODE& mode) + { + switch ( mode ) + { + case WRITING: + return "Writing"; + case UPDATING: + return "Updating"; + case OVERWRITING: + return "Overwriting"; + case SKIPPING: + return "Skipping"; + default: + return "Unknown"; + }; + } + uint64_t getOutputFileModifiedDate(const std::string & path) { uint64_t mod_time = 0; @@ -93,7 +147,23 @@ namespace bin2cpp return false; } - std::string getCppIncludeGuardMacroName(const std::string & path) + bool isCHeaderFile(const std::string & path) + { + std::string extension = ra::strings::Uppercase(ra::filesystem::GetFileExtention(path)); + if (extension == "H") + return true; + return false; + } + + bool isCSourceFile(const std::string & path) + { + std::string extension = ra::strings::Uppercase(ra::filesystem::GetFileExtention(path)); + if (extension == "C") + return true; + return false; + } + + std::string getIncludeGuardMacroName(const std::string & path) { static const std::string EMPTY_STRING; if (path.empty()) @@ -134,5 +204,261 @@ namespace bin2cpp return filename; } + std::string filter(std::string str, const std::string & valid_characters) + { + std::string output; + + //reserve as many characters as in input string + output.reserve(str.size()); + + //for each characters in input string + for(size_t i=0; i < str.size(); i++) + { + //is the current character is found in valid characters? + size_t pos = valid_characters.find(str[i], 0); + if (pos != std::string::npos) + output.append(1, str[i]); + } + + return output; + } + + std::string getFunctionIdentifierFromPath(const std::string & path) + { + std::string id; + + //build default id + std::string name = ra::filesystem::GetFilenameWithoutExtension(path.c_str()); + std::string ext = ra::filesystem::GetFileExtention(path.c_str()); + name = ra::strings::CapitalizeFirstCharacter(name); + ext = ra::strings::CapitalizeFirstCharacter(ext ); + id = name + ext; + + //filter out characters which are not alphanumeric characters or '_'. + static const std::string validCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; + id = filter(id, validCharacters); + + return id; + } + + std::string getUniqueFunctionIdentifierFromPath(const std::string & path, Dictionary & dict) + { + std::string id = getFunctionIdentifierFromPath(path); + + //find an unused identifier + bool exists = dict.find(id) != dict.end(); + if (exists) { + std::string base_id = id + "_"; + + //increase a counter until an identifier does not already exists + size_t counter = 0; + while(exists) { + //duplicate id + + //increase counter and generate a new id + counter++; + id = base_id + ra::strings::ToString(counter); + + //check again + exists = dict.find(id) != dict.end(); + } + } + + //this identifier is not already used. + //register this identifier in the dictionary. + dict.insert(id); + + return id; + } + + std::string getUniqueFilePath(const std::string & base_path, Dictionary & dict) + { + std::string dir; + std::string file_name; + std::string file_ext; + pathSplit(base_path, dir, file_name, file_ext); + + std::string next_path = base_path; + + //find an unused identifier + bool exists = dict.find(base_path) != dict.end(); + if (exists) { + + //increase a counter until an identifier does not already exists + size_t counter = 0; + while(exists) { + //duplicate id + + //increase counter and generate a new path + counter++; + std::string next_file_name = file_name + "_" + ra::strings::ToString(counter); + next_path = pathJoin(dir, next_file_name, file_ext); + + //check again + exists = dict.find(next_path) != dict.end(); + } + } + + //this identifier is not already used. + //register this identifier in the dictionary. + dict.insert(next_path); + + return next_path; + } + +#ifdef _WIN32 + inline bool isDriveLetter(char c) + { + if ( (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') ) + { + return true; + } + return false; + } +#endif + + void pathSplit(const std::string & path, std::string & directory, std::string & file_name, std::string & file_extension) + { + std::string tmp = path; + + directory = ra::filesystem::GetParentPath(tmp); + if (!directory.empty()) + tmp.erase(0, directory.size() + 1); // +1 to erase the last \ character + +#ifdef _WIN32 + //test special case for root directories + //convert C: to C:\ + if (directory.size() == 2 && directory[1] == ':') + { + if (isDriveLetter(directory[0])) + { + directory += "\\"; + } + } +#else + //test for root directory + if (directory.empty() && !path.empty() && path[0] == '/') + directory = "/"; +#endif + + file_name = ra::filesystem::GetFilenameWithoutExtension(tmp.c_str()); + file_extension = ra::filesystem::GetFileExtention(tmp); + } + + std::string pathJoin(const std::string & directory, const std::string & file_name, const std::string & file_extension) + { + std::string tmp; + + if (!directory.empty()) + { + tmp += directory; + tmp += ra::filesystem::GetPathSeparatorStr(); + +#ifdef _WIN32 + //special case for root directories + if (directory.size() == 3 && directory[1] == ':' && directory[2] == '\\' && isDriveLetter(directory[0])) + { + tmp.erase(2, 1); + } +#else + //special case for root directory + if (directory == "/") + tmp.erase(0, 1); +#endif + } + + if (!file_name.empty()) + { + tmp += file_name; + } + + if (!file_extension.empty()) + { + tmp += "."; + tmp += file_extension; + } + else + { + //no file extension + if (file_name.find('.') != std::string::npos) + { + // this file has a dot in file name + // we must add a dot at the end of the file name to make the distinction. + tmp += "."; + } + } + + return tmp; + } + + void strSplit(const std::string& value, char separator, std::vector& values) + { + values.clear(); + size_t start = 0; + size_t end = std::string::npos; + size_t length = 0; + + // find first separator + end = value.find(separator, start); + while ( end != std::string::npos ) + { + length = end - start; + std::string item = value.substr(start, length); + values.push_back(item); + + // find next separator + start = end + 1; + end = value.find(separator, start); + } + + // Capture last token + values.push_back(value.substr(start)); + } + + std::string strJoin(const std::vector& values, char separator) + { + std::string output; + + for ( size_t i = 0; i < values.size(); i++ ) + { + const std::string& element = values[i]; + output += element; + + bool is_last = (i == (values.size() - 1)); + if ( !is_last ) + output.append(1, separator); + } + + return output; + } + + CodeGenerationEnum parseCode(const std::string& value) + { + std::string value_upper = ra::strings::Uppercase(value); + if ( value_upper == "C" ) + return CodeGenerationEnum::CODE_GENERATION_C; + if ( value_upper == "CPP" || value_upper == "C++" ) + return CodeGenerationEnum::CODE_GENERATION_CPP; + return CodeGenerationEnum::CODE_GENERATION_UNKNOW; + } + + const std::string& getDefaultCodeSourceFileExtension(CodeGenerationEnum code) + { + static const std::string EMPTY = ""; + static const std::string CPP = "cpp"; + static const std::string C = "c"; + switch ( code ) + { + case CODE_GENERATION_UNKNOW: + return EMPTY; + case CODE_GENERATION_CPP: + return CPP; + case CODE_GENERATION_C: + return C; + default: + return EMPTY; + }; + } }; //bin2cpp diff --git a/src/bin2cpp/common.h b/src/bin2cpp/common.h index d315c82..096ddae 100644 --- a/src/bin2cpp/common.h +++ b/src/bin2cpp/common.h @@ -28,15 +28,34 @@ #include #include #include +#include +#include + +#include "types.h" +#include "enums.h" namespace bin2cpp { - /* - Description: - Returns the application version number. - */ + + /// + ///Returns the application version number. + /// const char * getVersionString(); + /// + ///Get the desription of the given application error code. + /// + ///The error code. + ///Returns a string description of the given error code. Returns 'Unknown error' for unknown codes. + const char* getErrorCodeDescription(const APP_ERROR_CODES& error_code); + + /// + ///Get the desription of the given file update mode. + /// + ///The file update mode. + ///Returns a string description of the given file update mode. Returns 'Unknown' for unknown modes. + const char* getUpdateModeText(const FILE_UPDATE_MODE& mode); + /// ///Returns the modified date from an embedded file's c++ header/source file. ///Note that the function returns the number of seconds elapsed since epoch since Jan 1st 1970. @@ -59,13 +78,112 @@ namespace bin2cpp ///Returns true if path is a c++ source file. Returns false otherwise. bool isCppSourceFile(const std::string & path); + /// + ///Determine if a given path is a C header file. + /// + ///An valid file path. + ///Returns true if path is a C header file. Returns false otherwise. + bool isCHeaderFile(const std::string & path); + + /// + ///Determine if a given path is a C source file. + /// + ///An valid file path. + ///Returns true if path is a C source file. Returns false otherwise. + bool isCSourceFile(const std::string & path); + /// ///Determine the appropriate macro name for the include guard of the given c++ header file. ///See also https://en.wikipedia.org/wiki/Include_guard /// ///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. + /// + ///The input string to filter. + ///The list of allowed characters. + ///Returns a string matching the content of `str` where the characters that are not in `valid_characters` are removed. + std::string filter(std::string str, const std::string & valid_characters); + + /// + ///Build a valid function identifier based on the path of a given file. + ///For example, given the file `c:\temp\www\static\css\theme.dark.css`, the returned string can be something like `themedarkcss`. + /// + ///The path of a file. + ///Returns a valid function identifier from a file path. + std::string getFunctionIdentifierFromPath(const std::string & path); + + /// + ///Build a unique function identifier based on the path of a given file. + ///The function is based on `getFunctionIdentifierFromPath()`. + ///A dictionary is used to keep track of existing function identifier. + ///If an identifier is already existing in the dictionary, "_[counter]" is added at the end of the identifier. + /// + ///The path of a file. + ///A dictionary that contains the existing function identifier. + ///Returns a unique function identifier from a file path. + std::string getUniqueFunctionIdentifierFromPath(const std::string & path, Dictionary & dict); + + /// + ///Build a unique file path based on the path of a given file. + ///A dictionary is used to keep track of existing file paths. + ///If a file is already existing in the dictionary, "_[counter]" is added at the end of the filename. + /// + ///The path of a file. + ///A dictionary that contains the existing file paths. + ///Returns a unique file path from the path of a given file. + std::string getUniqueFilePath(const std::string & path, Dictionary & dict); + + /// + ///Split a path into individual components: directory, file name, file extension. + /// + ///The path to split. + ///The dictionary of the given path. + ///The file name (without the extension) of the given path. + ///The file extension of the given path. + void pathSplit(const std::string & path, std::string & directory, std::string & file_name, std::string & file_extension); + + /// + ///Join individual components of a path into a full path. + /// + ///The dictionary of the path to join. + ///The file name (without the extension) of the path to join. + ///The file extension of the path to join. + ///Returns the path matching all given components. + std::string pathJoin(const std::string & directory, const std::string & file_name, const std::string & file_extension); + + /// + ///Split a string into a list of values based on a specified separator character. + /// + ///The input string that contains values to split. + ///The character that separate the values in the string. + ///The output individual values in the input string. + void strSplit(const std::string & value, char separator, std::vector & values); + + /// + ///"Combine a list of values into a single string, using a specified separator character. + /// + ///The list of values to join to a single string. + ///The character that separate the values in the string. + ///Returns the combined string. + std::string strJoin(const std::vector& values, char separator); + + /// + ///Parse a CodeGenerationEnum from a string. + /// + ///The string value representing of the code language. + ///Returns a valid CodeGenerationEnum value. Returns CODE_GENERATION_UNKNOW on parsing error. + CodeGenerationEnum parseCode(const std::string& value); + + /// + ///Get the default source file extension for the given CodeGenerationEnum. + /// + ///The code generation language. + ///Returns a valid file extension valu that matches the given code. Returns an empty string otherwise. + const std::string & getDefaultCodeSourceFileExtension(CodeGenerationEnum code); }; //bin2cpp diff --git a/src/bin2cpp/enums.h b/src/bin2cpp/enums.h new file mode 100644 index 0000000..eb9bdca --- /dev/null +++ b/src/bin2cpp/enums.h @@ -0,0 +1,79 @@ +/********************************************************************************** + * 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 ENUMS_H +#define ENUMS_H + +namespace bin2cpp +{ + + /// + ///Error codes returned by the application + /// + enum APP_ERROR_CODES + { + APP_ERROR_SUCCESS = 0, + APP_ERROR_MISSINGARGUMENTS, + APP_ERROR_INPUTFILENOTFOUND, + APP_ERROR_UNABLETOCREATEOUTPUTFILES, + APP_ERROR_TOOMANYARGUMENTS, + APP_ERROR_INPUTDIRNOTFOUND, + AAP_ERROR_NOTSUPPORTED, + APP_ERROR_OPERATIONHASFAILED, + APP_ERROR_INVALIDVALUE, + }; + + /// + ///File update modes. + /// + enum FILE_UPDATE_MODE + { + WRITING, + UPDATING, + OVERWRITING, + SKIPPING, + }; + + /// + ///Defines the different types of cpp encoding. + /// + enum CppEncoderEnum + { + CPP_ENCODER_OCT, + CPP_ENCODER_HEX, + }; + + /// + ///Defines the different types of programming language code output. + /// + enum CodeGenerationEnum + { + CODE_GENERATION_UNKNOW, + CODE_GENERATION_CPP, + CODE_GENERATION_C, + }; + +}; //bin2cpp + +#endif //ENUMS_H diff --git a/src/bin2cpp/main.cpp b/src/bin2cpp/main.cpp index 8f9f3bd..0ef661e 100755 --- a/src/bin2cpp/main.cpp +++ b/src/bin2cpp/main.cpp @@ -29,6 +29,10 @@ #include "StringGenerator.h" #include "ArrayGenerator.h" #include "Win32ResourceGenerator.h" +#include "ManagerGenerator.h" +#include "Context.h" +#include "INameProvider.h" +#include "LegacyNameProvider.h" #include #include @@ -41,110 +45,24 @@ #include "rapidassist/process.h" #include "rapidassist/timing.h" +#include "enums.h" #include "common.h" +#include "wildcard.h" using namespace bin2cpp; -enum APP_ERROR_CODES -{ - APP_ERROR_SUCCESS = 0, - APP_ERROR_MISSINGARGUMENTS, - APP_ERROR_INPUTFILENOTFOUND, - APP_ERROR_UNABLETOCREATEOUTPUTFILES, - APP_ERROR_TOOMANYARGUMENTS, - APP_ERROR_INPUTDIRNOTFOUND -}; - -enum FILE_UPDATE_MODE -{ - WRITING, - UPDATING, - OVERWRITING, - SKIPPING, -}; - //default values static const size_t DEFAULT_CHUNK_SIZE = 200; -static const char * DEFAULT_NAMESPACE = "bin2cpp"; -static const char * DEFAULT_BASECLASSNAME = "File"; -static const IGenerator::CppEncoderEnum DEFAULT_ENCODING = IGenerator::CPP_ENCODER_OCT; - -const char * getErrorCodeDescription(const APP_ERROR_CODES & error_code) -{ - switch(error_code) - { - case APP_ERROR_SUCCESS: - return "Success"; - break; - case APP_ERROR_MISSINGARGUMENTS: - return "Missing arguments"; - break; - case APP_ERROR_INPUTFILENOTFOUND: - return "Unable to open input file"; - break; - case APP_ERROR_UNABLETOCREATEOUTPUTFILES: - return "Unable to create output files"; - break; - case APP_ERROR_TOOMANYARGUMENTS: - return "Too many arguments"; - break; - case APP_ERROR_INPUTDIRNOTFOUND: - return "Input directory not found"; - break; - default: - return "Unknown error"; - }; -} - -const char * getUpdateModeText(const FILE_UPDATE_MODE & mode) -{ - switch(mode) - { - case WRITING: - return "Writing"; - case UPDATING: - return "Updating"; - case OVERWRITING: - return "Overwriting"; - case SKIPPING: - return "Skipping"; - default: - return "Unknown"; - }; -} - -inline std::string filter(std::string str, const std::string & valid_characters) -{ - std::string output; - - //reserve as many characters as in input string - output.reserve(str.size()); - - //for each characters in input string - for(size_t i=0; i < str.size(); i++) - { - //is the current character is found in valid characters? - size_t pos = valid_characters.find(str[i], 0); - if (pos != std::string::npos) - output.append(1, str[i]); - } - - return output; -} - -std::string getFunctionIdentifierFromPath(const std::string & path) -{ - std::string id; - - //get filename of the given path - id = ra::filesystem::GetFilenameWithoutExtension(path.c_str()); - - // filter out characters which are not alphanumeric characters or '_'. - static const std::string validCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; - id = filter(id, validCharacters); - - return id; -} +static const char * DEFAULT_NAMESPACE_CPP = "bin2cpp"; +static const char * DEFAULT_NAMESPACE_C = "bin2c"; +static const char * DEFAULT_BASECLASS_NAME_CPP = "File"; +static const char * DEFAULT_BASECLASS_NAME_C = "Bin2cFile"; +static const CppEncoderEnum DEFAULT_ENCODING = CPP_ENCODER_OCT; +static const CodeGenerationEnum DEFAULT_CODE_GENERATION = CODE_GENERATION_CPP; +static Dictionary identifiers_dictionary; // unique values for identifiers +static Dictionary output_files_dictionary; // unique values for output file names +#define DIRECTORY_FILTER_SEPARATOR_STR ":" +static const char DIRECTORY_FILTER_SEPARATOR = DIRECTORY_FILTER_SEPARATOR_STR[0]; struct ARGUMENTS { @@ -152,30 +70,15 @@ struct ARGUMENTS bool noheader; bool quiet; bool version; - bool hasFile; // true if 'inputFilePath' is set. - bool hasDir; // true if 'inputDirPath' is set. - bool hasManagerFile; // true if 'managerHeaderFilename' is set. - std::string inputFilePath; // path of the input binary file - std::string inputDirPath; - std::string outputDirPath; - std::string headerFilename; - std::string functionIdentifier; - size_t chunkSize; - bool overrideExisting; - std::string codeNamespace; - std::string baseClass; - std::string managerHeaderFilename; - bool registerfile; - IGenerator::CppEncoderEnum encoding; std::string generatorName; }; //pre-declarations -bool generateFile(const ARGUMENTS & args, const std::string & output_file_path, bin2cpp::IGenerator * generator); -bool generateManagerFile(const ARGUMENTS & args, const std::string & output_file_path, bin2cpp::IGenerator * generator); -APP_ERROR_CODES processInputFile(const ARGUMENTS & args, bin2cpp::IGenerator * generator); -APP_ERROR_CODES processInputDirectory(const ARGUMENTS & args, bin2cpp::IGenerator * generator); -APP_ERROR_CODES processManagerFiles(const ARGUMENTS & args, bin2cpp::IGenerator * generator); +bool generateOutputFile(const Context & c, const std::string & output_file_path, bin2cpp::IGenerator * generator); +APP_ERROR_CODES processInputFile(const Context & c, bin2cpp::IGenerator * generator); +APP_ERROR_CODES processInputDirectory(const Context & c, bin2cpp::INameProvider* nameProvider, bin2cpp::IGenerator * generator); +APP_ERROR_CODES processManagerFiles(const Context & c); +APP_ERROR_CODES processPlainOutput(const Context & c, bin2cpp::IGenerator * generator); void printHeader() { @@ -186,38 +89,71 @@ void printHeader() void printUsage() { +#ifdef _WIN32 +#define SEPARATOR "\\" +#else +#define SEPARATOR "/" +#endif + //usage string in docopt format. See http://docopt.org/ - static const char usage[] = + static const char usage[] = "Usage:\n" - " bin2cpp --file= --output= --headerfile= --identifier= [--generator=] [--encoding=] [--chunksize=] [--namespace=] [--baseclass=] [--managerfile=] [--registerfile] [--override] [--noheader] [--quiet]\n" + " bin2cpp --file= --output= [--headerfile=] [--identifier=] [--generator=] [--encoding=] [--chunksize=] [--namespace=] [--baseclass=] [--managerfile=] [--registerfile] [--reportedfilepath=] [--override] [--noheader] [--quiet]\n" + " bin2cpp --dir= --output= [--keepdirs] [--generator=] [--encoding=] [--chunksize=] [--namespace=] [--baseclass=] [--managerfile=] [--registerfile] [--dirincludefilter=] [--direxcludefilter=] [--override] [--noheader] [--quiet]\n" " bin2cpp --help\n" " bin2cpp --version\n" "\n" "Options:\n" - " --help Display this help message.\n" - " --version Display this application version.\n" - " --file= Path of the input file used for embedding as C++ source code.\n" - " --dir= Path of the input directory used for embedding all files of the directory as C++ source code.\n" - " When specified, the parameters 'headerfile' and 'identifier' are automatically calculated and cannot be manually specified.\n" - #ifdef _WIN32 - " --output= Output folder where to create generated code. ie: .\\generated_files\n" - #else - " --output= Output folder where to create generated code. ie: ./generated_files\n" - #endif - " --headerfile= File name of the generated C++ Header file. ie: SplashScreen.h\n" - " --generator= Name of the generator to use. Possible values are 'segment', 'string', 'array' and 'win32'. [default: segment].\n" - " --encoding= Name of the binary to string literal encoding to use. Possible values are 'oct' and 'hex'. [default: oct].\n" - " --identifier= Identifier of the function name that is used to get an instance of the file. ie: SplashScreen\n" - " --chunksize= Size in bytes of each string segments (bytes per row). [default: 200].\n" - " --baseclass= The name of the interface for embedded files. [default: File].\n" - " --namespace= The namespace of the generated source code [default: bin2cpp].\n" - " --managerfile= File name of the generated C++ header file for the FileManager class. ie: FileManager.h\n" - " --registerfile Register the generated file to the FileManager class. [default: false].\n" - " This flags is automatically set when parameter 'managerfile' is specified.\n" - " --override Tells bin2cpp to overwrite the destination files.\n" - " --noheader Do not print program header to standard output.\n" - " --quiet Do not log any message to standard output.\n" - "\n"; + " --help Display this help message.\n" + " --version Display this application version.\n" + " --file= Path of the input file used for embedding as C++ source code.\n" + " --dir= Path of the input directory used for embedding all files of the directory as C++ source code.\n" + " --output= Path of the output directory where to create generated code. ie: ." SEPARATOR "generated_files\n" + " --headerfile= File name or relative path of the generated C++ header file. If a relative path from the output directory is specified,\n" + " the #include statement in the generated cpp file will match the relative path. ie: SplashScreen.h\n" + " Default value: input file name (without extension)\n" + " --identifier= Identifier of the function name that is used to get an instance of the file. ie: SplashScreen\n" + " Default value is based on input file with format 'NameExt'.\n" + " --generator= Name of the generator to use. Possible values are 'segment', 'string', 'array' and 'win32'. [default: segment]\n" + " --encoding= Name of the binary to string literal encoding to use. Possible values are 'oct' and 'hex'. [default: oct]\n" + " --chunksize= Size in bytes of each string segments (bytes per LoC). [default: 200]\n" + " --baseclass= The name of the interface for embedded files. [default: File]\n" + " For C generated code, this parameter is for naming the File structure. [default: Bin2cFile]\n" + " --namespace= The namespace of the generated source code. [default: bin2cpp]\n" + " For C generated code, this parameter is for setting the prefix of all function names. [default: bin2c]\n" + " --reportedfilepath= The relative reported path of the File. Path returned when calling method getFilePath() of the File class. ie: images" SEPARATOR "DCIM" SEPARATOR "IMG_0001.jpg.\n" + " Automatically calculated when --dir mode is used.\n" + " --managerfile= File name or relative path of the generated C++ header file for the FileManager class. ie: FileManager.h\n" + " --registerfile Register the generated file to the FileManager class.\n" + " This flags is automatically set when parameter 'managerfile' is specified.\n" + " --dirincludefilter= Set a positive filter on the input directory to only select files matching the filter. Wildcard characters are accepted.\n" + " Separate each filter with the character '" DIRECTORY_FILTER_SEPARATOR_STR "'. Valid only when --dir is used. See wildcard characters definition below.\n" + " --direxcludefilter= Set a negative filter on the input directory to skip files matching the filter. Wildcard characters are accepted.\n" + " Separate each filter with the character '" DIRECTORY_FILTER_SEPARATOR_STR "'. Valid only when --dir is used. See wildcard characters definition below.\n" + " The exclude filter has precedence over the include filter.\n" + " --keepdirs Keep the directory structure. Forces the output files to have the same\n" + " directory structure as the input files. Valid only when --dir is used.\n" + " --plainoutput Print the encoded string in plain format to stdout. Useful for scripts and integration with third party application.\n" + " --code Define the programming language output for code generation. Supported values are 'c', 'cpp', 'c++'.\n" + " --override Tells bin2cpp to overwrite the destination files.\n" + " --noheader Do not print program header to standard output.\n" + " --quiet Do not log any message to standard output.\n" + "\n" + " Wildcard characters:\n" + " '?' Matches any single character.\n" + " '*' Matches zero or more characters.\n" + " '#' Matches exactly one numeric digit (0-9).\n" + " [charlist] Matches any single character inside the brackets.\n" + " [a-z] Matches any single lowercase letter between 'a' and 'z'.\n" + " [A-Z] Matches any single uppercase letter between 'A' and 'A'.\n" + " [0-9] Matches any single digit between '0' and '9'.\n" + " [a-zA-Z0-9] Matches any single letter (uppercase or lowercase) or digit.\n" + "\n" + " For example:\n" + " 'ker*##.\?\?\?' would match files that starts with 'ker', and ends with 2 digits, a dot and then 3 characters.\n" + " --dir-include-filter=\"*.jpg:*.png\" would include all files whose file extension is 'jpg' or 'png'.\n" + " --dir-exclude-filter=\"*.bak\" would exclude all backup files.\n" + " --dir-include-filter=\"*.log\" --dir-exclude-filter=\"debug.log\" would include all log files but not the one named 'debug.log'.\n"; printf("%s", usage); } @@ -228,13 +164,10 @@ int main(int argc, char* argv[]) args.noheader = false; args.quiet = false; args.version = false; - args.hasFile = false; - args.hasDir = false; - args.hasManagerFile = false; - args.chunkSize = 0; - args.overrideExisting = false; - args.registerfile = false; + Context c; + LegacyNameProvider legacyNameProvider; + INameProvider& nameProvider = legacyNameProvider; std::string dummy; //help @@ -252,6 +185,14 @@ int main(int argc, char* argv[]) //quiet args.quiet = ra::cli::ParseArgument("quiet", dummy, argc, argv); + //force quiet and noheader if plain output + c.plainOutput = ra::cli::ParseArgument("plainoutput", dummy, argc, argv); + if ( c.plainOutput ) + { + args.quiet = true; + args.noheader = true; + } + //force noheader if quiet if (args.quiet) args.noheader = true; @@ -271,18 +212,20 @@ int main(int argc, char* argv[]) printHeader(); //mandatory arguments - args.hasFile = ra::cli::ParseArgument("file", args.inputFilePath, argc, argv); - args.hasDir = ra::cli::ParseArgument("dir", args.inputDirPath, argc, argv); - args.hasManagerFile = ra::cli::ParseArgument("managerfile", args.managerHeaderFilename, argc, argv); - if (!args.hasFile && !args.hasDir && !args.hasManagerFile) + c.hasInputFile = ra::cli::ParseArgument("file", c.inputFilePath, argc, argv); + c.hasInputDir = ra::cli::ParseArgument("dir", c.inputDirPath, argc, argv); + c.hasManagerFile = ra::cli::ParseArgument("managerfile", c.managerHeaderFilename, argc, argv); + + //if no mandatory args is specified + if (!c.hasInputFile && !c.hasInputDir && !c.hasManagerFile && !c.plainOutput) { - //file, dir or managerfile must be specified + //file, dir, managerfile or plainoutput must be specified APP_ERROR_CODES error = APP_ERROR_MISSINGARGUMENTS; - ra::logging::Log(ra::logging::LOG_ERROR, "%s (file, dir, managerfile)", getErrorCodeDescription(error)); + ra::logging::Log(ra::logging::LOG_ERROR, "%s (file, dir, managerfile, plainoutput)", getErrorCodeDescription(error)); printUsage(); return error; } - else if (args.hasFile && args.hasDir) + else if (c.hasInputFile && c.hasInputDir) { //file OR dir must be specified, not both APP_ERROR_CODES error = APP_ERROR_TOOMANYARGUMENTS; @@ -291,39 +234,36 @@ int main(int argc, char* argv[]) return error; } - if (!ra::cli::ParseArgument("output", args.outputDirPath, argc, argv)) - { - APP_ERROR_CODES error = APP_ERROR_MISSINGARGUMENTS; - ra::logging::Log(ra::logging::LOG_ERROR, "%s (output)", getErrorCodeDescription(error)); - printUsage(); - return error; - } - - if (args.hasDir) + //if output args is mandatory + if (c.hasInputDir || (c.hasInputFile && !c.plainOutput) || c.hasManagerFile) { - if (ra::cli::ParseArgument("headerfile", args.headerFilename, argc, argv)) + c.hasOutputDir = ra::cli::ParseArgument("output", c.outputDirPath, argc, argv); + if (!c.hasOutputDir ) { - //headerfile not supported with dir argument - APP_ERROR_CODES error = APP_ERROR_TOOMANYARGUMENTS; - ra::logging::Log(ra::logging::LOG_ERROR, "%s (headerfile)", getErrorCodeDescription(error)); + APP_ERROR_CODES error = APP_ERROR_MISSINGARGUMENTS; + ra::logging::Log(ra::logging::LOG_ERROR, "%s (output)", getErrorCodeDescription(error)); printUsage(); return error; } } - else if (args.hasFile) + + // if headerfile should not be specified + if (c.hasInputDir) { - if (!ra::cli::ParseArgument("headerfile", args.headerFilename, argc, argv)) + if (ra::cli::ParseArgument("headerfile", c.headerFilename, argc, argv)) { - APP_ERROR_CODES error = APP_ERROR_MISSINGARGUMENTS; + //headerfile not supported with dir argument + APP_ERROR_CODES error = APP_ERROR_TOOMANYARGUMENTS; ra::logging::Log(ra::logging::LOG_ERROR, "%s (headerfile)", getErrorCodeDescription(error)); printUsage(); return error; } } - if (args.hasDir) + // if identifier should not be specified + if (c.hasInputDir) { - if (ra::cli::ParseArgument("identifier", args.functionIdentifier, argc, argv)) + if (ra::cli::ParseArgument("identifier", c.functionIdentifier, argc, argv)) { //identifier not supported with dir argument APP_ERROR_CODES error = APP_ERROR_TOOMANYARGUMENTS; @@ -332,56 +272,127 @@ int main(int argc, char* argv[]) return error; } } - else if (args.hasFile) + + //optional arguments + + std::string codeStr; + if ( ra::cli::ParseArgument("code", codeStr, argc, argv) ) { - if (!ra::cli::ParseArgument("identifier", args.functionIdentifier, argc, argv)) + CodeGenerationEnum codeTmp = parseCode(codeStr); + if ( codeTmp == CodeGenerationEnum::CODE_GENERATION_UNKNOW ) { - APP_ERROR_CODES error = APP_ERROR_MISSINGARGUMENTS; - ra::logging::Log(ra::logging::LOG_ERROR, "%s (identifier)", getErrorCodeDescription(error)); + APP_ERROR_CODES error = APP_ERROR_INVALIDVALUE; + ra::logging::Log(ra::logging::LOG_ERROR, "%s (code)", getErrorCodeDescription(error)); printUsage(); return error; } + + c.code = codeTmp; + } + else + { + c.code = DEFAULT_CODE_GENERATION; } - //optional arguments + if (c.hasInputFile) + { + //identifier + if (!ra::cli::ParseArgument("identifier", c.functionIdentifier, argc, argv)) + { + //identifier is not manually specified. + c.functionIdentifier = nameProvider.getDefaultFunctionIdentifier(c.inputFilePath, identifiers_dictionary); + } + + //headerfile + if (!ra::cli::ParseArgument("headerfile", c.headerFilename, argc, argv)) + { + //use the file name without extension as 'headerfile'. + c.headerFilename = nameProvider.getDefaultHeaderFile(c.inputFilePath); + } + } size_t tmpChunkSize = 0; - args.chunkSize = DEFAULT_CHUNK_SIZE; + c.chunkSize = DEFAULT_CHUNK_SIZE; if (ra::cli::ParseArgument("chunksize", tmpChunkSize, argc, argv)) { - args.chunkSize = tmpChunkSize; + c.chunkSize = tmpChunkSize; } - args.overrideExisting = ra::cli::ParseArgument("override", dummy, argc, argv); + c.overrideExistingFiles = ra::cli::ParseArgument("override", dummy, argc, argv); - if (!ra::cli::ParseArgument("namespace", args.codeNamespace, argc, argv)) + if (!ra::cli::ParseArgument("namespace", c.codeNamespace, argc, argv)) { - args.codeNamespace = DEFAULT_NAMESPACE; + switch ( c.code ) + { + default: + case CODE_GENERATION_CPP: + c.codeNamespace = DEFAULT_NAMESPACE_CPP; + break; + case CODE_GENERATION_C: + c.codeNamespace = DEFAULT_NAMESPACE_C; + break; + }; + } - if (!ra::cli::ParseArgument("baseclass", args.baseClass, argc, argv)) + if (!ra::cli::ParseArgument("baseclass", c.baseClass, argc, argv)) { - args.baseClass = DEFAULT_BASECLASSNAME; + switch ( c.code ) + { + default: + case CODE_GENERATION_CPP: + c.baseClass = DEFAULT_BASECLASS_NAME_CPP; + break; + case CODE_GENERATION_C: + c.baseClass = DEFAULT_BASECLASS_NAME_C; + break; + }; } - args.registerfile = ra::cli::ParseArgument("registerfile", dummy, argc, argv); + c.registerFiles = ra::cli::ParseArgument("registerfile", dummy, argc, argv); + // directory include filters + std::string filter; + c.hasDirectoryIncludeFilters = ra::cli::ParseArgument("dirincludefilter", filter, argc, argv); + if ( c.hasDirectoryIncludeFilters ) + { + strSplit(filter, DIRECTORY_FILTER_SEPARATOR, c.directoryIncludeFilters); + } + + // directory exclude filters + c.hasDirectoryExcludeFilters = ra::cli::ParseArgument("direxcludefilter", filter, argc, argv); + if ( c.hasDirectoryExcludeFilters ) + { + strSplit(filter, DIRECTORY_FILTER_SEPARATOR, c.directoryExcludeFilters); + } + //force registerfile if managerfile is specified - if (args.hasManagerFile) + if (c.hasManagerFile) { - args.registerfile = true; + c.registerFiles = true; + } + + c.hasReportedFilePath = ra::cli::ParseArgument("reportedfilepath", c.reportedFilePath, argc, argv); + if (c.hasReportedFilePath && c.hasInputDir) + { + APP_ERROR_CODES error = APP_ERROR_TOOMANYARGUMENTS; + ra::logging::Log(ra::logging::LOG_ERROR, "%s (reportedfilepath)", getErrorCodeDescription(error)); + printUsage(); + return error; } + c.keepDirectoryStructure = ra::cli::ParseArgument("keepdirs", dummy, argc, argv); + std::string encodingStr; if (ra::cli::ParseArgument("encoding", encodingStr, argc, argv)) { if (ra::strings::Uppercase(encodingStr) == "OCT") - args.encoding = IGenerator::CPP_ENCODER_OCT; + c.cppEncoder = CPP_ENCODER_OCT; else if (ra::strings::Uppercase(encodingStr) == "HEX") - args.encoding = IGenerator::CPP_ENCODER_HEX; + c.cppEncoder = CPP_ENCODER_HEX; else { - APP_ERROR_CODES error = APP_ERROR_MISSINGARGUMENTS; + APP_ERROR_CODES error = APP_ERROR_INVALIDVALUE; ra::logging::Log(ra::logging::LOG_ERROR, "%s (encoding)", getErrorCodeDescription(error)); printUsage(); return error; @@ -389,7 +400,7 @@ int main(int argc, char* argv[]) } else { - args.encoding = DEFAULT_ENCODING; + c.cppEncoder = DEFAULT_ENCODING; } //select generator @@ -428,39 +439,59 @@ int main(int argc, char* argv[]) } } + //win32 generator does not support plain output + if (args.generatorName == "win32" && c.plainOutput) + { + APP_ERROR_CODES error = AAP_ERROR_NOTSUPPORTED; + ra::logging::Log(ra::logging::LOG_ERROR, "%s.", getErrorCodeDescription(error)); + return error; + } + //apply default generator if (generator == NULL) { generator = &segmentGenerator; } - //process file or directory - if (args.hasFile) + //process file, directory or plain format + if (c.plainOutput) + { + APP_ERROR_CODES error = processPlainOutput(c, generator); + if (error != APP_ERROR_SUCCESS) + { + ra::logging::Log(ra::logging::LOG_ERROR, "%s.", getErrorCodeDescription(error)); + return error; + } + } + else if (c.hasInputFile) { - APP_ERROR_CODES error = processInputFile(args, generator); + APP_ERROR_CODES error = processInputFile(c, generator); if (error != APP_ERROR_SUCCESS) { - ra::logging::Log(ra::logging::LOG_ERROR, "%s", getErrorCodeDescription(error)); + ra::logging::Log(ra::logging::LOG_ERROR, "%s.", getErrorCodeDescription(error)); return error; } } - else if (args.hasDir) + else if (c.hasInputDir) { - APP_ERROR_CODES error = processInputDirectory(args, generator); + APP_ERROR_CODES error = processInputDirectory(c, &nameProvider, generator); if (error != APP_ERROR_SUCCESS) { - ra::logging::Log(ra::logging::LOG_ERROR, "%s", getErrorCodeDescription(error)); + ra::logging::Log(ra::logging::LOG_ERROR, "%s.", getErrorCodeDescription(error)); return error; } } //should we also generate the FileManager class? - if (args.hasManagerFile) + if (c.hasManagerFile) { - APP_ERROR_CODES error = processManagerFiles(args, generator); + //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) { - ra::logging::Log(ra::logging::LOG_ERROR, "%s", getErrorCodeDescription(error)); + ra::logging::Log(ra::logging::LOG_ERROR, "%s.", getErrorCodeDescription(error)); return error; } } @@ -468,50 +499,69 @@ int main(int argc, char* argv[]) return APP_ERROR_SUCCESS; } -APP_ERROR_CODES processInputFile(const ARGUMENTS & args, bin2cpp::IGenerator * generator) +APP_ERROR_CODES processInputFile(const Context & c, bin2cpp::IGenerator * generator) { // printing info std::string info; - info << "Embedding \"" << args.inputFilePath << "\""; - if (args.chunkSize != DEFAULT_CHUNK_SIZE) + info << "Embedding \"" << c.inputFilePath << "\""; + if (c.chunkSize != DEFAULT_CHUNK_SIZE) { info << " using chunks of "; - info << ra::strings::ToString(args.chunkSize); + info << ra::strings::ToString(c.chunkSize); info << " bytes"; } - if (args.overrideExisting) + if (c.overrideExistingFiles) info << " overriding existing files"; info << "..."; ra::logging::Log(ra::logging::LOG_INFO, info.c_str()); - //prepare output files path - std::string cppFilename = args.headerFilename; - ra::strings::Replace(cppFilename, ".hpp", ".cpp"); - ra::strings::Replace(cppFilename, ".h", ".cpp"); - std::string outputHeaderPath = args.outputDirPath + ra::filesystem::GetPathSeparatorStr() + args.headerFilename; - std::string outputCppPath = args.outputDirPath + ra::filesystem::GetPathSeparatorStr() + cppFilename; - //check if input file exists - if (!ra::filesystem::FileExists(args.inputFilePath.c_str())) + if (!ra::filesystem::FileExists(c.inputFilePath.c_str())) return APP_ERROR_INPUTFILENOTFOUND; + //prepare output files path + const std::string headerExtention = ra::filesystem::GetFileExtention(c.headerFilename); + const std::string & sourceExtension = getDefaultCodeSourceFileExtension(c.code); + std::string sourceFilename = c.headerFilename.substr(0, c.headerFilename.size() - headerExtention.size()) + sourceExtension; // strip out header file's extension and add 'cpp'. + + //create a copy of the context. + //we may have already generated files from a previous call to processInputFile(). + //make sure the file paths are unique. + Context cCopy = c; + + //build unique output relative file paths + cCopy.headerFilename = bin2cpp::getUniqueFilePath(cCopy.headerFilename, output_files_dictionary); + sourceFilename = bin2cpp::getUniqueFilePath(sourceFilename, output_files_dictionary); + + //build full absolute paths + std::string outputHeaderPath = cCopy.outputDirPath + ra::filesystem::GetPathSeparatorStr() + cCopy.headerFilename; + std::string outputSourcePath = cCopy.outputDirPath + ra::filesystem::GetPathSeparatorStr() + sourceFilename; + //configure the generator - generator->setInputFilePath(args.inputFilePath.c_str()); - generator->setHeaderFilename(args.headerFilename.c_str()); - generator->setFunctionIdentifier(args.functionIdentifier.c_str()); - generator->setChunkSize(args.chunkSize); - generator->setNamespace(args.codeNamespace.c_str()); - generator->setBaseClass(args.baseClass.c_str()); - generator->setCppEncoder(args.encoding); - generator->setManagerHeaderFilename(args.managerHeaderFilename.c_str()); - generator->setRegisterFileEnabled(args.registerfile); + generator->setContext(cCopy); + + //build the output directory structure if required + if (cCopy.keepDirectoryStructure) + { + std::string parent_directory = ra::filesystem::GetParentPath(outputHeaderPath); + if (!parent_directory.empty() && !ra::filesystem::DirectoryExists(parent_directory.c_str())) + { + ra::logging::Log(ra::logging::LOG_INFO, "Creating directory \"%s\"...", parent_directory.c_str()); + bool success = ra::filesystem::CreateDirectory(parent_directory.c_str()); + if (!success) + { + ra::logging::Log(ra::logging::LOG_ERROR, "Failed to create directory \"%s\".", parent_directory.c_str()); + return APP_ERROR_UNABLETOCREATEOUTPUTFILES; + } + } + } //process files - bool headerResult = generateFile(args, outputHeaderPath, generator); + bool headerResult = generateOutputFile(c, outputHeaderPath, generator); if (!headerResult) return APP_ERROR_UNABLETOCREATEOUTPUTFILES; - bool cppResult = generateFile(args, outputCppPath, generator); + bool cppResult = generateOutputFile(c, outputSourcePath, generator); if (!cppResult) return APP_ERROR_UNABLETOCREATEOUTPUTFILES; @@ -519,33 +569,53 @@ APP_ERROR_CODES processInputFile(const ARGUMENTS & args, bin2cpp::IGenerator * g return APP_ERROR_SUCCESS; } -APP_ERROR_CODES processInputDirectory(const ARGUMENTS & args, bin2cpp::IGenerator * generator) +APP_ERROR_CODES processInputDirectory(const Context& c, bin2cpp::INameProvider * nameProvider, bin2cpp::IGenerator * generator) { //check if input dir exists - if (!ra::filesystem::DirectoryExists(args.inputDirPath.c_str())) + if (!ra::filesystem::DirectoryExists(c.inputDirPath.c_str())) { APP_ERROR_CODES error = APP_ERROR_INPUTDIRNOTFOUND; - ra::logging::Log(ra::logging::LOG_ERROR, "%s (%s)", getErrorCodeDescription(error), args.inputDirPath.c_str()); + ra::logging::Log(ra::logging::LOG_ERROR, "%s (%s)", getErrorCodeDescription(error), c.inputDirPath.c_str()); return error; } //search all files in the directory ra::strings::StringVector files; - bool found = ra::filesystem::FindFiles(files, args.inputDirPath.c_str()); + bool found = ra::filesystem::FindFiles(files, c.inputDirPath.c_str()); if (!found) { APP_ERROR_CODES error = APP_ERROR_INPUTDIRNOTFOUND; - ra::logging::Log(ra::logging::LOG_ERROR, "%s (%s)", getErrorCodeDescription(error), args.inputDirPath.c_str()); + ra::logging::Log(ra::logging::LOG_ERROR, "%s (%s)", getErrorCodeDescription(error), c.inputDirPath.c_str()); return error; } - //remove directories from list + //remove directory entries from list ra::strings::StringVector tmp; for(size_t i=0; igetDefaultHeaderFile(cCopy.inputFilePath); //use the file name without extension as 'identifier'. - argsCopy.functionIdentifier = getFunctionIdentifierFromPath(ra::filesystem::GetFilenameWithoutExtension(file.c_str())); - argsCopy.functionIdentifier = ra::strings::CapitalizeFirstCharacter(argsCopy.functionIdentifier); + cCopy.functionIdentifier = nameProvider->getDefaultFunctionIdentifier(cCopy.inputFilePath, identifiers_dictionary); + + //build a relative file path + std::string relative_file_path = file; + relative_file_path.erase(0, cCopy.inputDirPath.size() + 1 ); // convert absolute path to relative path. +1 to remove first \ character + ra::filesystem::NormalizePath(relative_file_path); + + //automatically build a reported path with --dir mode. + cCopy.hasReportedFilePath = true; + cCopy.reportedFilePath = relative_file_path; + + if (c.keepDirectoryStructure) + { + // To keep the directory structure, we need to + // make headerFilename a relative path + // inside the output directory + std::string relative_header_file_path = relative_file_path; + + // change the file extension to *.h + std::string extension = ra::filesystem::GetFileExtention(relative_header_file_path); + if (relative_header_file_path.size() >= extension.size()) + { + relative_header_file_path.erase(relative_header_file_path.size() - extension.size()); + relative_header_file_path += "h"; + } + + cCopy.headerFilename = relative_header_file_path; + } //process this file... - APP_ERROR_CODES error = processInputFile(argsCopy, generator); + APP_ERROR_CODES error = processInputFile(cCopy, generator); if (error != APP_ERROR_SUCCESS) return error; @@ -608,9 +702,9 @@ FILE_UPDATE_MODE getFileUpdateMode(const std::string & input_file_path, const st return UPDATING; } -bool generateFile(const ARGUMENTS & args, const std::string & output_file_path, bin2cpp::IGenerator * generator) +bool generateOutputFile(const Context & c, const std::string & output_file_path, bin2cpp::IGenerator * generator) { - FILE_UPDATE_MODE mode = getFileUpdateMode(args.inputFilePath, output_file_path, args.overrideExisting); + FILE_UPDATE_MODE mode = getFileUpdateMode(c.inputFilePath, output_file_path, c.overrideExistingFiles); //writing message ra::logging::Log(ra::logging::LOG_INFO, "%s file \"%s\"...", getUpdateModeText(mode), output_file_path.c_str()); @@ -620,82 +714,87 @@ bool generateFile(const ARGUMENTS & args, const std::string & output_file_path, //generate file bool result = false; - if (isCppHeaderFile(output_file_path)) + if (c.code == CODE_GENERATION_CPP && isCppHeaderFile(output_file_path)) { - //generate header + //generate C++ header result = generator->createCppHeaderFile(output_file_path.c_str()); } - else + else if ( c.code == CODE_GENERATION_CPP) { - //generate cpp + //generate C++ source result = generator->createCppSourceFile(output_file_path.c_str()); } - if (!result) - { - //there was an error generating file - ra::logging::Log(ra::logging::LOG_ERROR, "%s", getErrorCodeDescription(APP_ERROR_UNABLETOCREATEOUTPUTFILES)); - ra::logging::Log(ra::logging::LOG_ERROR, "Embedding failed!"); - } - return result; -} - -bool generateManagerFile(const ARGUMENTS & args, const std::string & output_file_path, bin2cpp::IGenerator * generator) -{ - std::string processPath = ra::process::GetCurrentProcessPath(); - FILE_UPDATE_MODE mode = getFileUpdateMode(processPath, output_file_path, args.overrideExisting); - - //writing message - ra::logging::Log(ra::logging::LOG_INFO, "%s file \"%s\"...", getUpdateModeText(mode), output_file_path.c_str()); - - if (mode == SKIPPING) - return true; //skipping is success - - //generate file - bool result = false; - if (isCppHeaderFile(output_file_path)) + else if ( c.code == CODE_GENERATION_C && isCHeaderFile(output_file_path) ) { - //generate header - result = generator->createManagerHeaderFile(output_file_path.c_str()); + //generate C header + result = generator->createCHeaderFile(output_file_path.c_str()); } - else + else if ( c.code == CODE_GENERATION_C ) { - //generate cpp - result = generator->createManagerSourceFile(output_file_path.c_str()); + //generate C source + result = generator->createCSourceFile(output_file_path.c_str()); } if (!result) { //there was an error generating file - ra::logging::Log(ra::logging::LOG_ERROR, "%s failed!", getUpdateModeText(mode)); + ra::logging::Log(ra::logging::LOG_ERROR, "%s", getErrorCodeDescription(APP_ERROR_UNABLETOCREATEOUTPUTFILES)); + ra::logging::Log(ra::logging::LOG_ERROR, "Embedding failed!"); } return result; } -APP_ERROR_CODES processManagerFiles(const ARGUMENTS & args, bin2cpp::IGenerator * generator) +APP_ERROR_CODES processManagerFiles(const Context & c) { // printing info std::string info; - info << "Generating \"" << args.managerHeaderFilename << "\""; - if (args.overrideExisting) + info << "Generating \"" << c.managerHeaderFilename << "\""; + if (c.overrideExistingFiles) info << " overriding existing files"; info << "..."; ra::logging::Log(ra::logging::LOG_INFO, info.c_str()); + const std::string& sourceFileExtension = "." + getDefaultCodeSourceFileExtension(c.code); + //prepare output files path - std::string cppFilename = args.managerHeaderFilename; - ra::strings::Replace(cppFilename, ".hpp", ".cpp"); - ra::strings::Replace(cppFilename, ".h", ".cpp"); - std::string outputHeaderPath = args.outputDirPath + ra::filesystem::GetPathSeparatorStr() + args.managerHeaderFilename; - std::string outputCppPath = args.outputDirPath + ra::filesystem::GetPathSeparatorStr() + cppFilename; + std::string cppFilename = c.managerHeaderFilename; + ra::strings::Replace(cppFilename, ".hpp", sourceFileExtension); + ra::strings::Replace(cppFilename, ".h", sourceFileExtension); + std::string outputHeaderPath = c.outputDirPath + ra::filesystem::GetPathSeparatorStr() + c.managerHeaderFilename; + std::string outputSourcePath = c.outputDirPath + ra::filesystem::GetPathSeparatorStr() + cppFilename; + + ManagerGenerator generator; + + //configure the generator + generator.setContext(c); + //process files - bool headerResult = generateManagerFile(args, outputHeaderPath, generator); + bool headerResult = generateOutputFile(c, outputHeaderPath, &generator); if (!headerResult) return APP_ERROR_UNABLETOCREATEOUTPUTFILES; - bool cppResult = generateManagerFile(args, outputCppPath, generator); + bool cppResult = generateOutputFile(c, outputSourcePath, &generator); if (!cppResult) return APP_ERROR_UNABLETOCREATEOUTPUTFILES; //success return APP_ERROR_SUCCESS; } + +APP_ERROR_CODES processPlainOutput(const Context & c, bin2cpp::IGenerator * generator) +{ + //check if input file exists + if (!ra::filesystem::FileExists(c.inputFilePath.c_str())) + return APP_ERROR_INPUTFILENOTFOUND; + + //configure the generator + generator->setContext(c); + + //process file + bool result = generator->printFileContent(); + if (!result) + return APP_ERROR_OPERATIONHASFAILED; + + //success + return APP_ERROR_SUCCESS; +} diff --git a/src/bin2cpp/types.h b/src/bin2cpp/types.h new file mode 100644 index 0000000..5f3bc09 --- /dev/null +++ b/src/bin2cpp/types.h @@ -0,0 +1,41 @@ +/********************************************************************************** + * 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 TYPES_H +#define TYPES_H + +#include +#include + +namespace bin2cpp +{ + + /// + ///A set of names stored as a Distionnary + /// + typedef std::set Dictionary; + +}; //bin2cpp + +#endif //TYPES_H diff --git a/src/bin2cpp/wildcard.cpp b/src/bin2cpp/wildcard.cpp new file mode 100644 index 0000000..24e2056 --- /dev/null +++ b/src/bin2cpp/wildcard.cpp @@ -0,0 +1,171 @@ +/********************************************************************************** + * 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 "wildcard.h" +#include "bin2cpp/version.h" + +namespace bin2cpp +{ + static inline bool isdigit(const char& c) + { + return '0' <= c && c <= '9'; + } + + ///The search index within the value string. + ///The search index within the pattern string. + bool wildcard_match_helper(const std::string& value, const std::string& pattern, size_t value_index, size_t pattern_index, std::vector& captures) + { + // Base case: value and pattern are both exhausted. All characrters matches. + if ( value_index == value.size() && pattern_index == pattern.size() ) + { + return true; + } + + // If pattern is exhausted but value has more characters, no match + if ( pattern_index == pattern.size() ) return false; + + // Handle '*': Capture a variable-length substring + if ( pattern[pattern_index] == '*' ) + { + for ( size_t i = value_index; i <= value.size(); ++i ) + { + captures.push_back(value.substr(value_index, i - value_index)); + + // Recurse to resolve for the remaining characters. + bool match = wildcard_match_helper(value, pattern, i, pattern_index + 1, captures); + if ( match ) return true; + captures.pop_back(); // Remove last match if unsuccessful + } + return false; + } + + // Handle '?': Capture a single character. + if ( value_index < value.size() && pattern[pattern_index] == '?' ) + { + captures.push_back(std::string(1, value[value_index])); // Store single-character match + + // Recurse to resolve for the remaining characters. + bool match = wildcard_match_helper(value, pattern, value_index + 1, pattern_index + 1, captures); + return match; + } + + // Handle '#': Capture any single digit (0-9) + if ( value_index < value.size() && pattern[pattern_index] == '#' && isdigit(value[value_index]) ) + { + captures.push_back(std::string(1, value[value_index])); + + // Recurse to resolve for the remaining characters. + bool match = wildcard_match_helper(value, pattern, value_index + 1, pattern_index + 1, captures); + return match; + } + + // Handling character lists like '[xyz]' or ranges like '[a-z]'. + // This assumes that first range character is smaller than second range character. + if ( pattern[pattern_index] == '[' ) + { + size_t closing_bracket_pos = pattern.find(']', pattern_index); + if ( closing_bracket_pos == std::string::npos ) return false; // Malformed pattern + + char matchChar = value[value_index]; + bool found = false; + + // For each characters in within the brackets + for ( size_t i = pattern_index + 1; i < closing_bracket_pos; ++i ) + { + // Is this a range? + if ( pattern[i] == '-' && i > pattern_index + 1 && i < closing_bracket_pos - 1 ) + { + // Handle range [x-y] + if ( matchChar >= pattern[i - 1] && matchChar <= pattern[i + 1] ) found = true; + } + else if ( pattern[i] == matchChar ) + { + found = true; + } + } + + // If match is found, capture it and continue recursion + if ( found ) + { + captures.push_back(std::string(1, matchChar)); + + // Recurse to resolve for the remaining characters. + bool match = wildcard_match_helper(value, pattern, value_index + 1, closing_bracket_pos + 1, captures); + return match; + } + else + { + return false; + } + } + + // Exact character match + if ( value_index < value.size() && pattern[pattern_index] == value[value_index] ) + { + // Recurse to resolve for the remaining characters. + bool match = wildcard_match_helper(value, pattern, value_index + 1, pattern_index + 1, captures); + return match; + } + + return false; + } + + bool wildcard_match(const std::string& value, const std::string& pattern, std::vector& captures) + { + captures.clear(); // Ensure captures vector is empty before starting + bool match = wildcard_match_helper(value, pattern, 0, 0, captures); + if ( !match ) + captures.clear(); + return match; + } + + bool wildcard_match_any(const std::string& value, const std::vector& patterns) + { + bool result = false; + std::vector captures; + for ( size_t i = 0; i < patterns.size(); i++ ) + { + const std::string& pattern = patterns[i]; + bool match = wildcard_match(value, pattern, captures); + if ( match ) + return true; + } + return result; + } + + bool wildcard_match_all(const std::string& value, const std::vector& patterns) + { + bool result = true; + std::vector captures; + for ( size_t i = 0; i < patterns.size(); i++ ) + { + const std::string& pattern = patterns[i]; + bool match = wildcard_match(value, pattern, captures); + if ( !match ) + return false; + } + return result; + } + +}; //bin2cpp diff --git a/src/bin2cpp/wildcard.h b/src/bin2cpp/wildcard.h new file mode 100644 index 0000000..1439178 --- /dev/null +++ b/src/bin2cpp/wildcard.h @@ -0,0 +1,91 @@ +/********************************************************************************** + * 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 BIN2CPP_WILDCARD_H +#define BIN2CPP_WILDCARD_H + +#include +#include + +namespace bin2cpp +{ + + /// + ///Checks if a given value matches a pattern containing wildcard characters definition. + /// + /// + /// Supported Wildcards : + /// -'?' matches any single character. + /// -'*' matches zero or more characters. + /// -'#' matches any single digit(0 - 9). + /// -'[charlist]' matches any character in the provided set. + /// -'[a-z]', '[A-Z]', '[0-9]' match characters in respective ranges. + /// -'[a-zA-Z0-9]' matches any alphanumeric character. + /// + ///The file path, value or string to match. + ///The pattern containing wildcards. + ///The captured value of wildcard within the input value. The number of captures matches the number of wildcard in the pattern. + ///Returns true if the value matches the pattern, otherwise false. + bool wildcard_match(const std::string& value, const std::string& pattern, std::vector& captures); + + /// + ///Checks if a given value matches a pattern containing wildcard characters definition. + /// + /// + /// Supported Wildcards : + /// -'?' matches any single character. + /// -'*' matches zero or more characters. + /// -'#' matches any single digit(0 - 9). + /// -'[charlist]' matches any character in the provided set. + /// -'[a-z]', '[A-Z]', '[0-9]' match characters in respective ranges. + /// -'[a-zA-Z0-9]' matches any alphanumeric character. + /// + ///The file path, value or string to match. + ///The pattern containing wildcards. + ///Returns true if the value matches the pattern, otherwise false. + inline bool wildcard_match(const std::string& value, const std::string& pattern) + { + std::vector tmp_captures; + return wildcard_match(value, pattern, tmp_captures); + } + + /// + ///Checks if a given value matches at least one of the given patterns. + /// + ///The file path, value or string to match. + ///The list of patterns containing wildcards. + ///Returns true if the value matches the any pattern, otherwise false. + bool wildcard_match_any(const std::string& value, const std::vector& patterns); + + /// + ///Checks if a given value matches at of the given patterns. + /// + ///The file path, value or string to match. + ///The list of patterns containing wildcards. + ///Returns true if the value matches the any pattern, otherwise false. + bool wildcard_match_all(const std::string& value, const std::vector& patterns); + +}; //bin2cpp + +#endif //BIN2CPP_COMMON_H diff --git a/test/bin2cpp_unittest/CMakeLists.txt b/test/bin2cpp_unittest/CMakeLists.txt old mode 100755 new mode 100644 index 8d6c1b7..c682746 --- a/test/bin2cpp_unittest/CMakeLists.txt +++ b/test/bin2cpp_unittest/CMakeLists.txt @@ -1,20 +1,40 @@ +include_directories(${CMAKE_SOURCE_DIR}/src/bin2cpp) # for External Files + set(GENERATED_TEST_FILES_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated_files) include_directories(${GENERATED_TEST_FILES_DIR}) # for TestExtraction.cpp # Include directories for each generated files. +# These are required because each generated cpp file is including its header file +# without using the parent directory. include_directories(${GENERATED_TEST_FILES_DIR}/testBaseClass) +include_directories(${GENERATED_TEST_FILES_DIR}/testBaseClass_C) +include_directories(${GENERATED_TEST_FILES_DIR}/testDir01/sources) include_directories(${GENERATED_TEST_FILES_DIR}/testEncodingHex) include_directories(${GENERATED_TEST_FILES_DIR}/testEncodingOct) +include_directories(${GENERATED_TEST_FILES_DIR}/testFileManager) +include_directories(${GENERATED_TEST_FILES_DIR}/testFileManager_C) include_directories(${GENERATED_TEST_FILES_DIR}/testGeneratorArray10000) +include_directories(${GENERATED_TEST_FILES_DIR}/testGeneratorArray10000_C) include_directories(${GENERATED_TEST_FILES_DIR}/testGeneratorSegment10000) +include_directories(${GENERATED_TEST_FILES_DIR}/testGeneratorSegment10000_C) include_directories(${GENERATED_TEST_FILES_DIR}/testGeneratorString10000) +include_directories(${GENERATED_TEST_FILES_DIR}/testGeneratorString10000_C) +if (WIN32) + include_directories(${GENERATED_TEST_FILES_DIR}/testGeneratorWin32) + include_directories(${GENERATED_TEST_FILES_DIR}/testGeneratorWin32_C) +endif() include_directories(${GENERATED_TEST_FILES_DIR}/testHtml100000) include_directories(${GENERATED_TEST_FILES_DIR}/testIssue12) include_directories(${GENERATED_TEST_FILES_DIR}/testIssue12Mini) include_directories(${GENERATED_TEST_FILES_DIR}/testIssue13) include_directories(${GENERATED_TEST_FILES_DIR}/testIssue47) include_directories(${GENERATED_TEST_FILES_DIR}/testIssue50) +include_directories(${GENERATED_TEST_FILES_DIR}/testIssue56a) +include_directories(${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources) +include_directories(${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources) +include_directories(${GENERATED_TEST_FILES_DIR}/testKeepDirectories) include_directories(${GENERATED_TEST_FILES_DIR}/testNamespace) +include_directories(${GENERATED_TEST_FILES_DIR}/testNamespace_C) include_directories(${GENERATED_TEST_FILES_DIR}/testRandom1) include_directories(${GENERATED_TEST_FILES_DIR}/testRandom2) include_directories(${GENERATED_TEST_FILES_DIR}/testRandom3) @@ -23,20 +43,20 @@ include_directories(${GENERATED_TEST_FILES_DIR}/testRandom5) include_directories(${GENERATED_TEST_FILES_DIR}/testRandom6) include_directories(${GENERATED_TEST_FILES_DIR}/testRandom7) include_directories(${GENERATED_TEST_FILES_DIR}/testRandom8) +include_directories(${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources) +include_directories(${GENERATED_TEST_FILES_DIR}/testReportedPathFile1) +include_directories(${GENERATED_TEST_FILES_DIR}/testReportedPathFile2) include_directories(${GENERATED_TEST_FILES_DIR}/testSequential1000) include_directories(${GENERATED_TEST_FILES_DIR}/testSequential10MB) include_directories(${GENERATED_TEST_FILES_DIR}/testText10) include_directories(${GENERATED_TEST_FILES_DIR}/testText1000) include_directories(${GENERATED_TEST_FILES_DIR}/testText100000) -include_directories(${GENERATED_TEST_FILES_DIR}/testFileManager) -include_directories(${GENERATED_TEST_FILES_DIR}/testDir01/sources) -if (WIN32) - include_directories(${GENERATED_TEST_FILES_DIR}/testGeneratorWin32) -endif() set(GENERATED_TEST_FILES ${GENERATED_TEST_FILES_DIR}/testBaseClass/_testBaseClass.h ${GENERATED_TEST_FILES_DIR}/testBaseClass/_testBaseClass.cpp + ${GENERATED_TEST_FILES_DIR}/testBaseClass_C/_testBaseClass_C.h + ${GENERATED_TEST_FILES_DIR}/testBaseClass_C/_testBaseClass_C.c ${GENERATED_TEST_FILES_DIR}/testEncodingHex/_testEncodingHex.h ${GENERATED_TEST_FILES_DIR}/testEncodingHex/_testEncodingHex.cpp ${GENERATED_TEST_FILES_DIR}/testEncodingOct/_testEncodingOct.h @@ -47,6 +67,12 @@ set(GENERATED_TEST_FILES ${GENERATED_TEST_FILES_DIR}/testGeneratorSegment10000/_testGeneratorSegment10000.cpp ${GENERATED_TEST_FILES_DIR}/testGeneratorString10000/_testGeneratorString10000.h ${GENERATED_TEST_FILES_DIR}/testGeneratorString10000/_testGeneratorString10000.cpp + ${GENERATED_TEST_FILES_DIR}/testGeneratorArray10000_C/_testGeneratorArray10000_C.h + ${GENERATED_TEST_FILES_DIR}/testGeneratorArray10000_C/_testGeneratorArray10000_C.c + ${GENERATED_TEST_FILES_DIR}/testGeneratorSegment10000_C/_testGeneratorSegment10000_C.h + ${GENERATED_TEST_FILES_DIR}/testGeneratorSegment10000_C/_testGeneratorSegment10000_C.c + ${GENERATED_TEST_FILES_DIR}/testGeneratorString10000_C/_testGeneratorString10000_C.h + ${GENERATED_TEST_FILES_DIR}/testGeneratorString10000_C/_testGeneratorString10000_C.c ${GENERATED_TEST_FILES_DIR}/testHtml100000/_testHtml100000.h ${GENERATED_TEST_FILES_DIR}/testHtml100000/_testHtml100000.cpp ${GENERATED_TEST_FILES_DIR}/testIssue12/_testIssue12.h @@ -63,8 +89,44 @@ set(GENERATED_TEST_FILES ${GENERATED_TEST_FILES_DIR}/testIssue50/_testIssue50.cpp ${GENERATED_TEST_FILES_DIR}/testIssue50/FileManager50.h ${GENERATED_TEST_FILES_DIR}/testIssue50/FileManager50.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56a/compiled_sources/_testIssue56a.index.4321.h + ${GENERATED_TEST_FILES_DIR}/testIssue56a/compiled_sources/_testIssue56a.index.1234.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56a/compiled_sources/_testIssue56a.index.1234.h + ${GENERATED_TEST_FILES_DIR}/testIssue56a/compiled_sources/_testIssue56a.index.4321.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56a/compiled_sources/FileManager56a.h + ${GENERATED_TEST_FILES_DIR}/testIssue56a/compiled_sources/FileManager56a.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/FileManager56b.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/FileManager56b.h + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/index.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/index.h + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/blog/index.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/blog/index.h + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/blog/how-to-create-a-web-site/index.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/blog/how-to-create-a-web-site/index.h + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/blog/using-bin2cpp/index.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/blog/using-bin2cpp/index.h + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/contact/index.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/contact/index.h + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/home/index.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56b/generated_sources/www/home/index.h + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/FileManager56c.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/FileManager56c.h + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index.h + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index_1.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index_1.h + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index_2.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index_2.h + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index_3.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index_3.h + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index_4.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index_4.h + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index_5.cpp + ${GENERATED_TEST_FILES_DIR}/testIssue56c/generated_sources/index_5.h ${GENERATED_TEST_FILES_DIR}/testNamespace/_testNamespace.h ${GENERATED_TEST_FILES_DIR}/testNamespace/_testNamespace.cpp + ${GENERATED_TEST_FILES_DIR}/testNamespace_C/_testNamespace_C.h + ${GENERATED_TEST_FILES_DIR}/testNamespace_C/_testNamespace_C.c ${GENERATED_TEST_FILES_DIR}/testRandom1/_testRandom1.h ${GENERATED_TEST_FILES_DIR}/testRandom1/_testRandom1.cpp ${GENERATED_TEST_FILES_DIR}/testRandom2/_testRandom2.h @@ -97,6 +159,12 @@ set(GENERATED_TEST_FILES ${GENERATED_TEST_FILES_DIR}/testFileManager/_testFileManager.2.cpp ${GENERATED_TEST_FILES_DIR}/testFileManager/FileManager.h ${GENERATED_TEST_FILES_DIR}/testFileManager/FileManager.cpp + ${GENERATED_TEST_FILES_DIR}/testFileManager_C/_testFileManager_C.1.h + ${GENERATED_TEST_FILES_DIR}/testFileManager_C/_testFileManager_C.1.c + ${GENERATED_TEST_FILES_DIR}/testFileManager_C/_testFileManager_C.2.h + ${GENERATED_TEST_FILES_DIR}/testFileManager_C/_testFileManager_C.2.c + ${GENERATED_TEST_FILES_DIR}/testFileManager_C/filemanager.h + ${GENERATED_TEST_FILES_DIR}/testFileManager_C/filemanager.c ${GENERATED_TEST_FILES_DIR}/testDir01/sources/_img0001.h ${GENERATED_TEST_FILES_DIR}/testDir01/sources/_img0002.h ${GENERATED_TEST_FILES_DIR}/testDir01/sources/_img0003.h @@ -107,6 +175,24 @@ set(GENERATED_TEST_FILES ${GENERATED_TEST_FILES_DIR}/testDir01/sources/_img0003.cpp ${GENERATED_TEST_FILES_DIR}/testDir01/sources/_img0004.cpp ${GENERATED_TEST_FILES_DIR}/testDir01/sources/_img0005.cpp + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index.h + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index.cpp + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index_1.h + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index_1.cpp + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index_2.h + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index_2.cpp + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index_3.h + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index_3.cpp + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index_4.h + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index_4.cpp + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index_5.h + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/index_5.cpp + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/FileManagerReportedPathDir.h + ${GENERATED_TEST_FILES_DIR}/testReportedPathDir/generated_sources/FileManagerReportedPathDir.cpp + ${GENERATED_TEST_FILES_DIR}/testReportedPathFile1/_testReportedPathFile1.h + ${GENERATED_TEST_FILES_DIR}/testReportedPathFile1/_testReportedPathFile1.cpp + ${GENERATED_TEST_FILES_DIR}/testReportedPathFile2/_testReportedPathFile2.h + ${GENERATED_TEST_FILES_DIR}/testReportedPathFile2/_testReportedPathFile2.cpp ) if (WIN32) # Include win32 generated test files only on Windows platform. @@ -114,14 +200,34 @@ if (WIN32) ${GENERATED_TEST_FILES_DIR}/testGeneratorWin32/_testGeneratorWin32.h ${GENERATED_TEST_FILES_DIR}/testGeneratorWin32/_testGeneratorWin32.cpp ${GENERATED_TEST_FILES_DIR}/testGeneratorWin32/_testGeneratorWin32.rc + ${GENERATED_TEST_FILES_DIR}/testGeneratorWin32_C/_testGeneratorWin32_C.h + ${GENERATED_TEST_FILES_DIR}/testGeneratorWin32_C/_testGeneratorWin32_C.c + ${GENERATED_TEST_FILES_DIR}/testGeneratorWin32_C/_testGeneratorWin32_C.rc ) endif() set(TEMPLATE_SCRIPT_FILE ${BIN2CPP_UNITTEST_SOURCE_DIR}/generate_test_files.${SCRIPT_FILE_EXTENSION}.in) -# https://stackoverflow.com/questions/18427877/add-custom-build-step-in-cmake +# Define a dummy file to act as a stamp for file generation completion +set(GENERATION_STAMP ${GENERATED_TEST_FILES_DIR}/generated_files.stamp) + +# The script generates multiple files from a single command, but if I try to list all of them as OUTPUT of the add_custom_command it won't work. +# CMake assumes each output is independently produced, so it starts compiling as soon as any one is generated, not necessarily all. +# +# CMake tracks outputs individually, so even if I have `OUTPUT ${GENERATED_TEST_FILES}`, it sees each output as possibly ready at different times. +# When one appears on disk (even partially), it may trigger compilation of bin2cpp_unittest, before the script finishes generating all files. +# +# To work around this behavior, is using a stamp file which is created after the generation script has run which indicates to CMake we are ready to compile bin2cpp_unittest. +# Required steps: +# Only the stamp file is listed as OUTPUT. This prevents CMake from checking each generated file independently. +# The actual source files are listed as BYPRODUCTS, so CMake knows they will appear but doesn't rely on their timestamps individually. +# add_dependencies() ensures the executable only starts compiling after the stamp file is created, i.e., after the script finishes. +# +# To force CMake to regenerate the files, delete the stamp file. +# if (WIN32) - add_custom_command( OUTPUT ${GENERATED_TEST_FILES} + add_custom_command( OUTPUT ${GENERATION_STAMP} + BYPRODUCTS ${GENERATED_TEST_FILES} # Execute prebuild copy COMMAND ${CMAKE_COMMAND} -DBIN2CPP_TARGET_FILE=$ @@ -134,10 +240,17 @@ if (WIN32) # Execute generator script COMMAND echo Calling 'generate_test_files.bat' script... COMMAND cd /d ${CMAKE_CURRENT_BINARY_DIR} && call generate_test_files.bat + + # Tell CMake that we generated the last file of the series + COMMAND ${CMAKE_COMMAND} -E touch ${GENERATION_STAMP} + + COMMENT "Generating test files" + VERBATIM ) else() # Linux build - add_custom_command( OUTPUT ${GENERATED_TEST_FILES} + add_custom_command( OUTPUT ${GENERATION_STAMP} + BYPRODUCTS ${GENERATED_TEST_FILES} # Execute prebuild copy COMMAND ${CMAKE_COMMAND} -DBIN2CPP_TARGET_FILE=$ @@ -146,20 +259,50 @@ else() -DBIN2CPP_UNITTEST_PROJECT_DIR=${CMAKE_CURRENT_BINARY_DIR} -DBIN2CPP_UNITTEST_OUTPUT_DIR=${CMAKE_BINARY_DIR}/bin -P ${CMAKE_CURRENT_SOURCE_DIR}/generate_test_files.cmake - + # Execute generator script COMMAND echo Calling 'generate_test_files.sh' script... COMMAND cd ${CMAKE_CURRENT_BINARY_DIR} && ./generate_test_files.sh + + # Tell CMake that we generated the last file of the series + COMMAND ${CMAKE_COMMAND} -E touch ${GENERATION_STAMP} + + COMMENT "Generating test files" + VERBATIM ) - endif() +# Create a custom target that depends on the generated files +add_custom_target(generate_test_files + DEPENDS ${GENERATION_STAMP} + COMMENT "Ensuring file generation stamp exist" +) + # Show all generated files in a common folder source_group("Generated Files" FILES ${GENERATED_TEST_FILES}) +source_group("External Files" FILES + ${CMAKE_SOURCE_DIR}/src/bin2cpp/common.cpp + ${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 +set_source_files_properties(${GENERATED_TEST_FILES} PROPERTIES GENERATED TRUE) add_executable(bin2cpp_unittest ${BIN2CPP_VERSION_HEADER} ${BIN2CPP_CONFIG_HEADER} + ${CMAKE_SOURCE_DIR}/src/bin2cpp/common.cpp + ${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 @@ -169,13 +312,21 @@ add_executable(bin2cpp_unittest main.cpp TestCLI.cpp TestCLI.h + TestCommon.cpp + TestCommon.h TestExtraction.cpp TestExtraction.h + TestTemplateProcessor.cpp + TestTemplateProcessor.h + TestWildcard.cpp + TestWildcard.h ${GENERATED_TEST_FILES} ) add_dependencies(bin2cpp_unittest bin2cpp) add_dependencies(bin2cpp_unittest testfilegenerator) +add_dependencies(bin2cpp_unittest generate_test_files) + # Unit test projects requires to link with pthread if also linking with gtest if(NOT WIN32) diff --git a/test/bin2cpp_unittest/TestCLI.cpp b/test/bin2cpp_unittest/TestCLI.cpp index a416bc2..c23556c 100755 --- a/test/bin2cpp_unittest/TestCLI.cpp +++ b/test/bin2cpp_unittest/TestCLI.cpp @@ -30,6 +30,10 @@ #include "rapidassist/strings.h" #include "rapidassist/timing.h" +#include "enums.h" + +using namespace bin2cpp; + extern const std::string & gGeneratedFilesDir; #ifdef _WIN32 const std::string & gGeneratedFilesDir = "generated_files\\"; @@ -46,16 +50,6 @@ extern const std::string & gGeneratedFilesDir; }\ } -enum APP_ERROR_CODES -{ - APP_ERROR_SUCCESS, - APP_ERROR_MISSINGARGUMENTS, - APP_ERROR_INPUTFILENOTFOUND, - APP_ERROR_UNABLETOCREATEOUTPUTFILES, - APP_ERROR_TOOMANYARGUMENTS, - APP_ERROR_INPUTDIRNOTFOUND -}; - namespace TestCLIUtils { std::string getExpectedFilePath() @@ -848,54 +842,230 @@ TEST_F(TestCLI, testDir) ASSERT_TRUE(deleteFile(outputFilePath.c_str())); } -TEST_F(TestCLI, testErrorMissingArgumentFileOrDir) +TEST_F(TestCLI, testDirIncludeFilter) { + #define THIS_TEST_CASE_NAME "testDirIncludeFilter" static const std::string expectedFilePath = getExpectedFilePath(); - static const std::string outputFilePath = getActualFilePath(); - + static const std::string outputFilePath = getActualFilePath(); + std::string headerFileName = std::string("_") + ra::testing::GetTestCaseName().c_str() + ".h"; std::string headerFilePath = gGeneratedFilesDir + headerFileName; std::string cppFilePath = headerFilePath; ra::strings::Replace(cppFilePath, ".h", ".cpp"); - + //build command line std::string cmdline; cmdline.append(getBin2cppPath()); - //cmdline.append(" --file="); - //cmdline.append(getBin2cppPath()); //itself - cmdline.append(" --output=generated_files"); - cmdline.append(" --headerfile="); - cmdline.append(headerFileName); - cmdline.append(" --identifier="); - cmdline.append(ra::testing::GetTestCaseName().c_str()); + cmdline.append(" --dir=generated_files\\testDir02\\images"); //use windows path separator + cmdline.append(" --output=generated_files\\testDir02\\" THIS_TEST_CASE_NAME); + cmdline.append(" --dirincludefilter=\"*.svg:*.jpg\""); cmdline.append(" --noheader"); - + cmdline.append(" >"); cmdline.append(outputFilePath.c_str()); - + +#if defined(__linux__) || defined(__APPLE__) + //fix path separator + ra::strings::Replace(cmdline, "\\", "/"); +#endif + + //build the list of generated files + const char* generated_files_tmp[] = { + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0001.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0002.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0003.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0007.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0008.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0001.cpp", + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0002.cpp", + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0003.cpp", + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0007.cpp", + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0008.cpp", + }; + const size_t num_generated_files = sizeof(generated_files_tmp) / sizeof(generated_files_tmp[0]); + ra::strings::StringVector generated_files; + for ( size_t i = 0; i < num_generated_files; i++ ) + { + generated_files.push_back(generated_files_tmp[i]); +#if defined(__linux__) || defined(__APPLE__) + ra::strings::Replace(generated_files[i], "\\", "/"); //fix path separator +#endif + } + //delete generated files - ASSERT_TRUE(deleteFile(headerFilePath.c_str())); - ASSERT_TRUE(deleteFile(cppFilePath.c_str())); - + for ( size_t i = 0; i < generated_files.size(); i++ ) + { + const std::string& generated_file = generated_files[i]; + ASSERT_TRUE(deleteFile(generated_file.c_str())); + } + //run the command int returnCode = system(cmdline.c_str()); #if defined(__linux__) || defined(__APPLE__) returnCode = WEXITSTATUS(returnCode); #endif - ASSERT_EQ(APP_ERROR_MISSINGARGUMENTS, returnCode) << "The command line '" << cmdline.c_str() << "' returned " << returnCode; - - //load output file - ra::strings::StringVector lines; - bool loaded = ra::filesystem::ReadTextFile(outputFilePath.c_str(), lines); - ASSERT_TRUE(loaded); - - //assert standard output log - ASSERT_TEXT_IN_FILE(true, outputFilePath.c_str(), "Error: Missing arguments (file"); - + ASSERT_EQ(0, returnCode) << "The command line '" << cmdline.c_str() << "' returned " << returnCode; + + //assert that expected files were generated + for ( size_t i = 0; i < generated_files.size(); i++ ) + { + const std::string& generates_file = generated_files[i]; + ASSERT_TRUE(ra::filesystem::FileExists(generates_file.c_str())) << "File not found: '" << generates_file.c_str() << "'."; + } + //cleanup ASSERT_TRUE(deleteFile(outputFilePath.c_str())); + +#undef THIS_TEST_CASE_NAME } - -TEST_F(TestCLI, testErrorMissingArgumentOutput) + +TEST_F(TestCLI, testDirExcludeFilter) +{ + #define THIS_TEST_CASE_NAME "testDirExcludeFilter" + static const std::string expectedFilePath = getExpectedFilePath(); + static const std::string outputFilePath = getActualFilePath(); + + std::string headerFileName = std::string("_") + ra::testing::GetTestCaseName().c_str() + ".h"; + std::string headerFilePath = gGeneratedFilesDir + headerFileName; + std::string cppFilePath = headerFilePath; ra::strings::Replace(cppFilePath, ".h", ".cpp"); + + //build command line + std::string cmdline; + cmdline.append(getBin2cppPath()); + cmdline.append(" --dir=generated_files\\testDir02\\images"); //use windows path separator + cmdline.append(" --output=generated_files\\testDir02\\" THIS_TEST_CASE_NAME); + cmdline.append(" --direxcludefilter=\"*.jpg:*IMG_000[67]*\""); + cmdline.append(" --noheader"); + + cmdline.append(" >"); + cmdline.append(outputFilePath.c_str()); + +#if defined(__linux__) || defined(__APPLE__) + //fix path separator + ra::strings::Replace(cmdline, "\\", "/"); +#endif + + //build the list of generated files + const char* generated_files_tmp[] = { + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0004.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0005.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0008.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0004.cpp", + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0005.cpp", + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0008.cpp", + }; + const size_t num_generated_files = sizeof(generated_files_tmp) / sizeof(generated_files_tmp[0]); + ra::strings::StringVector generated_files; + for ( size_t i = 0; i < num_generated_files; i++ ) + { + generated_files.push_back(generated_files_tmp[i]); +#if defined(__linux__) || defined(__APPLE__) + ra::strings::Replace(generated_files[i], "\\", "/"); //fix path separator +#endif + } + + //delete generated files + for ( size_t i = 0; i < generated_files.size(); i++ ) + { + const std::string& generated_file = generated_files[i]; + ASSERT_TRUE(deleteFile(generated_file.c_str())); + } + + //run the command + int returnCode = system(cmdline.c_str()); +#if defined(__linux__) || defined(__APPLE__) + returnCode = WEXITSTATUS(returnCode); +#endif + ASSERT_EQ(0, returnCode) << "The command line '" << cmdline.c_str() << "' returned " << returnCode; + + //assert that expected files were generated + for ( size_t i = 0; i < generated_files.size(); i++ ) + { + const std::string& generates_file = generated_files[i]; + ASSERT_TRUE(ra::filesystem::FileExists(generates_file.c_str())) << "File not found: '" << generates_file.c_str() << "'."; + } + + //cleanup + ASSERT_TRUE(deleteFile(outputFilePath.c_str())); + +#undef THIS_TEST_CASE_NAME +} + +TEST_F(TestCLI, testDirMultipleFilter) +{ + #define THIS_TEST_CASE_NAME "testDirMultipleFilter" + static const std::string expectedFilePath = getExpectedFilePath(); + static const std::string outputFilePath = getActualFilePath(); + + std::string headerFileName = std::string("_") + ra::testing::GetTestCaseName().c_str() + ".h"; + std::string headerFilePath = gGeneratedFilesDir + headerFileName; + std::string cppFilePath = headerFilePath; ra::strings::Replace(cppFilePath, ".h", ".cpp"); + + //build command line + std::string cmdline; + cmdline.append(getBin2cppPath()); + cmdline.append(" --dir=generated_files\\testDir02\\images"); //use windows path separator + cmdline.append(" --output=generated_files\\testDir02\\" THIS_TEST_CASE_NAME); + cmdline.append(" --dirincludefilter=\"*.jpg:*IMG_000[678].*\""); // includes 1.jpg, 2.jpg, 3.jpg, 6.png, 7.svg 8.svg + cmdline.append(" --direxcludefilter=\"*01*:*07*\""); // excludes 1.jpg and 7.svg + cmdline.append(" --noheader"); + + cmdline.append(" >"); + cmdline.append(outputFilePath.c_str()); + +#if defined(__linux__) || defined(__APPLE__) + //fix path separator + ra::strings::Replace(cmdline, "\\", "/"); +#endif + + //build the list of generated files + const char* generated_files_tmp[] = { + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0002.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0003.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0006.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0008.h" , + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0002.cpp", + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0003.cpp", + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0006.cpp", + "generated_files\\testDir02\\" THIS_TEST_CASE_NAME "\\IMG_0008.cpp", + }; + const size_t num_generated_files = sizeof(generated_files_tmp) / sizeof(generated_files_tmp[0]); + ra::strings::StringVector generated_files; + for ( size_t i = 0; i < num_generated_files; i++ ) + { + generated_files.push_back(generated_files_tmp[i]); +#if defined(__linux__) || defined(__APPLE__) + ra::strings::Replace(generated_files[i], "\\", "/"); //fix path separator +#endif + } + + //delete generated files + for ( size_t i = 0; i < generated_files.size(); i++ ) + { + const std::string& generated_file = generated_files[i]; + ASSERT_TRUE(deleteFile(generated_file.c_str())); + } + + //run the command + int returnCode = system(cmdline.c_str()); +#if defined(__linux__) || defined(__APPLE__) + returnCode = WEXITSTATUS(returnCode); +#endif + ASSERT_EQ(0, returnCode) << "The command line '" << cmdline.c_str() << "' returned " << returnCode; + + //assert that expected files were generated + for ( size_t i = 0; i < generated_files.size(); i++ ) + { + const std::string& generates_file = generated_files[i]; + ASSERT_TRUE(ra::filesystem::FileExists(generates_file.c_str())) << "File not found: '" << generates_file.c_str() << "'."; + } + + //cleanup + ASSERT_TRUE(deleteFile(outputFilePath.c_str())); + +#undef THIS_TEST_CASE_NAME +} + +TEST_F(TestCLI, testErrorMissingArgumentFileOrDir) { static const std::string expectedFilePath = getExpectedFilePath(); static const std::string outputFilePath = getActualFilePath(); @@ -907,9 +1077,9 @@ TEST_F(TestCLI, testErrorMissingArgumentOutput) //build command line std::string cmdline; cmdline.append(getBin2cppPath()); - cmdline.append(" --file="); - cmdline.append(getBin2cppPath()); //itself - //cmdline.append(" --output=generated_files"); + //cmdline.append(" --file="); + //cmdline.append(getBin2cppPath()); //itself + cmdline.append(" --output=generated_files"); cmdline.append(" --headerfile="); cmdline.append(headerFileName); cmdline.append(" --identifier="); @@ -936,13 +1106,13 @@ TEST_F(TestCLI, testErrorMissingArgumentOutput) ASSERT_TRUE(loaded); //assert standard output log - ASSERT_TEXT_IN_FILE(true, outputFilePath.c_str(), "Error: Missing arguments (output)"); + ASSERT_TEXT_IN_FILE(true, outputFilePath.c_str(), "Error: Missing arguments (file"); //cleanup ASSERT_TRUE(deleteFile(outputFilePath.c_str())); } -TEST_F(TestCLI, testErrorMissingArgumentHeaderfile) +TEST_F(TestCLI, testErrorMissingArgumentOutput) { static const std::string expectedFilePath = getExpectedFilePath(); static const std::string outputFilePath = getActualFilePath(); @@ -956,9 +1126,9 @@ TEST_F(TestCLI, testErrorMissingArgumentHeaderfile) cmdline.append(getBin2cppPath()); cmdline.append(" --file="); cmdline.append(getBin2cppPath()); //itself - cmdline.append(" --output=generated_files"); - //cmdline.append(" --headerfile="); - //cmdline.append(headerFileName); + //cmdline.append(" --output=generated_files"); + cmdline.append(" --headerfile="); + cmdline.append(headerFileName); cmdline.append(" --identifier="); cmdline.append(ra::testing::GetTestCaseName().c_str()); cmdline.append(" --noheader"); @@ -983,60 +1153,72 @@ TEST_F(TestCLI, testErrorMissingArgumentHeaderfile) ASSERT_TRUE(loaded); //assert standard output log - ASSERT_TEXT_IN_FILE(true, outputFilePath.c_str(), "Error: Missing arguments (headerfile)"); + ASSERT_TEXT_IN_FILE(true, outputFilePath.c_str(), "Error: Missing arguments (output)"); //cleanup ASSERT_TRUE(deleteFile(outputFilePath.c_str())); } -TEST_F(TestCLI, testErrorMissingArgumentIdentifier) +TEST_F(TestCLI, testAutomaticIdentifierHeaderfile) { static const std::string expectedFilePath = getExpectedFilePath(); static const std::string outputFilePath = getActualFilePath(); - std::string headerFileName = std::string("_") + ra::testing::GetTestCaseName().c_str() + ".h"; + static const std::string bin2cppPath = getBin2cppPath(); + + std::string headerFileName = ra::filesystem::GetFilenameWithoutExtension(bin2cppPath.c_str()) + ".h"; std::string headerFilePath = gGeneratedFilesDir + headerFileName; std::string cppFilePath = headerFilePath; ra::strings::Replace(cppFilePath, ".h", ".cpp"); - + + //build the expected generated class + std::string expectedClassDeclaration; + std::string name = ra::filesystem::GetFilenameWithoutExtension(bin2cppPath.c_str()); + std::string ext = ra::filesystem::GetFileExtention(bin2cppPath.c_str()); + name = ra::strings::CapitalizeFirstCharacter(name); + ext = ra::strings::CapitalizeFirstCharacter(ext ); + expectedClassDeclaration = "class "; + expectedClassDeclaration += (name + ext); + expectedClassDeclaration += "File"; + ra::strings::Replace(expectedClassDeclaration, ".", ""); // remove the dot from bin2cpp.exe on Windows + ra::strings::Replace(expectedClassDeclaration, "-", ""); // remove the dash from bin2cpp-d.exe on Windows + //build command line std::string cmdline; cmdline.append(getBin2cppPath()); cmdline.append(" --file="); - cmdline.append(getBin2cppPath()); //itself + cmdline.append(bin2cppPath); //itself cmdline.append(" --output=generated_files"); - cmdline.append(" --headerfile="); - cmdline.append(headerFileName); - //cmdline.append(" --identifier="); - //cmdline.append(ra::testing::GetTestCaseName().c_str()); cmdline.append(" --noheader"); cmdline.append(" >"); cmdline.append(outputFilePath.c_str()); //delete generated files + ASSERT_TRUE(deleteFile(outputFilePath.c_str())); ASSERT_TRUE(deleteFile(headerFilePath.c_str())); ASSERT_TRUE(deleteFile(cppFilePath.c_str())); - + //run the command int returnCode = system(cmdline.c_str()); #if defined(__linux__) || defined(__APPLE__) returnCode = WEXITSTATUS(returnCode); #endif - ASSERT_EQ(APP_ERROR_MISSINGARGUMENTS, returnCode) << "The command line '" << cmdline.c_str() << "' returned " << returnCode; - - //load output file - ra::strings::StringVector lines; - bool loaded = ra::filesystem::ReadTextFile(outputFilePath.c_str(), lines); - ASSERT_TRUE(loaded); + ASSERT_EQ(0, returnCode) << "The command line '" << cmdline.c_str() << "' returned " << returnCode; - //assert standard output log - ASSERT_TEXT_IN_FILE(true, outputFilePath.c_str(), "Error: Missing arguments (identifier)"); + //assert generated code + ASSERT_TRUE(ra::filesystem::FileExists(headerFilePath.c_str())); + ASSERT_TRUE(ra::filesystem::FileExists(cppFilePath.c_str())); + + //assert content properly generated + ASSERT_TEXT_IN_FILE(true, cppFilePath.c_str(), expectedClassDeclaration.c_str()); //cleanup ASSERT_TRUE(deleteFile(outputFilePath.c_str())); + ASSERT_TRUE(deleteFile(headerFilePath.c_str())); + ASSERT_TRUE(deleteFile(cppFilePath.c_str())); } -TEST_F(TestCLI, testErrorMissingArgumentEncoding) +TEST_F(TestCLI, testErrorInvalidArgumentEncoding) { static const std::string expectedFilePath = getExpectedFilePath(); static const std::string outputFilePath = getActualFilePath(); @@ -1070,7 +1252,7 @@ TEST_F(TestCLI, testErrorMissingArgumentEncoding) #if defined(__linux__) || defined(__APPLE__) returnCode = WEXITSTATUS(returnCode); #endif - ASSERT_EQ(APP_ERROR_MISSINGARGUMENTS, returnCode) << "The command line '" << cmdline.c_str() << "' returned " << returnCode; + ASSERT_EQ(APP_ERROR_INVALIDVALUE, returnCode) << "The command line '" << cmdline.c_str() << "' returned " << returnCode; //load output file ra::strings::StringVector lines; @@ -1078,7 +1260,7 @@ TEST_F(TestCLI, testErrorMissingArgumentEncoding) ASSERT_TRUE(loaded); //assert standard output log - ASSERT_TEXT_IN_FILE(true, outputFilePath.c_str(), "Error: Missing arguments (encoding)"); + ASSERT_TEXT_IN_FILE(true, outputFilePath.c_str(), "Error: Invalid value (encoding)"); //cleanup ASSERT_TRUE(deleteFile(outputFilePath.c_str())); @@ -1732,3 +1914,225 @@ TEST_F(TestCLI, testRegisterFileAllGenerators) ASSERT_TRUE(deleteFile(backupCppFile2.c_str())); } } + +TEST_F(TestCLI, testKeepDirectories) +{ + static const std::string expectedFilePath = getExpectedFilePath(); + static const std::string outputFilePath = getActualFilePath(); + + //build command line + std::string cmdline; + cmdline.append(getBin2cppPath()); + cmdline.append(" --dir=generated_files\\testKeepDirectories\\input_files"); //use windows path separator + cmdline.append(" --output=generated_files\\testKeepDirectories\\generated_sources"); + cmdline.append(" --noheader --managerfile=FileManagerKeepDirs.h --registerfile --namespace=testkeepdirs --override --keepdirs"); + + cmdline.append(" >"); + cmdline.append(outputFilePath.c_str()); + +#if defined(__linux__) || defined(__APPLE__) + //fix path separator + ra::strings::Replace(cmdline, "\\", "/"); +#endif + + //build the list of generated files + const char * generated_files_tmp[] = { + "generated_files\\testKeepDirectories\\generated_sources\\FileManagerKeepDirs.cpp", + "generated_files\\testKeepDirectories\\generated_sources\\FileManagerKeepDirs.h", + "generated_files\\testKeepDirectories\\generated_sources\\www\\index.cpp", + "generated_files\\testKeepDirectories\\generated_sources\\www\\index.h", + "generated_files\\testKeepDirectories\\generated_sources\\www\\blog\\index.cpp", + "generated_files\\testKeepDirectories\\generated_sources\\www\\blog\\index.h", + "generated_files\\testKeepDirectories\\generated_sources\\www\\blog\\how-to-create-a-web-site\\index.cpp", + "generated_files\\testKeepDirectories\\generated_sources\\www\\blog\\how-to-create-a-web-site\\index.h", + "generated_files\\testKeepDirectories\\generated_sources\\www\\blog\\using-bin2cpp\\index.cpp", + "generated_files\\testKeepDirectories\\generated_sources\\www\\blog\\using-bin2cpp\\index.h", + "generated_files\\testKeepDirectories\\generated_sources\\www\\contact\\index.cpp", + "generated_files\\testKeepDirectories\\generated_sources\\www\\contact\\index.h", + "generated_files\\testKeepDirectories\\generated_sources\\www\\home\\index.cpp", + "generated_files\\testKeepDirectories\\generated_sources\\www\\home\\index.h", + }; + const size_t num_generated_files = sizeof(generated_files_tmp)/sizeof(generated_files_tmp[0]); + ra::strings::StringVector generated_files; + for(size_t i=0; i"); + cmdline.append(outputFilePath.c_str()); + + //delete generated files + ASSERT_TRUE(deleteFile(outputFilePath.c_str())); + + //run the command + int returnCode = system(cmdline.c_str()); +#if defined(__linux__) || defined(__APPLE__) + returnCode = WEXITSTATUS(returnCode); +#endif + ASSERT_EQ(0, returnCode) << "The command line '" << cmdline.c_str() << "' returned " << returnCode; + + //assert generated code + ASSERT_TRUE(ra::filesystem::FileExists(outputFilePath.c_str())); + + //load output file + std::string content; + bool loaded = ra::filesystem::ReadTextFile(outputFilePath.c_str(), content); + ASSERT_TRUE(loaded); + + //assert content is a string and not c++ code + ASSERT_EQ('\"', content[0]); + ASSERT_EQ('\"', content[content.size()-1]); + + //cleanup + ASSERT_TRUE(deleteFile(outputFilePath.c_str())); +} + +TEST_F(TestCLI, testPlainOutputGenerators) +{ + static const std::string expectedFilePath = getExpectedFilePath(); + static const std::string outputFilePath = getActualFilePath(); + + static const std::string WIN32_GENERATOR_NAME = "win32"; + static const std::string SEGMENT_GENERATOR_NAME = "segment"; + static const std::string STRING_GENERATOR_NAME = "string"; + + //define all command line generators + std::vector generators; + generators.push_back("segment"); + generators.push_back("string"); + generators.push_back("array"); + generators.push_back("win32"); + + //generate output for each generators + std::vector files; + for(size_t genIndex = 0; genIndex"); + cmdline.append(generatorOutputFilePath.c_str()); + + //run the command + int returnCode = system(cmdline.c_str()); +#if defined(__linux__) || defined(__APPLE__) + returnCode = WEXITSTATUS(returnCode); +#endif + if (WIN32_GENERATOR_NAME == generatorName) + { + ASSERT_NE(0, returnCode) << "The command line '" << cmdline.c_str() << "' was expected to fail but returned " << returnCode; + + //remember this generated file + files.push_back(generatorOutputFilePath); + } + else + { + ASSERT_EQ(0, returnCode) << "The command line '" << cmdline.c_str() << "' returned " << returnCode; + + //remember this generated file + files.push_back(generatorOutputFilePath); + + //assert generated code + ASSERT_TRUE(ra::filesystem::FileExists(generatorOutputFilePath.c_str())); + + //load output file + std::string content; + bool loaded = ra::filesystem::ReadTextFile(generatorOutputFilePath.c_str(), content); + ASSERT_TRUE(loaded); + + //assert content is a string and not c++ code + ASSERT_EQ('\"', content[0]); + ASSERT_EQ('\"', content[content.size()-1]); + } + } + + //assert all files different + if (files.size() >= 2) + { + for(size_t i=0; i expected_values; + }; + static const char SEPARATOR = ':'; + + // arrange + static const TEST_HELPER test_values[] = { + {SEPARATOR, "", {""}}, // empty string + {SEPARATOR, "abc", {"abc"}}, // no separator + {SEPARATOR, "a:b:c", {"a", "b", "c"}}, // multiple + {SEPARATOR, ":b:c", {"", "b", "c"}}, // start with separator + {SEPARATOR, "a:b:", {"a", "b", ""}}, // end with separator + {SEPARATOR, "a::", {"a", "", ""}}, // 2 consecutive separators + {SEPARATOR, "::", {"", "", ""}}, // only consecutive separators + }; + static const size_t num_test_values = sizeof(test_values) / sizeof(test_values[0]); + + // act (strSplit) + for ( size_t i = 0; i < num_test_values; i++ ) + { + const TEST_HELPER& t = test_values[i]; + + std::vector actual_values; + bin2cpp::strSplit(t.value, t.separator, actual_values); + + // assert + ASSERT_EQ(actual_values, t.expected_values) << "Test fail for strSplit() with test_values[" << i << "]. Splitting value `" << t.value << "` with separator '" << t.separator << "' should result in " << t.expected_values.size() << " elements."; + } + + // act (strJoin) + for ( size_t i = 0; i < num_test_values; i++ ) + { + const TEST_HELPER& t = test_values[i]; + + std::vector tmp_values; + bin2cpp::strSplit(t.value, t.separator, tmp_values); + + std::string expected_value = t.value; + std::string actual_value = bin2cpp::strJoin(tmp_values, t.separator); + + // assert + ASSERT_EQ(actual_value, expected_value) << "Test fail for strJoin() with test_values[" << i << "]. Joining values with separator '" << t.separator << "' should result in `" << expected_value << "` but we got `" << actual_value << "`."; + } +} diff --git a/test/bin2cpp_unittest/TestCommon.h b/test/bin2cpp_unittest/TestCommon.h new file mode 100644 index 0000000..e12cc9e --- /dev/null +++ b/test/bin2cpp_unittest/TestCommon.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 TESTCOMMON_H +#define TESTCOMMON_H + +#include + +class TestCommon : public ::testing::Test +{ +public: + virtual void SetUp(); + virtual void TearDown(); +}; + +#endif //TESTCOMMON_H diff --git a/test/bin2cpp_unittest/TestExtraction.cpp b/test/bin2cpp_unittest/TestExtraction.cpp index b8573a5..3e527e6 100755 --- a/test/bin2cpp_unittest/TestExtraction.cpp +++ b/test/bin2cpp_unittest/TestExtraction.cpp @@ -56,13 +56,31 @@ #include "testIssue13/_testIssue13.h" #include "testIssue47/generated/_testIssue47.h" #include "testIssue50/_testIssue50.h" +#include "testIssue50/_testIssue50.h" +#include "testIssue56a/compiled_sources/_testIssue56a.index.1234.h" +#include "testIssue56a/compiled_sources/_testIssue56a.index.4321.h" +#include "testReportedPathFile1/_testReportedPathFile1.h" +#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" +{ + #include "testGeneratorArray10000_C/_testGeneratorArray10000_C.h" + #include "testGeneratorSegment10000_C/_testGeneratorSegment10000_C.h" + #include "testGeneratorString10000_C/_testGeneratorString10000_C.h" + #ifdef _WIN32 + #include "testGeneratorWin32_C/_testGeneratorWin32_C.h" + #endif + #include "testNamespace_C/_testNamespace_C.h" + #include "testBaseClass_C/_testBaseClass_C.h" +} + extern const std::string & gGeneratedFilesDir; namespace TestExtractionUtils @@ -108,7 +126,7 @@ TEST_F(TestExtraction, testText10) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -123,7 +141,7 @@ TEST_F(TestExtraction, testText1000) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -138,7 +156,7 @@ TEST_F(TestExtraction, testText100000) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -153,7 +171,7 @@ TEST_F(TestExtraction, testHtml100000) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -168,7 +186,7 @@ TEST_F(TestExtraction, testRandom1) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -183,7 +201,7 @@ TEST_F(TestExtraction, testRandom2) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -198,7 +216,7 @@ TEST_F(TestExtraction, testRandom3) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -213,7 +231,7 @@ TEST_F(TestExtraction, testRandom4) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -228,7 +246,7 @@ TEST_F(TestExtraction, testRandom5) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -243,7 +261,7 @@ TEST_F(TestExtraction, testRandom6) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -258,7 +276,7 @@ TEST_F(TestExtraction, testRandom7) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -273,7 +291,7 @@ TEST_F(TestExtraction, testRandom8) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -288,7 +306,7 @@ TEST_F(TestExtraction, testSequential1000) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -303,7 +321,7 @@ TEST_F(TestExtraction, testSequential10MB) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -318,7 +336,22 @@ TEST_F(TestExtraction, testGeneratorArray10000) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same + std::string reason; + bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); + ASSERT_TRUE(equal) << reason.c_str(); +} + +TEST_F(TestExtraction, testGeneratorArray10000_C) +{ + static const std::string expectedFilePath = getExpectedFilePath(); + static const std::string outputFilePath = getActualFilePath(); + + Bin2cFile* file = bin2c_get_file_testgeneratorarray10000_c(); + bool extractSuccess = file->save(outputFilePath.c_str()); + ASSERT_TRUE(extractSuccess); + + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -333,7 +366,22 @@ TEST_F(TestExtraction, testGeneratorSegment10000) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same + std::string reason; + bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); + ASSERT_TRUE(equal) << reason.c_str(); +} + +TEST_F(TestExtraction, testGeneratorSegment10000_C) +{ + static const std::string expectedFilePath = getExpectedFilePath(); + static const std::string outputFilePath = getActualFilePath(); + + const Bin2cFile* file = bin2c_get_file_testgeneratorsegment10000_c(); + bool extractSuccess = file->save(outputFilePath.c_str()); + ASSERT_TRUE(extractSuccess); + + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -348,7 +396,22 @@ TEST_F(TestExtraction, testGeneratorString10000) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same + std::string reason; + bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); + ASSERT_TRUE(equal) << reason.c_str(); +} + +TEST_F(TestExtraction, testGeneratorString10000_C) +{ + static const std::string expectedFilePath = getExpectedFilePath(); + static const std::string outputFilePath = getActualFilePath(); + + const Bin2cFile* file = bin2c_get_file_testgeneratorstring10000_c(); + bool extractSuccess = file->save(outputFilePath.c_str()); + ASSERT_TRUE(extractSuccess); + + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -364,7 +427,22 @@ TEST_F(TestExtraction, testGeneratorWin32) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same + std::string reason; + bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); + ASSERT_TRUE(equal) << reason.c_str(); +} + +TEST_F(TestExtraction, testGeneratorWin32_C) +{ + static const std::string expectedFilePath = getExpectedFilePath(); + static const std::string outputFilePath = getActualFilePath(); + + const Bin2cFile* file = bin2c_get_file_testgeneratorwin32_c(); + bool extractSuccess = file->save(outputFilePath.c_str()); + ASSERT_TRUE(extractSuccess); + + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -380,7 +458,7 @@ TEST_F(TestExtraction, testEncodingOct) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -395,7 +473,7 @@ TEST_F(TestExtraction, testEncodingHex) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -410,7 +488,22 @@ TEST_F(TestExtraction, testNamespace) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same + std::string reason; + bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); + ASSERT_TRUE(equal) << reason.c_str(); +} + +TEST_F(TestExtraction, testNamespace_C) +{ + static const std::string expectedFilePath = getExpectedFilePath(); + static const std::string outputFilePath = getActualFilePath(); + + const Bin2cFile2* file = foobar_get_file_testnamespace_c(); + bool extractSuccess = file->save(outputFilePath.c_str()); + ASSERT_TRUE(extractSuccess); + + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -425,7 +518,22 @@ TEST_F(TestExtraction, testBaseClass) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same + std::string reason; + bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); + ASSERT_TRUE(equal) << reason.c_str(); +} + +TEST_F(TestExtraction, testBaseClass_C) +{ + static const std::string expectedFilePath = getExpectedFilePath(); + static const std::string outputFilePath = getActualFilePath(); + + const Resource* file = tbc_get_file_testbaseclass_c(); + bool extractSuccess = file->save(outputFilePath.c_str()); + ASSERT_TRUE(extractSuccess); + + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -440,7 +548,7 @@ TEST_F(TestExtraction, testIssue12) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -455,7 +563,7 @@ TEST_F(TestExtraction, testIssue12Mini) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -470,7 +578,7 @@ TEST_F(TestExtraction, testIssue13) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -485,7 +593,7 @@ TEST_F(TestExtraction, testIssue47) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -522,7 +630,7 @@ TEST_F(TestExtraction, testIssue50) bool extractSuccess = file.save(outputFilePath.c_str()); ASSERT_TRUE(extractSuccess); - //assert content is the same + //assert binary content is the same std::string reason; bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); ASSERT_TRUE(equal) << reason.c_str(); @@ -537,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 @@ -545,7 +653,155 @@ 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) ); } } + +TEST_F(TestExtraction, testIssue56a) +{ + //save _testIssue56a.index.1234.css + std::string output_path1234 = "generated_files/testIssue56a/saved_files/_testIssue56a.index.1234.css"; + { + ra::filesystem::NormalizePath(output_path1234); + const issue56a::File & file = issue56a::get_testIssue56aindex1234CssFile(); + bool extractSuccess = file.save(output_path1234.c_str()); + ASSERT_TRUE(extractSuccess); + } + + //save _testIssue56a.index.4321.css + std::string output_path4321 = "generated_files/testIssue56a/saved_files/_testIssue56a.index.4321.css"; + { + ra::filesystem::NormalizePath(output_path4321); + const issue56a::File & file = issue56a::get_testIssue56aindex4321CssFile(); + bool extractSuccess = file.save(output_path4321.c_str()); + ASSERT_TRUE(extractSuccess); + } + + //assert binary content is the same + std::string reason; + std::string expected_path1234 = "generated_files/testIssue56a/input_files/_testIssue56a.index.1234.css"; + ra::filesystem::NormalizePath(expected_path1234); + bool equal1234 = ra::testing::IsFileEquals(expected_path1234.c_str(), output_path1234.c_str(), reason); + ASSERT_TRUE(equal1234) << reason.c_str(); + + std::string expected_path4321 = "generated_files/testIssue56a/input_files/_testIssue56a.index.4321.css"; + ra::filesystem::NormalizePath(expected_path4321); + bool equal4321 = ra::testing::IsFileEquals(expected_path4321.c_str(), output_path4321.c_str(), reason); + ASSERT_TRUE(equal4321) << reason.c_str(); + + //assert correct identifiers + + int line = 0; + int index = 0; + + //_testIssue56a.index.1234.h + { + std::string path = "generated_files/testIssue56a/compiled_sources/_testIssue56a.index.1234.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(), "get_testIssue56aindex1234CssFile()", line, index) ); + } + + //_testIssue56a.index.4321.h + { + std::string path = "generated_files/testIssue56a/compiled_sources/_testIssue56a.index.4321.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(), "get_testIssue56aindex4321CssFile()", line, index) ); + } +} + +TEST_F(TestExtraction, testDeprecatedGetFilename) +{ + const testReportedPathFile1::File & file = testReportedPathFile1::getTestReportedPathFile1File(); + ASSERT_TRUE( file.getFileName() != NULL ); + ASSERT_TRUE( file.getFilename() != NULL ); + ASSERT_EQ(0, strcmp(file.getFileName(), file.getFilename()) ); +} + +TEST_F(TestExtraction, testReportedPathFile1) +{ + const testReportedPathFile1::File & file = testReportedPathFile1::getTestReportedPathFile1File(); + + // @BIN2CPP_TARGET_FILE@ --noheader --file=.\generated_files\testReportedPathFile1\testReportedPathFile1.bin + // --output=.\generated_files\testReportedPathFile1 --chunksize=50 + // --headerfile=_testReportedPathFile1.h --identifier=testReportedPathFile1 + // --namespace=testReportedPathFile1 --override --reportedfilepath=foo\bar\testReportedPathFile1.bin + + std::string actual_file_name = file.getFileName(); + std::string expected_file_name = "testReportedPathFile1.bin"; + ASSERT_EQ(expected_file_name, actual_file_name); + + std::string actual_file_path = file.getFilePath(); + std::string expected_file_path = "foo\\bar\\testReportedPathFile1.bin"; + ra::filesystem::NormalizePath(expected_file_path); + ASSERT_EQ(expected_file_path, actual_file_path); +} + +TEST_F(TestExtraction, testReportedPathFile2) +{ + const testReportedPathFile2::File & file = testReportedPathFile2::getTestReportedPathFile2File(); + + // @BIN2CPP_TARGET_FILE@ --noheader --file=.\generated_files\testReportedPathFile2\testReportedPathFile2.bin + // --output=.\generated_files\testReportedPathFile2 --chunksize=50 + // --headerfile=_testReportedPathFile2.h --identifier=testReportedPathFile2 + // --namespace=testReportedPathFile2 --override --reportedfilepath=ham\eggs\breakfast.bin + + std::string actual_file_name = file.getFileName(); + std::string expected_file_name = "testReportedPathFile2.bin"; + ASSERT_EQ(expected_file_name, actual_file_name); + + std::string actual_file_path = file.getFilePath(); + std::string expected_file_path = "ham\\eggs\\breakfast.bin"; + ra::filesystem::NormalizePath(expected_file_path); + ASSERT_EQ(expected_file_path, actual_file_path); +} + +TEST_F(TestExtraction, testReportedPathDir) +{ + testReportedPathDir::FileManager & mgr = testReportedPathDir::FileManager::getInstance(); + + std::string expected_path; + expected_path += "www"; + expected_path += ra::filesystem::GetPathSeparatorStr(); + + size_t count = mgr.getFileCount(); + for(size_t i=0; igetFilePath(); + + //assert in www directory + ASSERT_EQ( 0, file_path.compare(0, expected_path.size(), expected_path) ) << "file_path=" << file_path; + } +} + +TEST_F(TestExtraction, testFileSave) +{ + std::string expectedFilePath = "generated_files/testEncodingHex/testEncodingHex.bin"; + std::string outputFilePath = "generated_files/testEncodingHex/testEncodingHex.output"; + ra::filesystem::NormalizePath(expectedFilePath); + ra::filesystem::NormalizePath(outputFilePath ); + + const bin2cpp::File & file = bin2cpp::getTestEncodingHexFile(); + bool extractSuccess = file.save(outputFilePath.c_str()); + ASSERT_TRUE(extractSuccess); + + //change the content of the file + ra::testing::ChangeFileContent(outputFilePath.c_str(), 0, 'T'); + ra::testing::ChangeFileContent(outputFilePath.c_str(), 1, 'E'); + ra::testing::ChangeFileContent(outputFilePath.c_str(), 2, 'S'); + ra::testing::ChangeFileContent(outputFilePath.c_str(), 3, 'T'); + + //assert calling save() when the file already exists should replace the content + extractSuccess = file.save(outputFilePath.c_str()); + ASSERT_TRUE(extractSuccess); + + //assert binary content is the same + std::string reason; + bool equal = ra::testing::IsFileEquals(expectedFilePath.c_str(), outputFilePath.c_str(), reason); + ASSERT_TRUE(equal) << reason.c_str(); + +} 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 diff --git a/test/bin2cpp_unittest/TestWildcard.cpp b/test/bin2cpp_unittest/TestWildcard.cpp new file mode 100644 index 0000000..95d5d95 --- /dev/null +++ b/test/bin2cpp_unittest/TestWildcard.cpp @@ -0,0 +1,188 @@ +/********************************************************************************** + * 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 "TestWildcard.h" + +#include "wildcard.h" + +void TestWildcard::SetUp() +{ +} + +void TestWildcard::TearDown() +{ +} + +std::string to_boolean_str(bool value) +{ + return (value ? "true" : "false"); +} + +TEST_F(TestWildcard, testBasicExamples) +{ + struct TEST_HELPER + { + const char* value; + const char* pattern; + bool expected_result; + std::vector expected_captures; + }; + static const TEST_HELPER test_values[] = { + // ============================== matches ============================== + // ? + {"a", "?", true, {"a"}}, + {"abc", "???", true, {"a", "b", "c"}}, + {"kernel32.dll", "kernel??.dll", true, {"3", "2"}}, + {"kernel32.dll", "kernel32.???", true, {"d", "l", "l"}}, + {"kernel32.dll", "???nel32.dll", true, {"k", "e", "r"}}, + + // * + {"kernel32.dll", "*", true, {"kernel32.dll"}}, + {"kernel32.dll", "ker*.dll", true, {"nel32"}}, + {"kernel32.dll", "kernel32.*", true, {"dll"}}, + {"kernel32.dll", "*.dll", true, {"kernel32"}}, + + // empty '*' wildcard + {"kernel32.dll", "*kernel32.dll", true, {""}}, + {"kernel32.dll", "kernel32*.dll", true, {""}}, + {"kernel32.dll", "kernel32.dll*", true, {""}}, + + // # + {"kernel32.dll", "kernel##.dll", true, {"3", "2"}}, + + // [abc] + {"kernel32.dll", "[Kk]ernel32.dll", true, {"k"}}, + {"kernel32.dll", "kernel32.[dD][lL][lL]", true, {"d", "l", "l"}}, + {"kernel32.dll", "ke[r]nel32.dll", true, {"r"}}, + + // [ranges] + {"kernel32.dll", "kernel[0-9][0-9].dll", true, {"3", "2"}}, + {"kernel32.dll", "kernel32.[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]", true, {"d", "l", "l"}}, + + // complex, multiple wildcard + {"kernel32.dll", "ker*.*", true, {"nel32", "dll"}}, + {"kernel32.dll", "*##.???", true, {"kernel", "3", "2", "d", "l", "l"}}, + {"aabbccdd", "*??*dd", true, {"", "a", "a", "bbcc"}}, + + // ============================== failing matches ============================== + {"kernel32.dll", "ker*.txt", false, {}}, + + // too many '?' character + {"kernel32.dll", "kernel32?.dll", false, {}}, + {"kernel32.dll", "kernel32.dll?", false, {}}, + {"kernel32.dll", "?kernel32.dll", false, {}}, + + {"kernel32.dll", "k##nel32.dll", false, {}}, + {"kernel32.dll", "[aA]ernel32.dll", false, {}}, + {"kernel32.dll", "k[0-9]ernel32.dll", false, {}}, + {"!", "[a-zA-Z0-9]", false, {}}, + }; + static const size_t num_test_values = sizeof(test_values) / sizeof(test_values[0]); + + for ( size_t i = 0; i < num_test_values; i++ ) + { + const TEST_HELPER& t = test_values[i]; + + std::vector actual_captures; + bool actual_result = bin2cpp::wildcard_match(t.value, t.pattern, actual_captures); + + ASSERT_EQ(actual_result, t.expected_result) << "Test fail with test_values[" << i << "]. The match between value '" << t.value << "' and pattern '" << t.pattern << "' is supposed to return '" << to_boolean_str(t.expected_result) << "' but it actually retuned '" << to_boolean_str(actual_result) << "'."; + ASSERT_EQ(actual_captures, t.expected_captures) << "Test fail with test_values[" << i << "]. The match between value '" << t.value << "' and pattern '" << t.pattern << "' is has returned '" << to_boolean_str(t.expected_result) << "' but the expected captures does not match."; + } +} + +TEST_F(TestWildcard, testWildcardMatchAny) +{ + const std::string path = "path/to/a/file.jpg"; + std::vector patterns; + + { + // test for no matches + patterns.clear(); + patterns.push_back("idonotmatch"); + patterns.push_back("idonotmatcheither"); + + ASSERT_FALSE(bin2cpp::wildcard_match_any(path, patterns)); + } + + { + // test matches from first element + patterns.clear(); + patterns.push_back("*.jpg"); + patterns.push_back("idonotmatch"); + + ASSERT_TRUE(bin2cpp::wildcard_match_any(path, patterns)); + } + + { + // test matches from second element + patterns.clear(); + patterns.push_back("idonotmatch"); + patterns.push_back("*.jpg"); + + ASSERT_TRUE(bin2cpp::wildcard_match_any(path, patterns)); + } +} + +TEST_F(TestWildcard, testWildcardMatchAll) +{ + const std::string path = "path/to/a/file.jpg"; + std::vector patterns; + + { + // test for no matches + patterns.clear(); + patterns.push_back("idonotmatch"); + patterns.push_back("idonotmatcheither"); + + ASSERT_FALSE(bin2cpp::wildcard_match_all(path, patterns)); + } + + { + // test matches from first element + patterns.clear(); + patterns.push_back("*.jpg"); + patterns.push_back("idonotmatch"); + + ASSERT_FALSE(bin2cpp::wildcard_match_all(path, patterns)); + } + + { + // test matches from second element + patterns.clear(); + patterns.push_back("idonotmatch"); + patterns.push_back("*.jpg"); + + ASSERT_FALSE(bin2cpp::wildcard_match_all(path, patterns)); + } + + { + // test matches from all elements + patterns.clear(); + patterns.push_back("*/to/*"); + patterns.push_back("*.jpg"); + + ASSERT_TRUE(bin2cpp::wildcard_match_all(path, patterns)); + } +} \ No newline at end of file diff --git a/test/bin2cpp_unittest/TestWildcard.h b/test/bin2cpp_unittest/TestWildcard.h new file mode 100644 index 0000000..ece6a3f --- /dev/null +++ b/test/bin2cpp_unittest/TestWildcard.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 TESTWILDCARD_H +#define TESTWILDCARD_H + +#include + +class TestWildcard : public ::testing::Test +{ +public: + virtual void SetUp(); + virtual void TearDown(); +}; + +#endif //TESTWILDCARD_H diff --git a/test/bin2cpp_unittest/generate_test_files.bat.in b/test/bin2cpp_unittest/generate_test_files.bat.in old mode 100755 new mode 100644 index 10c82b7..13708da --- a/test/bin2cpp_unittest/generate_test_files.bat.in +++ b/test/bin2cpp_unittest/generate_test_files.bat.in @@ -1,5 +1,7 @@ @echo off +echo SCRIPT GENERATE_TEST_FILES - START + set TEST_NAME=testText10 set OUTDIR=.\generated_files\%TEST_NAME% mkdir %OUTDIR% 1>NUL 2>NUL @@ -119,6 +121,13 @@ mkdir %OUTDIR% 1>NUL 2>NUL @BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=array --override if %errorlevel% neq 0 exit /b %errorlevel% +set TEST_NAME=testGeneratorArray10000_C +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\%TEST_NAME%.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=array --override --code=c +if %errorlevel% neq 0 exit /b %errorlevel% + set TEST_NAME=testGeneratorString10000 set OUTDIR=.\generated_files\%TEST_NAME% mkdir %OUTDIR% 1>NUL 2>NUL @@ -126,6 +135,13 @@ mkdir %OUTDIR% 1>NUL 2>NUL @BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=string --override if %errorlevel% neq 0 exit /b %errorlevel% +set TEST_NAME=testGeneratorString10000_C +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\%TEST_NAME%.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=string --override --code=c +if %errorlevel% neq 0 exit /b %errorlevel% + set TEST_NAME=testGeneratorSegment10000 set OUTDIR=.\generated_files\%TEST_NAME% mkdir %OUTDIR% 1>NUL 2>NUL @@ -133,6 +149,13 @@ mkdir %OUTDIR% 1>NUL 2>NUL @BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=segment --override if %errorlevel% neq 0 exit /b %errorlevel% +set TEST_NAME=testGeneratorSegment10000_C +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\%TEST_NAME%.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=segment --override --code=c +if %errorlevel% neq 0 exit /b %errorlevel% + set TEST_NAME=testGeneratorWin32 set OUTDIR=.\generated_files\%TEST_NAME% mkdir %OUTDIR% 1>NUL 2>NUL @@ -140,6 +163,13 @@ mkdir %OUTDIR% 1>NUL 2>NUL @BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=win32 --override if %errorlevel% neq 0 exit /b %errorlevel% +set TEST_NAME=testGeneratorWin32_C +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\%TEST_NAME%.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=win32 --override --code=c +if %errorlevel% neq 0 exit /b %errorlevel% + set TEST_NAME=testNamespace set OUTDIR=.\generated_files\%TEST_NAME% mkdir %OUTDIR% 1>NUL 2>NUL @@ -147,6 +177,13 @@ mkdir %OUTDIR% 1>NUL 2>NUL @BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=segment --override --namespace=foobar if %errorlevel% neq 0 exit /b %errorlevel% +set TEST_NAME=testNamespace_C +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\%TEST_NAME%.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=segment --override --baseclass=Bin2cFile2 --namespace=foobar --code=c +if %errorlevel% neq 0 exit /b %errorlevel% + set TEST_NAME=testBaseClass set OUTDIR=.\generated_files\%TEST_NAME% mkdir %OUTDIR% 1>NUL 2>NUL @@ -154,6 +191,13 @@ mkdir %OUTDIR% 1>NUL 2>NUL @BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=segment --override --baseclass=Resource if %errorlevel% neq 0 exit /b %errorlevel% +set TEST_NAME=testBaseClass_C +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\%TEST_NAME%.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --chunksize=450 --generator=segment --override --baseclass=Resource --namespace=tbc --code=c +if %errorlevel% neq 0 exit /b %errorlevel% + set TEST_NAME=testEncodingOct set OUTDIR=.\generated_files\%TEST_NAME% mkdir %OUTDIR% 1>NUL 2>NUL @@ -199,6 +243,15 @@ mkdir %OUTDIR% 1>NUL 2>NUL @BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.2.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.2.h --identifier=%TEST_NAME%2 --registerfile --override if %errorlevel% neq 0 exit /b %errorlevel% +set TEST_NAME=testFileManager_C +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\%TEST_NAME%.1.bin --size=1000 --fill=random --seed=1 +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\%TEST_NAME%.2.bin --size=1000 --fill=random --seed=2 +@BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.1.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.1.h --identifier=%TEST_NAME%1 --managerfile=filemanager.h --override --code=c +@BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.2.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.2.h --identifier=%TEST_NAME%2 --registerfile --override --code=c +if %errorlevel% neq 0 exit /b %errorlevel% + set TEST_NAME=testDir01 set OUTDIR=.\generated_files\%TEST_NAME% mkdir %OUTDIR% 1>NUL 2>NUL @@ -220,6 +273,22 @@ if %errorlevel% neq 0 exit /b %errorlevel% @BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\images\IMG_0005.jpg --output=%OUTDIR%\sources --headerfile=_img0005.h --identifier=Img0005 --chunksize=200 --override if %errorlevel% neq 0 exit /b %errorlevel% +set TEST_NAME=testDir02 +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +mkdir %OUTDIR%\images 1>NUL 2>NUL +mkdir %OUTDIR%\testDirIncludeFilter 1>NUL 2>NUL +mkdir %OUTDIR%\testDirExcludeFilter 1>NUL 2>NUL +mkdir %OUTDIR%\testDirMultipleFilter 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\images\IMG_0001.jpg --size=1010 --fill=random --seed=1 +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\images\IMG_0002.jpg --size=1020 --fill=random --seed=2 +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\images\IMG_0003.jpg --size=1030 --fill=random --seed=3 +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\images\IMG_0004.png --size=1040 --fill=random --seed=4 +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\images\IMG_0005.png --size=1050 --fill=random --seed=5 +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\images\IMG_0006.png --size=1060 --fill=random --seed=6 +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\images\IMG_0007.svg --size=0170 --fill=html --seed=7 +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\images\IMG_0008.svg --size=0180 --fill=html --seed=8 + set TEST_NAME=testIssue47 set OUTDIR=.\generated_files\%TEST_NAME% mkdir %OUTDIR% 1>NUL 2>NUL @@ -235,4 +304,116 @@ mkdir %OUTDIR% 1>NUL 2>NUL @BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --managerfile=FileManager50.h --registerfile --namespace=bin2cpp50 --override if %errorlevel% neq 0 exit /b %errorlevel% +set TEST_NAME=testIssue56a +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +mkdir %OUTDIR%\input_files 1>NUL 2>NUL +mkdir %OUTDIR%\compiled_sources 1>NUL 2>NUL +mkdir %OUTDIR%\saved_files 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\input_files\_%TEST_NAME%.index.1234.css --size=1010 --fill=text +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\input_files\_%TEST_NAME%.index.4321.css --size=1020 --fill=text +@BIN2CPP_TARGET_FILE@ --noheader --dir=%OUTDIR%\input_files --output=%OUTDIR%\compiled_sources --chunksize=200 --managerfile=FileManager56a.h --registerfile --namespace=issue56a --override +if %errorlevel% neq 0 exit /b %errorlevel% + +set TEST_NAME=testIssue56b +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +mkdir %OUTDIR%\input_files 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\home 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog\how-to-create-a-web-site 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog\using-bin2cpp 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\contact 1>NUL 2>NUL +mkdir %OUTDIR%\generated_sources 1>NUL 2>NUL +mkdir %OUTDIR%\saved_files 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\home\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\how-to-create-a-web-site\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\using-bin2cpp\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\contact\index.html +@BIN2CPP_TARGET_FILE@ --noheader --dir=%OUTDIR%\input_files --output=%OUTDIR%\generated_sources --chunksize=200 --managerfile=FileManager56b.h --registerfile --namespace=issue56b --override --keepdirs +if %errorlevel% neq 0 exit /b %errorlevel% + +set TEST_NAME=testIssue56c +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +mkdir %OUTDIR%\input_files 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\home 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog\how-to-create-a-web-site 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog\using-bin2cpp 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\contact 1>NUL 2>NUL +mkdir %OUTDIR%\generated_sources 1>NUL 2>NUL +mkdir %OUTDIR%\saved_files 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\home\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\how-to-create-a-web-site\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\using-bin2cpp\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\contact\index.html +@BIN2CPP_TARGET_FILE@ --noheader --dir=%OUTDIR%\input_files --output=%OUTDIR%\generated_sources --chunksize=200 --managerfile=FileManager56c.h --registerfile --namespace=issue56c --override +if %errorlevel% neq 0 exit /b %errorlevel% + +set TEST_NAME=testKeepDirectories +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +mkdir %OUTDIR%\input_files 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\home 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog\how-to-create-a-web-site 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog\using-bin2cpp 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\contact 1>NUL 2>NUL +mkdir %OUTDIR%\generated_sources 1>NUL 2>NUL +mkdir %OUTDIR%\saved_files 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\home\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\how-to-create-a-web-site\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\using-bin2cpp\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\contact\index.html +@BIN2CPP_TARGET_FILE@ --noheader --dir=%OUTDIR%\input_files --output=%OUTDIR%\generated_sources --chunksize=200 --managerfile=FileManagerKeepDirs.h --registerfile --namespace=testkeepdirs --override --keepdirs +if %errorlevel% neq 0 exit /b %errorlevel% + +set TEST_NAME=testReportedPathFile1 +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\%TEST_NAME%.bin --size=1024 --fill=random --seed=1 +@BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --chunksize=50 --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --namespace=testReportedPathFile1 --override --reportedfilepath=foo\bar\%TEST_NAME%.bin +if %errorlevel% neq 0 exit /b %errorlevel% + +:: Test option --reportedfilepath where the reported filename does not match the original filename. +set TEST_NAME=testReportedPathFile2 +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --file=%OUTDIR%\%TEST_NAME%.bin --size=1024 --fill=random --seed=2 +@BIN2CPP_TARGET_FILE@ --noheader --file=%OUTDIR%\%TEST_NAME%.bin --output=%OUTDIR% --chunksize=50 --headerfile=_%TEST_NAME%.h --identifier=%TEST_NAME% --namespace=testReportedPathFile2 --override --reportedfilepath=ham\eggs\breakfast.bin +if %errorlevel% neq 0 exit /b %errorlevel% + +set TEST_NAME=testReportedPathDir +set OUTDIR=.\generated_files\%TEST_NAME% +mkdir %OUTDIR% 1>NUL 2>NUL +mkdir %OUTDIR%\input_files 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\home 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog\how-to-create-a-web-site 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\blog\using-bin2cpp 1>NUL 2>NUL +mkdir %OUTDIR%\input_files\www\contact 1>NUL 2>NUL +mkdir %OUTDIR%\generated_sources 1>NUL 2>NUL +mkdir %OUTDIR%\saved_files 1>NUL 2>NUL +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\home\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\how-to-create-a-web-site\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\blog\using-bin2cpp\index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=%OUTDIR%\input_files\www\contact\index.html +@BIN2CPP_TARGET_FILE@ --noheader --dir=%OUTDIR%\input_files --output=%OUTDIR%\generated_sources --chunksize=200 --managerfile=FileManagerReportedPathDir.h --registerfile --namespace=testReportedPathDir --override +if %errorlevel% neq 0 exit /b %errorlevel% + +echo GENERATE_TEST_FILES - END + dir >NUL diff --git a/test/bin2cpp_unittest/generate_test_files.sh.in b/test/bin2cpp_unittest/generate_test_files.sh.in index e30b3c5..f808d55 100755 --- a/test/bin2cpp_unittest/generate_test_files.sh.in +++ b/test/bin2cpp_unittest/generate_test_files.sh.in @@ -1,6 +1,8 @@ # Any commands which fail will cause the shell script to exit immediately set -e +echo "SCRIPT GENERATE_TEST_FILES - START" + export TEST_NAME=testText10 export OUTDIR=./generated_files/$TEST_NAME mkdir -p ${OUTDIR} @@ -103,36 +105,72 @@ mkdir -p ${OUTDIR} @TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=array --override +export TEST_NAME=testGeneratorArray10000_C +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=array --override --code=c + export TEST_NAME=testGeneratorString10000 export OUTDIR=./generated_files/$TEST_NAME mkdir -p ${OUTDIR} @TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=string --override +export TEST_NAME=testGeneratorString10000_C +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=string --override --code=c + export TEST_NAME=testGeneratorSegment10000 export OUTDIR=./generated_files/$TEST_NAME mkdir -p ${OUTDIR} @TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=segment --override +export TEST_NAME=testGeneratorSegment10000_C +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=segment --override --code=c + export TEST_NAME=testGeneratorWin32 export OUTDIR=./generated_files/$TEST_NAME mkdir -p ${OUTDIR} @TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=win32 --override +export TEST_NAME=testGeneratorWin32_C +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=win32 --override --code=c + export TEST_NAME=testNamespace export OUTDIR=./generated_files/$TEST_NAME mkdir -p ${OUTDIR} @TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=segment --override --namespace=foobar +export TEST_NAME=testNamespace_C +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=segment --override --baseclass=Bin2cFile2 --namespace=foobar --code=c + export TEST_NAME=testBaseClass export OUTDIR=./generated_files/$TEST_NAME mkdir -p ${OUTDIR} @TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=segment --override --baseclass=Resource +export TEST_NAME=testBaseClass_C +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=10000 --fill=sequential +@BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --chunksize=450 --generator=segment --override --baseclass=Resource --namespace=tbc --code=c + export TEST_NAME=testEncodingOct export OUTDIR=./generated_files/$TEST_NAME mkdir -p ${OUTDIR} @@ -172,6 +210,14 @@ mkdir -p ${OUTDIR} @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.1.bin --output=$OUTDIR --headerfile=_$TEST_NAME.1.h --identifier=testFileManager1 --managerfile=FileManager.h --override @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.2.bin --output=$OUTDIR --headerfile=_$TEST_NAME.2.h --identifier=testFileManager2 --registerfile --override +export TEST_NAME=testFileManager_C +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.1.bin --size=1000 --fill=random --seed=1 +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.2.bin --size=1000 --fill=random --seed=2 +@BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.1.bin --output=$OUTDIR --headerfile=_$TEST_NAME.1.h --identifier=testFileManager1 --managerfile=filemanager.h --override --code=c +@BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.2.bin --output=$OUTDIR --headerfile=_$TEST_NAME.2.h --identifier=testFileManager2 --registerfile --override --code=c + export TEST_NAME=testDir01 export OUTDIR=./generated_files/$TEST_NAME mkdir -p ${OUTDIR} @@ -188,6 +234,22 @@ mkdir -p ${OUTDIR}/sources @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/images/IMG_0004.jpg --output=$OUTDIR/sources --headerfile=_img0004.h --identifier=Img0004 --chunksize=200 --override @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/images/IMG_0005.jpg --output=$OUTDIR/sources --headerfile=_img0005.h --identifier=Img0005 --chunksize=200 --override +export TEST_NAME=testDir02 +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +mkdir -p ${OUTDIR}/images +mkdir -p ${OUTDIR}/testDirIncludeFilter +mkdir -p ${OUTDIR}/testDirExcludeFilter +mkdir -p ${OUTDIR}/testDirMultipleFilter +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/images/IMG_0001.jpg --size=1010 --fill=random --seed=1 +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/images/IMG_0002.jpg --size=1020 --fill=random --seed=2 +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/images/IMG_0003.jpg --size=1030 --fill=random --seed=3 +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/images/IMG_0004.png --size=1040 --fill=random --seed=4 +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/images/IMG_0005.png --size=1050 --fill=random --seed=5 +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/images/IMG_0006.png --size=1060 --fill=random --seed=6 +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/images/IMG_0007.svg --size=0170 --fill=html --seed=7 +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/images/IMG_0008.svg --size=0180 --fill=html --seed=8 + export TEST_NAME=testIssue47 export OUTDIR=./generated_files/$TEST_NAME mkdir -p ${OUTDIR} @@ -200,3 +262,108 @@ export OUTDIR=./generated_files/$TEST_NAME mkdir -p ${OUTDIR} @TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=1000 --fill=random --seed=1 @BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --managerfile=FileManager50.h --registerfile --namespace=bin2cpp50 --override + +export TEST_NAME=testIssue56a +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +mkdir -p ${OUTDIR}/input_files +mkdir -p ${OUTDIR}/compiled_sources +mkdir -p ${OUTDIR}/saved_files +@TESTFILEGENERATOR_TARGET_FILE@ --file=${OUTDIR}/input_files/_$TEST_NAME.index.1234.css --size=1010 --fill=text +@TESTFILEGENERATOR_TARGET_FILE@ --file=${OUTDIR}/input_files/_$TEST_NAME.index.4321.css --size=1020 --fill=text +@BIN2CPP_TARGET_FILE@ --noheader --dir=${OUTDIR}/input_files --output=${OUTDIR}/compiled_sources --chunksize=200 --managerfile=FileManager56a.h --registerfile --namespace=issue56a --override + +export TEST_NAME=testIssue56b +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +mkdir -p ${OUTDIR}/input_files +mkdir -p ${OUTDIR}/input_files/www +mkdir -p ${OUTDIR}/input_files/www/home +mkdir -p ${OUTDIR}/input_files/www/blog +mkdir -p ${OUTDIR}/input_files/www/blog/how-to-create-a-web-site +mkdir -p ${OUTDIR}/input_files/www/blog/using-bin2cpp +mkdir -p ${OUTDIR}/input_files/www/contact +mkdir -p ${OUTDIR}/generated_sources +mkdir -p ${OUTDIR}/saved_files +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/home/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/blog/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/blog/how-to-create-a-web-site/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/blog/using-bin2cpp/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/contact/index.html +@BIN2CPP_TARGET_FILE@ --noheader --dir=${OUTDIR}/input_files --output=${OUTDIR}/generated_sources --chunksize=200 --managerfile=FileManager56b.h --registerfile --namespace=issue56b --override --keepdirs + +export TEST_NAME=testIssue56c +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +mkdir -p ${OUTDIR}/input_files +mkdir -p ${OUTDIR}/input_files/www +mkdir -p ${OUTDIR}/input_files/www/home +mkdir -p ${OUTDIR}/input_files/www/blog +mkdir -p ${OUTDIR}/input_files/www/blog/how-to-create-a-web-site +mkdir -p ${OUTDIR}/input_files/www/blog/using-bin2cpp +mkdir -p ${OUTDIR}/input_files/www/contact +mkdir -p ${OUTDIR}/generated_sources +mkdir -p ${OUTDIR}/saved_files +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/home/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/blog/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/blog/how-to-create-a-web-site/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/blog/using-bin2cpp/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/contact/index.html +@BIN2CPP_TARGET_FILE@ --noheader --dir=${OUTDIR}/input_files --output=${OUTDIR}/generated_sources --chunksize=200 --managerfile=FileManager56c.h --registerfile --namespace=issue56c --override + +export TEST_NAME=testKeepDirectories +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p ${OUTDIR} +mkdir -p ${OUTDIR}/input_files +mkdir -p ${OUTDIR}/input_files/www +mkdir -p ${OUTDIR}/input_files/www/home +mkdir -p ${OUTDIR}/input_files/www/blog +mkdir -p ${OUTDIR}/input_files/www/blog/how-to-create-a-web-site +mkdir -p ${OUTDIR}/input_files/www/blog/using-bin2cpp +mkdir -p ${OUTDIR}/input_files/www/contact +mkdir -p ${OUTDIR}/generated_sources +mkdir -p ${OUTDIR}/saved_files +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/home/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/blog/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/blog/how-to-create-a-web-site/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/blog/using-bin2cpp/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=${OUTDIR}/input_files/www/contact/index.html +@BIN2CPP_TARGET_FILE@ --noheader --dir=${OUTDIR}/input_files --output=${OUTDIR}/generated_sources --chunksize=200 --managerfile=FileManagerKeepDirs.h --registerfile --namespace=testkeepdirs --override --keepdirs + +export TEST_NAME=testReportedPathFile1 +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p $OUTDIR +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=1024 --fill=random --seed=1 +@BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --chunksize=50 --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --namespace=testReportedPathFile1 --override --reportedfilepath=foo/bar/$TEST_NAME.bin + +# Test option --reportedfilepath where the reported filename does not match the original filename. +export TEST_NAME=testReportedPathFile2 +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p $OUTDIR +@TESTFILEGENERATOR_TARGET_FILE@ --file=$OUTDIR/$TEST_NAME.bin --size=1024 --fill=random --seed=2 +@BIN2CPP_TARGET_FILE@ --noheader --file=$OUTDIR/$TEST_NAME.bin --output=$OUTDIR --chunksize=50 --headerfile=_$TEST_NAME.h --identifier=$TEST_NAME --namespace=testReportedPathFile2 --override --reportedfilepath=ham/eggs/breakfast.bin + +export TEST_NAME=testReportedPathDir +export OUTDIR=./generated_files/$TEST_NAME +mkdir -p $OUTDIR +mkdir -p $OUTDIR/input_files +mkdir -p $OUTDIR/input_files/www +mkdir -p $OUTDIR/input_files/www/home +mkdir -p $OUTDIR/input_files/www/blog +mkdir -p $OUTDIR/input_files/www/blog/how-to-create-a-web-site +mkdir -p $OUTDIR/input_files/www/blog/using-bin2cpp +mkdir -p $OUTDIR/input_files/www/contact +mkdir -p $OUTDIR/generated_sources +mkdir -p $OUTDIR/saved_files +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=$OUTDIR/input_files/www/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=$OUTDIR/input_files/www/home/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=$OUTDIR/input_files/www/blog/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=$OUTDIR/input_files/www/blog/how-to-create-a-web-site/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=$OUTDIR/input_files/www/blog/using-bin2cpp/index.html +@TESTFILEGENERATOR_TARGET_FILE@ --size=1010 --fill=html --file=$OUTDIR/input_files/www/contact/index.html +@BIN2CPP_TARGET_FILE@ --noheader --dir=$OUTDIR/input_files --output=$OUTDIR/generated_sources --chunksize=200 --managerfile=FileManagerReportedPathDir.h --registerfile --namespace=testReportedPathDir --override + +echo "SCRIPT GENERATE_TEST_FILES - END"