This commit is contained in:
Jakob Leben 2025-01-28 04:53:08 +00:00 committed by GitHub
commit 75522096e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 338 additions and 0 deletions

View File

@ -0,0 +1,151 @@
#include "yaml-cpp/dll.h"
#include "yaml-cpp/eventhandler.h"
#include <string>
namespace YAML {
struct Mark;
/**
* TagResolver is a base class for tag resolution.
* It acts as an event filter: it is an EventHandler itself,
* and it passes events on to a client EventHandler
* while resolving tags in the process.
* This base class passes events unmodified.
* A subclass is supposed to implement tag resolution
* according to a particular schema,
* as recommended by the YAML 1.2 spec:
* http://yaml.org/spec/1.2/spec.html#Schema
* Note that each tag in a schema also needs to provide
* a canonical representation of its values.
* Mapping values into canonical representations
* is not the responsibility of TagResolver though.
*/
class YAML_CPP_API TagResolver : public EventHandler
{
public:
using string = std::string;
TagResolver(EventHandler & client): m_client(client) {}
virtual void OnDocumentStart(const Mark& mark)
{
m_client.OnDocumentStart(mark);
}
virtual void OnDocumentEnd()
{
m_client.OnDocumentEnd();
}
virtual void OnNull(const Mark& mark, anchor_t anchor)
{
m_client.OnNull(mark, anchor);
}
virtual void OnAlias(const Mark& mark, anchor_t anchor)
{
m_client.OnAlias(mark, anchor);
}
virtual void OnScalar(const Mark& mark, const std::string& tag,
anchor_t anchor, const std::string& value)
{
m_client.OnScalar(mark, tag, anchor, value);
}
virtual void OnSequenceStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style)
{
m_client.OnSequenceStart(mark, tag, anchor, style);
}
virtual void OnSequenceEnd()
{
m_client.OnSequenceEnd();
}
virtual void OnMapStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style)
{
m_client.OnMapStart(mark, tag, anchor, style);
}
virtual void OnMapEnd()
{
m_client.OnMapEnd();
}
EventHandler & m_client;
};
/**
* Implements tag resolution according to Core Schema,
* as defined by YAML 1.2 spec:
* http://yaml.org/spec/1.2/spec.html#id2804923
*/
class YAML_CPP_API CoreTagResolver : public TagResolver
{
private:
static bool IsBase10Digit(char c)
{
return c >= '0' and c <= '9';
}
static bool IsBase8Digit(char c)
{
return c >= '0' and c <= '7';
}
static bool IsBase16Digit(char c)
{
return IsBase10Digit(c) || (c >= 'a' and c <= 'f') || (c >= 'A' and c <= 'F');
}
static bool IsBase8Int(const string & text);
static bool IsBase16Int(const string & text);
static bool isBase10Int(const string & text);
public:
CoreTagResolver(EventHandler & client): TagResolver(client) {}
static bool TagIsNonSpecific(const string & tag)
{
return (tag == "?" || tag == "!");
}
static bool ScalarIsNull(const string & text)
{
return (text == "null" || text == "Null" || text == "NULL" || text == "~");
}
static bool ScalarIsBool(const string & text)
{
return text == "true" ||
text == "True" ||
text == "TRUE" ||
text == "false" ||
text == "False" ||
text == "FALSE";
}
static bool ScalarIsInt(const string & text);
static bool ScalarIsFloat(const string & text);
virtual void OnScalar(const Mark& mark, const std::string& tag,
anchor_t anchor, const std::string& value);
virtual void OnSequenceStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style);
virtual void OnMapStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style);
};
}

187
src/tagresolver.cpp Normal file
View File

