diff --git a/include/stdex/json.hpp b/include/stdex/json.hpp new file mode 100644 index 000000000..65268af51 --- /dev/null +++ b/include/stdex/json.hpp @@ -0,0 +1,100 @@ +/* + SPDX-License-Identifier: MIT + Copyright © 2025 Amebis +*/ + +#pragma once + +#include "assert.hpp" +#include "compat.hpp" +#include + +namespace stdex +{ + namespace json + { + /// + /// Appends escaped JSON string + /// + /// \param[in,out] dst String to append to + /// \param[in] src Source string + /// \param[in] num_chars Code unit limit in string `src` + /// + template, class AX = std::allocator> + void escape( + _Inout_ std::basic_string& dst, + _In_reads_or_z_opt_(num_chars) const char* src, _In_ size_t num_chars = SIZE_MAX) + { + stdex_assert(src || !num_chars); + for (size_t i = 0; i < num_chars && src[i]; ++i) { + switch (src[i]) { + case '\"': dst += "\\\""; break; + case '\\': dst += "\\\\"; break; + case '/' : dst += "\\/"; break; + case '\b': dst += "\\b"; break; + case '\f': dst += "\\f"; break; + case '\n': dst += "\\n"; break; + case '\r': dst += "\\r"; break; + case '\t': dst += "\\t"; break; + default: dst += src[i]; break; + } + } + } + + /// + /// Appends escaped JSON string + /// + /// \param[in,out] dst String to append to + /// \param[in] src Source string + /// \param[in] num_chars Code unit limit in string `src` + /// + template, class AX = std::allocator> + void escape( + _Inout_ std::basic_string& dst, + _In_reads_or_z_opt_(num_chars) const wchar_t* src, _In_ size_t num_chars = SIZE_MAX) + { + stdex_assert(src || !num_chars); + for (size_t i = 0; i < num_chars && src[i]; ++i) { + switch (src[i]) { + case L'\"': dst += L"\\\""; break; + case L'\\': dst += L"\\\\"; break; + case L'/' : dst += L"\\/"; break; + case L'\b': dst += L"\\b"; break; + case L'\f': dst += L"\\f"; break; + case L'\n': dst += L"\\n"; break; + case L'\r': dst += L"\\r"; break; + case L'\t': dst += L"\\t"; break; + default: dst += src[i]; break; + } + } + } + + /// + /// Appends escaped JSON string + /// + /// \param[in,out] dst String to append to + /// \param[in] src Source string + /// + template, class AX = std::allocator> + void escape( + _Inout_ std::basic_string& dst, + _In_ const T (&src)[N]) + { + escape(dst, src, N); + } + + /// + /// Appends escaped JSON string + /// + /// \param[in,out] dst String to append to + /// \param[in] src Source string + /// + template, class AX_dst = std::allocator, class TR_src = std::char_traits, class AX_src = std::allocator> + void escape( + _Inout_ std::basic_string& dst, + _In_ const std::basic_string& src) + { + escape(dst, src.data(), src.size()); + } + } +} \ No newline at end of file