From 6f8f076e6620bb34b3794671715d1cbe43d98e3a Mon Sep 17 00:00:00 2001 From: Pinwhell <60289470+pinwhell@users.noreply.github.com> Date: Thu, 1 Aug 2024 05:14:26 -0400 Subject: [PATCH] CLI Integrated --- .gitmodules | 3 - CMakeLists.txt | 25 +++- cli/CMakeLists.txt | 11 ++ cli/TBSCLI.cpp | 250 +++++++++++++++++++++++++++++++++++++++ cli/main.cpp | 6 + cmake/TBSConfig.cmake.in | 3 + tests/CMakeLists.txt | 8 ++ tests/TBSCLITest.cxx | 14 +++ vendor/CMakeLists.txt | 4 - vendor/doctest | 1 - 10 files changed, 316 insertions(+), 9 deletions(-) create mode 100644 cli/CMakeLists.txt create mode 100644 cli/TBSCLI.cpp create mode 100644 cli/main.cpp create mode 100644 cmake/TBSConfig.cmake.in create mode 100644 tests/TBSCLITest.cxx delete mode 160000 vendor/doctest diff --git a/.gitmodules b/.gitmodules index aed1997..a03182b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "vendor/doctest"] - path = vendor/doctest - url = https://github.com/doctest/doctest.git [submodule "vendor/etl"] path = vendor/etl url = https://github.com/ETLCPP/etl.git diff --git a/CMakeLists.txt b/CMakeLists.txt index a3f0d7c..88cc510 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,9 +51,32 @@ if(TBS_USE_ARCH_WORD_SIMD) target_compile_definitions(TBS INTERFACE TBS_USE_ARCH_WORD_SIMD) endif() +target_include_directories(TBS INTERFACE $ $) -target_include_directories(TBS INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) +add_subdirectory(cli) if(TBS_TESTS) add_subdirectory(tests) endif() + +install(TARGETS TBS + EXPORT TBSTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin) + +install(EXPORT TBSTargets + FILE TBSTargets.cmake + NAMESPACE TBS:: + DESTINATION lib/cmake/TBS) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ + DESTINATION include) + +configure_file(cmake/TBSConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/TBSConfig.cmake + @ONLY) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/TBSConfig.cmake + DESTINATION lib/cmake/TBS) \ No newline at end of file diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt new file mode 100644 index 0000000..5533098 --- /dev/null +++ b/cli/CMakeLists.txt @@ -0,0 +1,11 @@ +set(CMAKE_CXX_STANDARD 17) + +find_package(cxxopts REQUIRED) + +add_executable(TBSCLI main.cpp TBSCLI.cpp) +target_link_libraries(TBSCLI TBS cxxopts::cxxopts) + +install(TARGETS TBSCLI + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin) \ No newline at end of file diff --git a/cli/TBSCLI.cpp b/cli/TBSCLI.cpp new file mode 100644 index 0000000..df77625 --- /dev/null +++ b/cli/TBSCLI.cpp @@ -0,0 +1,250 @@ +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#endif + +class FileView { +public: + inline FileView(const char* filePath) + : fileHandle(nullptr) + , fileMapping(nullptr) + , mapView(nullptr) + { + Init(filePath); + } + + inline ~FileView() { + + Release(); + } + + operator const void* () const + { + return mapView; + } + + size_t size() const + { + return fileSize; + } + +private: + size_t fileSize; + union { + void* fileHandle; + int fileHandleI; + }; + void* fileMapping; + union { + void* mapView; + int mapViewI; + }; + +#ifdef __linux__ + inline void Init(const char* filePath) + { + fileSize = std::filesystem::file_size(filePath); + + if ((fileSize > 0) == false) + throw std::runtime_error("Invalid File Size"); + + fileHandleI = open(filePath, O_RDONLY); + + if (fileHandleI < 0) + throw std::runtime_error("File Open Failed"); + + mapView = mmap(nullptr, fileSize, PROT_READ, MAP_SHARED, fileHandleI, 0); + + if (mapViewI == -1) + { + close(fileHandleI); + throw std::runtime_error("File Mapping Failed"); + } + } + + inline void Release() + { + if (mapViewI != -1 && mapView != nullptr) + { + munmap(mapView, fileSize); + } + + if (fileHandleI > 0) + close(fileHandleI); + } +#endif + + +#ifdef _WIN32 + inline void Init(const char* filePath) + { + fileHandle = CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (fileHandle == INVALID_HANDLE_VALUE) + throw std::runtime_error("Error opening file"); + + fileSize = std::filesystem::file_size(filePath); + + fileMapping = CreateFileMappingA(fileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr); + if (fileMapping == nullptr) + { + CloseHandle(fileHandle); + throw std::runtime_error("Error creating file mapping"); + } + + mapView = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, 0); + + if (mapView == nullptr) { + CloseHandle(fileMapping); + CloseHandle(fileHandle); + throw std::runtime_error("Error mapping view of file"); + } + } + + inline void Release() + { + if (mapView != nullptr) { + UnmapViewOfFile(mapView); + } + + if (fileMapping != nullptr) { + CloseHandle(fileMapping); + } + + if (fileHandle != nullptr && fileHandle != INVALID_HANDLE_VALUE) { + CloseHandle(fileHandle); + } + } +#endif +}; + +using namespace cxxopts; + +int TBSCLI(int argc, const char* argv[]) +{ + std::string file; + std::string pattern; + bool bSingleRes = false; + bool bNaked = false; + bool bJson = false; + + cxxopts::Options options("TBSCLI", "Command Line Interface for TBS"); + + options.allow_unrecognised_options(); + + options.add_options() + ("f,file", "File to perform the scan at", cxxopts::value()) // a bool parameter + ("p,pattern", "Pattern to scan for", cxxopts::value()) + ("s,single", "show first result", cxxopts::value()->default_value("false")) + ("n,naked", "to keep neat output raw naked output", cxxopts::value()->default_value("false")) + ("j,json", "to output as JSON", cxxopts::value()->default_value("false")) + ; + + auto result = options.parse(argc, argv); + + if (!result.count("file") || + !result.count("pattern")) + { + std::cout << options.help() << std::endl; + return 0; + } + + pattern = result["pattern"].as(); + + if (!TBS::Pattern::Valid(pattern)) + { + printf("Pattern '%s' invalid\n", pattern.c_str()); + return 1; + } + + file = result["file"].as(); + + if (!std::filesystem::exists(file)) + { + printf("File '%s' Does not exist\n", file.c_str()); + return 2; + } + + bSingleRes = result["single"].as(); + bNaked = result["naked"].as(); + bJson = result["json"].as(); + + try { + FileView fileView(file.c_str()); + const char* fileBegin = (char*)((const void*)fileView); + const char* fileEnd = fileBegin + fileView.size(); + + const auto handleSingleResult = [&] { + TBS::Pattern::Result result; + + if (!TBS::Light::ScanOne(fileBegin, fileEnd, result, pattern.c_str())) + { + printf("pattern '%s' not found in '%s'\n", pattern.c_str(), file.c_str()); + return 3; + } + + if (bJson) + + printf( + R"({ + \"%s\" : %d + })", pattern.c_str(), result - (size_t)fileBegin); + + else printf("0x%016Xll", result - (size_t)fileBegin); + + return 0; + }; + + const auto handleMultiResult = [&] { + TBS::Pattern::Results results; + + if (!TBS::Light::Scan(fileBegin, fileEnd, results, pattern.c_str())) + { + printf("pattern '%s' not found in '%s'\n", pattern.c_str(), file.c_str()); + return 3; + } + + if (bJson) + { + printf( + R"({ + \"%s\" : [ + ])", pattern.c_str()); + + for (size_t i = 0; i < results.size(); i++) + { + if (i != 0) + printf(", "); + + printf("%ull", results[i] - (size_t)fileBegin); + } + + printf("]\n}"); + + return 0; + } + + for (auto res : results) + printf("0x%016Xll\n", res - (size_t)fileBegin); + + return 0; + }; + + return (bSingleRes ? handleSingleResult() : handleMultiResult()); + } + catch (const std::exception& e) + { + printf(e.what()); + return 2; + } + + return 0; +} \ No newline at end of file diff --git a/cli/main.cpp b/cli/main.cpp new file mode 100644 index 0000000..91b1ec2 --- /dev/null +++ b/cli/main.cpp @@ -0,0 +1,6 @@ +extern int TBSCLI(int argc, const char* argv[]); + +int main(int argc, const char* argv[]) +{ + return TBSCLI(argc, argv); +} \ No newline at end of file diff --git a/cmake/TBSConfig.cmake.in b/cmake/TBSConfig.cmake.in new file mode 100644 index 0000000..7d68cd3 --- /dev/null +++ b/cmake/TBSConfig.cmake.in @@ -0,0 +1,3 @@ +@PACKAGE_INIT@ # Init + +include("${CMAKE_CURRENT_LIST_DIR}/TBSTargets.cmake") # Targets \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8014503..b47b101 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,8 @@ enable_testing() +find_package(doctest REQUIRED) +find_package(cxxopts REQUIRED) + file(GLOB ALL_TST_SRC *.cpp) foreach(TST_SRC ${ALL_TST_SRC}) @@ -16,3 +19,8 @@ foreach(TST_SRC ${ALL_TST_SRC}) target_link_libraries(${TST_SRC_NAME} TBS doctest_with_main) endif() endforeach() + +set(CMAKE_CXX_STANDARD 17) + +add_executable(TBSCLITest TBSCLITest.cxx ${CMAKE_CURRENT_SOURCE_DIR}/../cli/TBSCLI.cpp) +target_link_libraries(TBSCLITest TBS cxxopts::cxxopts) \ No newline at end of file diff --git a/tests/TBSCLITest.cxx b/tests/TBSCLITest.cxx new file mode 100644 index 0000000..4ca751d --- /dev/null +++ b/tests/TBSCLITest.cxx @@ -0,0 +1,14 @@ + +extern int TBSCLI(int argc, const char* argv[]); + +int main(int argc, const char* realArgv[]) +{ + const const char* argv[] = { + realArgv[0], + "-f", "C:\\Users\\Wing\\Desktop\\prueva.bin", + "-p", "AA AA AA AA", + "--quiet" + }; + + return TBSCLI(sizeof(argv) / sizeof(argv[0]), argv); +} \ No newline at end of file diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt index db50958..6a2c577 100644 --- a/vendor/CMakeLists.txt +++ b/vendor/CMakeLists.txt @@ -1,7 +1,3 @@ -if(TBS_TESTS) - add_subdirectory(doctest) -endif() - if(TBS_USE_ETL) if(NOT TARGET etl) add_subdirectory(etl) diff --git a/vendor/doctest b/vendor/doctest deleted file mode 160000 index ae7a135..0000000 --- a/vendor/doctest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ae7a13539fb71f270b87eb2e874fbac80bc8dda2