@ -0,0 +1,187 @@
#include "../include/yaml-cpp/tagresolver.h"
#include <vector>
#include <algorithm>
namespace YAML {
bool CoreTagResolver::IsBase8Int(const string & text)
{
if (text.empty())
return false;
for (string::size_type i = 0; i < text.size(); ++i)
{
if (!IsBase8Digit(text[i]))
return false;
}
return true;
}
bool CoreTagResolver::IsBase16Int(const string & text)
{
if (text.empty())
return false;
for (string::size_type i = 0; i < text.size(); ++i)
{
if (!IsBase16Digit(text[i]))
return false;
}
return true;
}
bool CoreTagResolver::isBase10Int(const string & text)
{
using namespace std;
if (text.empty())
return false;
string::size_type pos = 0;
if ( text[pos] == '-' ||
text[pos] == '+' )
pos += 1;
if (pos == text.size())
return false;
for (; pos < text.size(); ++pos)
{
if (!IsBase10Digit(text[pos]))
return false;
}
return true;
}
bool CoreTagResolver::ScalarIsInt(const string & text)
{
if (text.substr(0,2) == "0o")
{
return IsBase8Int(text.substr(2));
}
else if (text.substr(0,2) == "0x")
{
return IsBase16Int(text.substr(2));
}
else
{
return isBase10Int(text);
}
}
bool CoreTagResolver::ScalarIsFloat(const string & text)
{
static std::vector<string> inf = { ".inf", ".Inf", ".INF" };
static std::vector<string> nan = { ".nan", ".NaN", ".NAN" };
if (text.empty())
return false;
if (std::find(nan.begin(), nan.end(), text) != nan.end())
return true;
string::size_type pos = 0;
if ( text[0] == '-' ||
text[0] == '+' )
{
pos += 1;
}
if (pos == text.size())
return false;
if (std::find(inf.begin(), inf.end(), text.substr(pos)) != inf.end())
return true;
string::size_type intStart = pos;
while(pos < text.size() && IsBase10Digit(text[pos]))
{
++pos;
}
bool hasInt = pos > intStart;
if (pos == text.size())
return false;
if (text[pos] != '.')
return false;
++pos;
string::size_type fracStart = pos;
while(pos < text.size() && IsBase10Digit(text[pos]))
{
++pos;
}
bool hasFrac = pos > fracStart;
if (!hasInt && !hasFrac)
return false;
if (pos == text.size())
return true;
if (text[pos] != 'e' && text[pos] != 'E')
return false;
++pos;
if ( text[pos] == '-' || text[pos] == '+' )
++pos;
string::size_type expStart = pos;
while(pos < text.size() && IsBase10Digit(text[pos]))
{
++pos;
}
if (pos == expStart)
return false;
if (pos != text.size())
return false;
return true;
}
void CoreTagResolver::OnScalar(const Mark& mark, const std::string& tag,
anchor_t anchor, const std::string& value)
{
if (tag == "!")
{
TagResolver::OnScalar(mark, "tag:yaml.org,2002:str", anchor, value);
}
else if (tag == "?")
{
string resolved_tag;
if (ScalarIsNull(value))
resolved_tag = "tag:yaml.org,2002:null";
else if (ScalarIsBool(value))
resolved_tag = "tag:yaml.org,2002:bool";
else if (ScalarIsInt(value))
resolved_tag = "tag:yaml.org,2002:int";
else if (ScalarIsFloat(value))
resolved_tag = "tag:yaml.org,2002:float";
else
resolved_tag = "tag:yaml.org,2002:str";
TagResolver::OnScalar(mark, resolved_tag, anchor, value);
}
else
{
TagResolver::OnScalar(mark, tag, anchor, value);
}
}
void CoreTagResolver::OnSequenceStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style)
{
if (TagIsNonSpecific(tag))
TagResolver::OnSequenceStart(mark, "tag:yaml.org,2002:seq", anchor, style);
else
TagResolver::OnSequenceStart(mark, tag, anchor, style);
}
void CoreTagResolver::OnMapStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style)
{
if (TagIsNonSpecific(tag))
TagResolver::OnMapStart(mark, "tag:yaml.org,2002:map", anchor, style);
else
TagResolver::OnMapStart(mark, tag, anchor, style);
}
}