oxen-core/contrib/epee/src/parserse_base_utils.cpp

180 lines
4.8 KiB
C++

#include "epee/storages/parserse_base_utils.h"
#undef OXEN_DEFAULT_LOG_CATEGORY
#define OXEN_DEFAULT_LOG_CATEGORY "serialization"
#include <algorithm>
#include <string>
#include <string_view>
#include <oxenc/hex.h>
#include "epee/misc_log_ex.h"
namespace epee::misc_utils::parse {
/*
\b Backspace (ascii code 08)
\f Form feed (ascii code 0C)
\n New line
\r Carriage return
\t Tab
\v Vertical tab
\' Apostrophe or single quote
\" Double quote
\\ Backslash character
*/
void match_string2(const char*& star_end_string, const char* buf_end, std::string& val)
{
bool escape_mode = false;
auto it = star_end_string;
++it;
auto fi = it;
while (fi != buf_end && ((detail::lut[(uint8_t)*fi] & 32)) == 0)
++fi;
val.assign(it, fi);
val.reserve(std::distance(star_end_string, buf_end));
it = fi;
for(;it != buf_end;it++)
{
if(escape_mode/*prev_ch == '\\'*/)
{
switch(*it)
{
case 'b': //Backspace (ascii code 08)
val.push_back(0x08);break;
case 'f': //Form feed (ascii code 0C)
val.push_back(0x0C);break;
case 'n': //New line
val.push_back('\n');break;
case 'r': //Carriage return
val.push_back('\r');break;
case 't': //Tab
val.push_back('\t');break;
case 'v': //Vertical tab
val.push_back('\v');break;
case '\'': //Apostrophe or single quote
val.push_back('\'');break;
case '"': //Double quote
val.push_back('"');break;
case '\\': //Backslash character
val.push_back('\\');break;
case '/': //Slash character
val.push_back('/');break;
case 'u': //Unicode code point
if (buf_end - it < 4)
{
ASSERT_MES_AND_THROW("Invalid Unicode escape sequence");
}
else
{
uint32_t dst = 0;
for (int i = 0; i < 4; ++i)
{
const auto c = *++it;
CHECK_AND_ASSERT_THROW_MES(oxenc::is_hex_digit(c), "Bad Unicode encoding: " + std::to_string(c));
dst = dst << 4 | oxenc::from_hex_digit(c);
}
// encode as UTF-8
if (dst <= 0x7f)
{
val.push_back(dst);
}
else if (dst <= 0x7ff)
{
val.push_back(0xc0 | (dst >> 6));
val.push_back(0x80 | (dst & 0x3f));
}
else if (dst <= 0xffff)
{
val.push_back(0xe0 | (dst >> 12));
val.push_back(0x80 | ((dst >> 6) & 0x3f));
val.push_back(0x80 | (dst & 0x3f));
}
else
{
ASSERT_MES_AND_THROW("Unicode code point is out or range");
}
}
break;
default:
val.push_back(*it);
LOG_PRINT_L0("Unknown escape sequence :\"\\" << *it << "\"");
}
escape_mode = false;
}else if(*it == '"')
{
star_end_string = it;
return;
}else if(*it == '\\')
{
escape_mode = true;
}
else
{
val.push_back(*it);
}
}
ASSERT_MES_AND_THROW("Failed to match string in json entry: " << std::string(star_end_string, buf_end));
}
// The only conclusive thing that can be said about this function is that it does indeed
// closely match a "number 2". 💩
void match_number2(const char*& star_end_string, const char* buf_end, std::string_view& val, bool& is_float_val, bool& is_negative_val)
{
val = {};
uint8_t float_flag = 0;
is_negative_val = false;
is_float_val = false;
size_t chars = 0;
auto it = star_end_string;
if (it != buf_end && *it == '-')
{
is_negative_val = true;
++chars;
++it;
}
for(;it != buf_end;it++)
{
const uint8_t flags = detail::lut[(uint8_t)*it];
if (flags & 16)
{
float_flag |= flags;
++chars;
}
else
{
val = std::string_view(&*star_end_string, chars);
if(val.size())
{
star_end_string = --it;
is_float_val = !!(float_flag & 2);
return;
}
else
ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
}
}
ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
}
void match_word2(const char*& star_end_string, const char* buf_end, std::string_view& val)
{
val = {};
for(auto it = star_end_string;it != buf_end;it++)
{
if (!(detail::lut[(uint8_t)*it] & 4))
{
val = std::string_view(&*star_end_string, std::distance(star_end_string, it));
if(val.size())
{
star_end_string = --it;
return;
}else
ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
}
}
ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
}
} // namespace epee::misc_utils::parse