Merge 15fb22eee0 into 39f737443b
This commit is contained in:
commit
75522096e4
151
include/yaml-cpp/tagresolver.h
Normal file
151
include/yaml-cpp/tagresolver.h
Normal 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
187
src/tagresolver.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user