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 : #ifndef JDX_LDRUTILS_HPP 19 : #define JDX_LDRUTILS_HPP 20 : 21 : #include "io/TextReader.hpp" 22 : #include "jdx/StringLdr.hpp" 23 : #include "util/StringUtils.hpp" 24 : 25 : #include <limits> 26 : #include <optional> 27 : #include <string> 28 : #include <type_traits> 29 : #include <vector> 30 : 31 : /** 32 : * @brief Helper functions for parsing JCAMP-DX labeled data records (LDRs). 33 : */ 34 : namespace libjdx::jdx::util 35 : { 36 : bool isLdrStart(const std::string& line); 37 : std::string normalizeLdrStart(const std::string& ldr); 38 : std::string normalizeLdrLabel(const std::string& label); 39 : std::pair<std::string, std::string> parseLdrStart(const std::string& ldrStart); 40 : std::pair<std::string, std::optional<std::string>> stripLineComment( 41 : const std::string& line, bool trimContent = false, 42 : bool trimComment = false); 43 : std::optional<const StringLdr> findLdr( 44 : const std::vector<StringLdr>& ldrs, const std::string& label); 45 : std::optional<std::string> findLdrValue( 46 : const std::vector<StringLdr>& ldrs, const std::string& label); 47 : void skipToNextLdr(io::TextReader& reader, std::optional<std::string>& nextLine, 48 : bool forceSkipFirstLine); 49 : void skipPureComments(io::TextReader& reader, 50 : std::optional<std::string>& nextLine, bool mustPrecedeLdr); 51 : bool isPureComment(const std::string& line); 52 : bool isBrukerSpecificSectionStart(const std::string& line); 53 : bool isBrukerSpecificSectionEnd(const std::string& line); 54 : 55 : template<typename T> struct LdrValueParser 56 : { 57 : // for std::string 58 136 : static std::optional<T> parse(const std::string& value) 59 : { 60 : // see: 61 : // https://stackoverflow.com/questions/49330687/how-do-i-restrict-templates-to-specific-types 62 : // https://stackoverflow.com/questions/44847559/is-stdis-samet-tvalue-always-true 63 : static_assert(std::is_same_v<T, std::string>, 64 : "LdrValueParser template for string used with wrong type."); 65 : // could be empty string which is also a valid string 66 136 : return value; 67 : }; 68 : }; 69 : template<> struct LdrValueParser<double> 70 : { 71 315 : static std::optional<double> parse(const std::string& value) 72 : { 73 315 : return value.empty() ? std::nullopt 74 630 : : std::optional<double>{std::stod(value)}; 75 : }; 76 : }; 77 : template<> struct LdrValueParser<uint64_t> 78 : { 79 65 : static std::optional<uint64_t> parse(const std::string& value) 80 : { 81 : // we parse uint64_t as unsigned long and assign it to uint64_t 82 : static_assert(std::numeric_limits<unsigned long>::max() 83 : // NOLINTNEXTLINE(misc-redundant-expression) 84 : <= std::numeric_limits<uint64_t>::max(), 85 : "unsigned long max larger than uint_64_t max"); 86 65 : return value.empty() ? std::nullopt 87 130 : : std::optional<uint64_t>{std::stoul(value)}; 88 : }; 89 : }; 90 : 91 : template<typename T> 92 938 : std::optional<T> parseLdrValue( 93 : const std::vector<StringLdr>& ldrs, const std::string& label) 94 : { 95 1876 : auto stringValueOptional = findLdrValue(ldrs, label); 96 938 : if (!stringValueOptional.has_value()) 97 : { 98 : // LDR not found 99 422 : return std::nullopt; 100 : } 101 1032 : auto stringValue 102 516 : = stripLineComment(stringValueOptional.value(), true).first; 103 516 : return LdrValueParser<T>::parse(stringValue); 104 : } 105 : } // namespace libjdx::jdx::utils 106 : 107 : #endif