Line data Source code
1 : /* Copyright (C) 2025 Robert Schiwon 2 : * 3 : * This file is part of libjdx. 4 : * 5 : * libjdx is free software: you can redistribute it and/or modify it under the 6 : * terms of the GNU Lesser General Public License as published by the Free 7 : * Software Foundation, either version 3 of the License, or (at your option) any 8 : * later version. 9 : * 10 : * libjdx is distributed in the hope that it will be useful, but WITHOUT ANY 11 : * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 12 : * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 : * details. 14 : * 15 : * You should have received a copy of the GNU Lesser General Public License 16 : * along with libjdx. If not, see <https://www.gnu.org/licenses/>. 17 : */ 18 : // determine the availability of the filesystem header 19 : // inspired by: 20 : // https://stackoverflow.com/questions/53365538/how-to-determine-whether-to-use-filesystem-or-experimental-filesystem 21 : #ifndef JDX_USE_EXPERIMENTAL_FILESYSTEM 22 : #if defined(__cpp_lib_filesystem) 23 : // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 24 : #define JDX_USE_EXPERIMENTAL_FILESYSTEM 0 25 : #elif defined(__cpp_lib_experimental_filesystem) 26 : // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 27 : #define JDX_USE_EXPERIMENTAL_FILESYSTEM 1 28 : #elif !defined(__has_include) 29 : // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 30 : #define JDX_USE_EXPERIMENTAL_FILESYSTEM 1 31 : #elif __has_include(<filesystem>) 32 : // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 33 : #define JDX_USE_EXPERIMENTAL_FILESYSTEM 0 34 : #elif __has_include(<experimental/filesystem>) 35 : // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 36 : #define JDX_USE_EXPERIMENTAL_FILESYSTEM 1 37 : #endif 38 : #endif 39 : 40 : #ifndef JDX_USE_EXPERIMENTAL_FILESYSTEM 41 : #error Required <filesystem> header not available. 42 : #endif 43 : 44 : #include "jdx/JdxParser.hpp" 45 : #include "io/TextReader.hpp" 46 : #include "util/LdrUtils.hpp" 47 : #include "util/StringUtils.hpp" 48 : 49 : #include <algorithm> 50 : #include <array> 51 : #include <climits> 52 : #include <cstring> 53 : #include <limits> 54 : #include <sstream> 55 : // include and alias filesystem header 56 : #if JDX_USE_EXPERIMENTAL_FILESYSTEM 57 : #include <experimental/filesystem> 58 : namespace fs = std::experimental::filesystem; 59 : #else 60 : #include <filesystem> 61 : namespace fs = std::filesystem; 62 : #endif 63 : 64 10 : bool libjdx::jdx::JdxParser::canParse( 65 : const std::string& filePath, std::istream& iStream) 66 : { 67 : // check extension 68 30 : std::string extension = fs::path(filePath).extension(); 69 10 : util::toLower(extension); 70 10 : if (std::find(std::begin(s_acceptedExtensions), 71 : std::end(s_acceptedExtensions), extension) 72 10 : == std::end(s_acceptedExtensions)) 73 : { 74 5 : return false; 75 : } 76 : 77 : // read first few chars 78 5 : std::ios::pos_type position = iStream.tellg(); 79 10 : std::string buffer(s_scanBufferSize, '\0'); 80 5 : iStream.read(buffer.data(), s_scanBufferSize); 81 5 : const auto bytesRead = iStream.gcount(); 82 5 : if (iStream.eof() || iStream.fail() || iStream.bad()) 83 : { 84 0 : iStream.clear(); 85 : } 86 5 : iStream.seekg(position, std::ios_base::beg); 87 5 : buffer.resize(bytesRead); 88 5 : if (util::isLdrStart(buffer)) 89 : { 90 8 : auto label = util::parseLdrStart(buffer).first; 91 4 : return label == "TITLE"; 92 : } 93 1 : return false; 94 : } 95 : 96 5 : libjdx::jdx::Block libjdx::jdx::JdxParser::parse( 97 : std::unique_ptr<std::istream> streamPtr) 98 : { 99 10 : auto textReaderPtr = std::make_unique<io::TextReader>(std::move(streamPtr)); 100 6 : libjdx::jdx::Block block{std::move(textReaderPtr)}; 101 8 : return block; 102 : } 103 : 104 22 : libjdx::jdx::Block libjdx::jdx::JdxParser::parse(const std::string& filePath) 105 : { 106 42 : auto textReaderPtr = std::make_unique<io::TextReader>(filePath); 107 22 : libjdx::jdx::Block block{std::move(textReaderPtr)}; 108 36 : return block; 109 : }