diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c9c29f..496b481 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,8 @@ project(md5sum LANGUAGES CXX) # ------------------------------------------------------------------------------------ # -option(MD5_SHARED_LIB "Built as a dynamic library." OFF) +option(MD5_BUILD_DEMO "Build md5 demo binary." OFF) +option(MD5_SHARED_LIB "Build as a dynamic library." OFF) option(MD5_ENABLE_LTO "Enable LTO optimization of the library." ON) option(MD5_ENABLE_TESTING "Enable testing of the md5sum library." OFF) option(MD5_ENABLE_BENCHMARK "Enable benchmark of the md5sum library." OFF) @@ -44,15 +45,22 @@ else() add_library(md5sum SHARED ${MD5_SRC}) target_compile_options(md5sum PRIVATE -fvisibility=hidden) endif() -target_include_directories(md5sum PUBLIC src/) set(MD5_COMPILE_OPTIONS -fno-rtti -fno-exceptions) target_compile_options(md5sum PRIVATE ${MD5_COMPILE_OPTIONS}) - +target_include_directories(md5sum PUBLIC src/) add_library(md5sum::md5sum ALIAS md5sum) # ------------------------------------------------------------------------------------ # +if (MD5_BUILD_DEMO) + add_executable(md5_demo demo.cc) + target_link_libraries(md5_demo PRIVATE md5sum) + target_compile_options(md5_demo PRIVATE ${MD5_COMPILE_OPTIONS}) +endif() + +# ------------------------------------------------------------------------------------ # + include(third_party/ThirdParty.cmake) if (MD5_ENABLE_TESTING) diff --git a/demo.cc b/demo.cc new file mode 100644 index 0000000..8d04059 --- /dev/null +++ b/demo.cc @@ -0,0 +1,80 @@ +#include "md5.h" +#include +#include + +using md5::MD5; + +#if not __linux__ +std::optional hash_file(const std::string_view &file_name) { + auto *fp = std::fopen(file_name.data(), "rb"); + if (!fp) { + std::perror("File open failed"); + return std::nullopt; + } + + MD5 md5; + size_t len; + char buffer[BUFSIZ]; + while ((len = std::fread(buffer, sizeof(char), BUFSIZ, fp)) > 0) { + md5.Update(buffer, len); + } + if (std::ferror(fp)) { + std::perror("File read failed"); + std::fclose(fp); + return std::nullopt; + } + std::fclose(fp); + return md5.Final().Digest(); +} + +#else + +#include +#include +#include +#include + +std::optional hash_file(const std::string_view &file_name) { + auto fd = open(file_name.data(), O_RDONLY); + if (fd < 0) { + std::perror("File open failed"); + return std::nullopt; + } + + struct stat st {}; + fstat(fd, &st); + auto file_size = st.st_size; + + auto ptr = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + if (ptr == MAP_FAILED) { + std::perror("File mapping failed"); + return std::nullopt; + } + auto result = MD5::Hash(ptr, file_size); + if (munmap(ptr, file_size)) { + std::perror("File unmapping failed"); + } + return result; +} +#endif + +constexpr auto NO_ERROR = 0; +constexpr auto ARG_ERROR = 1; +constexpr auto FILE_ERROR = 2; + +int main(int argc, char *argv[]) { + if (argc == 1) { + std::cout << "Usage: " << argv[0] << " [FILE]" << std::endl; + return NO_ERROR; + } else if (argc != 2) { + std::cout << "Invalid MD5 arguments" << std::endl; + return ARG_ERROR; + } + + if (auto result = hash_file(argv[1]); result.has_value()) { + std::cout << result.value() << std::endl; + return NO_ERROR; + } + return FILE_ERROR; +}