#include "logTypes.hpp" namespace scn { scan_expected scanner::scan(WebStat::QuotedString & value, ContextType & ctx) { if (auto empty = scn::scan<>(ctx.range(), R"("")")) { return empty->begin(); } auto result = scn::scan(ctx.range(), R"("{:[^"]}")"); if (!result) { return unexpected(result.error()); } value = result->value(); return result->begin(); } scan_expected scanner::scan(WebStat::QueryString & value, ContextType & ctx) { if (auto null = scn::scan<>(ctx.range(), R"("")")) { return null->begin(); } if (auto empty = scn::scan<>(ctx.range(), R"("?")")) { value.emplace(); return empty->begin(); } auto result = scn::scan(ctx.range(), R"("?{:[^"]}")"); if (!result) { return unexpected(result.error()); } value = result->value(); return result->begin(); } scan_expected scanner::scan(WebStat::CLFString & value, ContextType & ctx) { if (auto empty = scn::scan<>(ctx.range(), R"("")")) { value.emplace(); return empty->begin(); } if (auto null = scn::scan<>(ctx.range(), R"("-")")) { return null->begin(); } auto result = scn::scan(ctx.range(), R"("{:[^"]}")"); if (!result) { return unexpected(result.error()); } value = result->value(); decode(*value); return result->begin(); } void scanner::decode(std::string & value) { static constexpr auto BS_MAP = []() { std::array map {}; map['f'] = '\f'; map['n'] = '\n'; map['r'] = '\r'; map['t'] = '\t'; map['v'] = '\v'; map['"'] = '"'; map['\\'] = '\\'; return map; }(); if (auto src = std::ranges::find(value, '\\'); src != value.end()) { auto dest = src; while (src != value.cend()) { if (*src == '\\') { const std::string_view escaped {++src, value.end()}; if (auto chr = BS_MAP[static_cast(*src)]) { *dest++ = chr; src++; } else if (auto hex = scn::scan(escaped, R"(x{:.2x})")) { *dest++ = static_cast(hex->value()); src += 3; } } else { *dest++ = *src++; } } value.erase(dest, value.end()); } } }