commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <cstring>
|
||||
#include "metafile/nml.h"
|
||||
#include "filesystem/io_handle.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "platform.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::NML;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Parser::SaveBinaryTag(IO::Handle &out, const Tag &tag, File::Binary method)
|
||||
{
|
||||
const Variant &v = tag.GetValue();
|
||||
|
||||
if (v.GetType() != Variant::VariantNone)
|
||||
{
|
||||
out.Write <ushort> ((ushort)tag.name.Len());
|
||||
out.Write((void *)tag.name.c_str(), tag.name.Len());
|
||||
}
|
||||
else
|
||||
__ERR__(__LOG_W__ << "Ignoring invalid metatag '" << tag.name << "'.\n", true)
|
||||
|
||||
// Store tag start size/type.
|
||||
out.Write <uchar> ((uchar)v.GetType());
|
||||
|
||||
size_t tag_length_pos = out.Tell();
|
||||
switch (v.GetType())
|
||||
{
|
||||
case Variant::VariantNone:
|
||||
case Variant::VariantBinary:
|
||||
case Variant::VariantString:
|
||||
out.Write <int> (-1);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (v.GetType())
|
||||
{
|
||||
case Variant::VariantNone:
|
||||
NMLTagForeach(child, tag)
|
||||
if (!SaveBinaryTag(out, *child, method))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case Variant::VariantBinary:
|
||||
out.Write(tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize());
|
||||
break;
|
||||
|
||||
case Variant::VariantInteger:
|
||||
out.Write <int> (tag.GetInteger());
|
||||
break;
|
||||
|
||||
case Variant::VariantFloat:
|
||||
out.Write <float> (tag.GetReal());
|
||||
break;
|
||||
|
||||
case Variant::VariantString:
|
||||
out.Write(tag.GetString(), std::strlen(tag.GetString()));
|
||||
break;
|
||||
|
||||
default:
|
||||
__ERR__(__LOG_E__ << "No method to output tag '" << tag.name << "' type.\n", false)
|
||||
}
|
||||
|
||||
switch (v.GetType())
|
||||
{
|
||||
case Variant::VariantNone:
|
||||
case Variant::VariantBinary:
|
||||
case Variant::VariantString:
|
||||
{
|
||||
size_t tag_end_pos = out.Tell();
|
||||
out.Seek(tag_length_pos, IO::Base::SeekStart);
|
||||
out.Write <int> (tag_end_pos - tag_length_pos);
|
||||
out.Seek(tag_end_pos, IO::Base::SeekStart);
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Parser::SaveBinary(IO::Handle &h, const File &file)
|
||||
{
|
||||
h.Write((const void *)"<BML=1.0>\n", 10);
|
||||
NMLFileForeach(tag, file)
|
||||
if (!SaveBinaryTag(h, *tag, file.GetBinaryMethod()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Parser::SaveBinary(const char *uri, const File &file)
|
||||
{
|
||||
if (!uri)
|
||||
return false;
|
||||
|
||||
AutoPtr <IO::Handle> handle;
|
||||
if (!(handle = Platform::Get().io->Open(uri, IO::ModeWrite)))
|
||||
__ERR__(__LOG_E__ << "Failed to open metafile output '" << uri << "'.\n", false)
|
||||
|
||||
return SaveBinary(*handle, file);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,83 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "metafile/nml.h"
|
||||
#include "alloc/ialloc.h"
|
||||
|
||||
using namespace GS::NML;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool File::GetBool(const char *path, bool dflt, bool verbose) const {
|
||||
Tag *t = GetTypedTag(path, Variant::VariantBool, verbose);
|
||||
return t ? t->GetBool() : dflt;
|
||||
}
|
||||
|
||||
int File::GetInteger(const char *path, int dflt, bool verbose) const {
|
||||
Tag *t = GetTypedTag(path, Variant::VariantInteger, verbose);
|
||||
return t ? t->GetInteger() : dflt;
|
||||
}
|
||||
|
||||
float File::GetReal(const char *path, float dflt, bool verbose) const {
|
||||
Tag *t = GetTypedTag(path, Variant::VariantFloat, verbose);
|
||||
return t ? t->GetReal() : dflt;
|
||||
}
|
||||
|
||||
const char *File::GetString(const char *path, const char *dflt, bool verbose) const {
|
||||
Tag *t = GetTypedTag(path, Variant::VariantString, verbose);
|
||||
return t ? t->GetString() : dflt;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void File::Import(const File &src, bool clear_before_import) {
|
||||
if (clear_before_import)
|
||||
Clear();
|
||||
ListForeachPtr(Tag *, tag, src.GetTags())
|
||||
AddRoot(tag->Clone());
|
||||
}
|
||||
|
||||
File *File::Clone() const {
|
||||
File *clone = new File;
|
||||
if (!clone)
|
||||
return NULL;
|
||||
|
||||
if (!name.IsEmpty())
|
||||
clone->name = name.c_str();
|
||||
|
||||
clone->Import(*this);
|
||||
return clone;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Tag *File::AddRoot(Tag *t) {
|
||||
if (!t)
|
||||
return NULL;
|
||||
if (!tags.Add(t))
|
||||
return NULL;
|
||||
return t;
|
||||
}
|
||||
|
||||
Tag *File::AddRoot(const char *name) { return AddRoot(new Tag(name)); }
|
||||
Tag *File::AddRoot(const char *name, bool v) { return AddRoot(new Tag(name, v)); }
|
||||
Tag *File::AddRoot(const char *name, int v) { return AddRoot(new Tag(name, v)); }
|
||||
Tag *File::AddRoot(const char *name, float v) { return AddRoot(new Tag(name, v)); }
|
||||
Tag *File::AddRoot(const char *name, const char *s) { return AddRoot(new Tag(name, s)); }
|
||||
Tag *File::AddRoot(const char *name, void *d, size_t s) { return AddRoot(new Tag(name, d, s)); }
|
||||
bool File::UnlinkRoot(Tag *t) { return tags.Remove(t); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void File::Free() {
|
||||
ListDeleteAllPtr(Tag *, tags);
|
||||
name.Clear();
|
||||
}
|
||||
|
||||
File::~File() { Free(); }
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,122 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "metafile/nml.h"
|
||||
#include "reflection/c_refl.h"
|
||||
#include "memory/nauto_ptr.h"
|
||||
#include "assert/nassert.h"
|
||||
|
||||
|
||||
namespace GS {
|
||||
namespace NML {
|
||||
using namespace Reflection;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool GenericObjectFromMetaTag(Tag &t, void *o, Property *o_prop)
|
||||
{
|
||||
NMLTagForeach(pt, t)
|
||||
for (int n = 0; o_prop[n].name; ++n)
|
||||
if (pt->name == o_prop[n].name)
|
||||
{
|
||||
size_t p_prop = (size_t)o + o_prop[n].offset_of;
|
||||
|
||||
switch (o_prop[n].type)
|
||||
{
|
||||
case Property::BoolProp:
|
||||
*(bool *)p_prop = pt->GetBool();
|
||||
break;
|
||||
case Property::CharProp:
|
||||
*(char *)p_prop = (char)pt->GetInteger();
|
||||
break;
|
||||
case Property::ShortProp:
|
||||
*(short *)p_prop = (short)pt->GetInteger();
|
||||
break;
|
||||
case Property::IntProp:
|
||||
*(int *)p_prop = pt->GetInteger();
|
||||
break;
|
||||
case Property::FloatProp:
|
||||
*(float *)p_prop = pt->GetReal();
|
||||
break;
|
||||
case Property::StringProp:
|
||||
*(GS::String *)p_prop = pt->GetString();
|
||||
break;
|
||||
case Property::EnumProp:
|
||||
__ASSERT__(o_prop[n].enum_dict);
|
||||
*(int *)p_prop = Enum::fromString(pt->GetString(), o_prop[n].enum_dict);
|
||||
break;
|
||||
|
||||
default:
|
||||
__ASSERT_ALWAYS__;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Tag *GenericObjectToMetaTag(Tag *t, const void *o, Property *o_prop)
|
||||
{
|
||||
if (t)
|
||||
for (int n = 0; o_prop[n].name; ++n)
|
||||
{
|
||||
size_t p_prop = (size_t)o + o_prop[n].offset_of;
|
||||
|
||||
switch (o_prop[n].type)
|
||||
{
|
||||
case Property::BoolProp:
|
||||
t->AddChild(o_prop[n].name, *(bool *)p_prop);
|
||||
break;
|
||||
case Property::CharProp:
|
||||
t->AddChild(o_prop[n].name, (int)*(char *)p_prop);
|
||||
break;
|
||||
case Property::ShortProp:
|
||||
t->AddChild(o_prop[n].name, (int)*(short *)p_prop);
|
||||
break;
|
||||
case Property::IntProp:
|
||||
t->AddChild(o_prop[n].name, *(int *)p_prop);
|
||||
break;
|
||||
case Property::FloatProp:
|
||||
t->AddChild(o_prop[n].name, *(float *)p_prop);
|
||||
break;
|
||||
case Property::StringProp:
|
||||
t->AddChild(o_prop[n].name, ((GS::String *)p_prop)->c_str());
|
||||
break;
|
||||
case Property::EnumProp:
|
||||
__ASSERT__(o_prop[n].enum_dict);
|
||||
t->AddChild(o_prop[n].name, Enum::toString(*(int *)p_prop, o_prop[n].enum_dict));
|
||||
break;
|
||||
|
||||
default:
|
||||
__ASSERT_ALWAYS__;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool GenericObjectFromMetaFile(const char *uri, void *obj, Property *obj_prop, const char *root_name)
|
||||
{
|
||||
File file;
|
||||
if (!Parser::Load(uri, file))
|
||||
return false;
|
||||
|
||||
if (Tag *root = file.GetTag(root_name))
|
||||
if (!GenericObjectFromMetaTag(*root, obj, obj_prop))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool GenericObjectToMetaFile(const char *uri, const void *obj, Property *obj_prop, const char *root_name)
|
||||
{
|
||||
File file;
|
||||
file.AddRoot(GenericObjectToMetaTag(new Tag(root_name), obj, obj_prop));
|
||||
return Parser::Save(uri, file);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
} //NML
|
||||
} // GS
|
||||
@@ -0,0 +1,380 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <cstring>
|
||||
#include "metafile/nml.h"
|
||||
#include "ascii/parser.h"
|
||||
#include "ascii/ascii_encoder.h"
|
||||
#include "filesystem/io_handle.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "platform.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::NML;
|
||||
using namespace GS::AsciiParser;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Parser::IsMetafile(const char *name)
|
||||
{
|
||||
AutoPtr <IO::Handle> h(Platform::Get().io->Open(name));
|
||||
if (h.IsNull())
|
||||
return false;
|
||||
|
||||
char header[9];
|
||||
h->Read(header, 9);
|
||||
if (Memory::Compare(header, "<Version=", 9) && Memory::Compare(header, "<NML=", 5))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
const char *Parser::ParseTagPreprocessorDirective(Tag &tag, const char *s, const char *e)
|
||||
{
|
||||
s++;
|
||||
|
||||
// Catch preprocessor directive.
|
||||
if (!strncmp(s, "include", 7))
|
||||
{
|
||||
// Ensure base coherency.
|
||||
if (tag.GetValue().GetType() != Variant::VariantNone)
|
||||
__ERR__(__LOG_E__ << "Incoherent type in tag '" << tag.name << "' declaration.\n", NULL)
|
||||
|
||||
// Parse directive.
|
||||
s += SkipSpace(s + 7, e) - s;
|
||||
if (s[0] != '(')
|
||||
__ERR__(__LOG_E__ << "Mangled #include directive.\n", NULL);
|
||||
|
||||
// Fetch arguments.
|
||||
String include_path;
|
||||
|
||||
forever
|
||||
{
|
||||
if (s[0] == ')')
|
||||
break;
|
||||
s += SkipSpace(s + 1, e) - s;
|
||||
|
||||
// Path.
|
||||
if (s[0] == '"')
|
||||
{
|
||||
s++;
|
||||
uint len = (uint)(RunToEOS(s, e) - s);
|
||||
include_path.Set(s, s + len);
|
||||
|
||||
s += SkipSpace(s + len + 1, e) - s;
|
||||
}
|
||||
else
|
||||
__ERR__(__LOG_E__ << "Unexpected character in #include directive.\n", NULL);
|
||||
}
|
||||
s++;
|
||||
|
||||
// Load external metafile.
|
||||
File tmp_file;
|
||||
|
||||
if (Parser::Load(include_path, tmp_file, true))
|
||||
{
|
||||
// Then transfer all tags to our current file.
|
||||
NMLFileForeach(t, tmp_file)
|
||||
{
|
||||
if (tmp_file.UnlinkRoot(t))
|
||||
tag.AddChild(t);
|
||||
else
|
||||
__LOG_E__ << "Could not relink root tag from included metafile.\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
__LOG_E__ << "Failed to include external metafile '" << include_path << "'.\n";
|
||||
}
|
||||
else if (!strncmp(s, "append", 6))
|
||||
__LOG_E__ << "Preprocessor directive #append deprecated.\n";
|
||||
else
|
||||
__ERR__(__LOG_E__ << "Unknown preprocessor directive, metatag '" << tag.name << "'.\n", NULL)
|
||||
|
||||
return s;
|
||||
}
|
||||
bool Parser::ParseTag(Tag &tag, const char *s, const char *e, const char **es)
|
||||
{
|
||||
// Safety net.
|
||||
s += SkipSpace(s, e) - s;
|
||||
if (s[0] != '<')
|
||||
return false;
|
||||
|
||||
// Get the tag id.
|
||||
#define MLTAG_ERROR(c) { __LOG_E__ << c; return false; }
|
||||
|
||||
const char *etn = s + 1;
|
||||
etn += SkipEntry(etn, e) - etn;
|
||||
if (String::strfindchar(s + 1, ':', etn) != etn)
|
||||
MLTAG_ERROR("':' is a path character and cannot be used in tag name.\n")
|
||||
if (String::strfindchar(s + 1, ';', etn) != etn)
|
||||
MLTAG_ERROR("';' is a path character and cannot be used in tag name.\n")
|
||||
|
||||
tag.name.Set(s + 1, etn);
|
||||
s = etn;
|
||||
|
||||
// Get tag type.
|
||||
s += SkipSpace(s, e) - s;
|
||||
if (s == e)
|
||||
MLTAG_ERROR("Mangled definition, metatag '" << tag.name << "'.\n")
|
||||
|
||||
switch (s[0])
|
||||
{
|
||||
case '>':
|
||||
s++;
|
||||
break;
|
||||
|
||||
// Node/real/integer/string.
|
||||
case '=':
|
||||
{
|
||||
s++;
|
||||
forever
|
||||
{
|
||||
s += SkipSpace(s, e) - s;
|
||||
if (s == e)
|
||||
MLTAG_ERROR("Mangled definition, metatag '" << tag.name << "'.\n")
|
||||
|
||||
// End of tag.
|
||||
if (s[0] == '>')
|
||||
{
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
|
||||
// Preprocessor directive.
|
||||
if (s[0] == '#')
|
||||
s = ParseTagPreprocessorDirective(tag, s + 1, e);
|
||||
|
||||
// Node.
|
||||
else if (s[0] == '<')
|
||||
{
|
||||
if (tag.GetValue().GetType() != Variant::VariantNone)
|
||||
MLTAG_ERROR("Incoherent type in tag '" << tag.name << "' declaration.\n")
|
||||
|
||||
Tag *stag = tag.tags.Add(new Tag)->Object();
|
||||
if (!ParseTag(*stag, s, e, &s))
|
||||
MLTAG_ERROR("")
|
||||
s += SkipSpace(s, e) - s;
|
||||
}
|
||||
|
||||
// Constant.
|
||||
else
|
||||
{
|
||||
if (tag.GetValue().GetType() != Variant::VariantNone)
|
||||
MLTAG_ERROR("Incoherent type in tag '" << tag.name << "' declaration.\n")
|
||||
|
||||
// Binary.
|
||||
if (s[0] == '=')
|
||||
{
|
||||
s++;
|
||||
if (!(s[0] >= '0' && s[0] <= '9'))
|
||||
MLTAG_ERROR("Expected encoded size in binary tag '" << tag.name << "' declaration.\n")
|
||||
|
||||
const char *ye = s;
|
||||
while (ye[0] >= '0' && ye[0] <= '9')
|
||||
ye++;
|
||||
if (ye[0] != ':')
|
||||
MLTAG_ERROR("Expected size delimiter in binary tag '" << tag.name << "' declaration.\n")
|
||||
uint asize = String(s, ye).Integer();
|
||||
|
||||
s = ye + 1;
|
||||
if (!(s[0] >= '0' && s[0] <= '9'))
|
||||
MLTAG_ERROR("Expected binary size in binary tag '" << tag.name << "' declaration.\n")
|
||||
ye = s;
|
||||
while (ye[0] >= '0' && ye[0] <= '9')
|
||||
ye++;
|
||||
|
||||
// Trailing @ means yEnc binary.
|
||||
File::Binary encoding = File::Binary_UU;
|
||||
if (ye[0] == '@')
|
||||
{
|
||||
encoding = File::Binary_yEnc;
|
||||
ye++;
|
||||
}
|
||||
|
||||
// Detect EOL
|
||||
if ((ye[0] != 0x0a) && ((ye[0] != 0x0d) && (ye[1] != 0x0a)))
|
||||
MLTAG_ERROR("Expected EOL following binary size in binary tag '" << tag.name << "' declaration.\n")
|
||||
|
||||
size_t eol_size = (ye[0] == 0x0a) ? 1 : 2;
|
||||
uint bsize = String(s, ye).Integer();
|
||||
|
||||
uchar *astart = (uchar *)(ye + eol_size);
|
||||
|
||||
// [EJ] Adjust asize to account for Windows EOL (historically NML only specifies Unix ascii size).
|
||||
if (eol_size > 1)
|
||||
{
|
||||
__LOG_V__ << "CRLF reduces NML binary load performance.\n";
|
||||
|
||||
size_t a_size_in = asize;
|
||||
asize = 0;
|
||||
|
||||
for (; a_size_in > 0; --a_size_in)
|
||||
if ((astart[asize] == 0x0d) && (astart[asize + 1] == 0x0a))
|
||||
asize += 2;
|
||||
else
|
||||
++asize;
|
||||
}
|
||||
// Load ASCII encoded data.
|
||||
Array <uchar> aenc(asize, Alloc::Metatag);
|
||||
if (!aenc)
|
||||
MLTAG_ERROR("Failed to allocate binary buffer in binary tag '" << tag.name << "'.\n")
|
||||
|
||||
memcpy(&aenc[0], astart, asize);
|
||||
|
||||
s = ye + eol_size + asize;
|
||||
if (s[0] != '>')
|
||||
MLTAG_ERROR("Expected closing tag in tag '" << tag.name << "'.\n")
|
||||
|
||||
Array <uchar> data(bsize, Alloc::Metatag);
|
||||
if (data)
|
||||
{
|
||||
switch (encoding)
|
||||
{
|
||||
case File::Binary_UU: nAsciiEncoder::UUDecode(&aenc[0], asize, &data[0], bsize); break;
|
||||
case File::Binary_yEnc: nAsciiEncoder::yDecode(&aenc[0], asize, &data[0], bsize); break;
|
||||
}
|
||||
tag.GetValue().SetBinary(&data[0], bsize);
|
||||
}
|
||||
}
|
||||
// Real/Integer.
|
||||
else if ((s[0] >= '0' && s[0] <= '9') || (s[0] == '.') || (s[0] == '-'))
|
||||
{
|
||||
if (IsConstantFloat(s, e))
|
||||
tag.GetValue() = String::atof(s, e, true);
|
||||
else tag.GetValue() = String::atoi(s);
|
||||
|
||||
if (s[0] == '-')
|
||||
s++;
|
||||
s += SkipEntry(s, e) - s;
|
||||
|
||||
if (s[0] != '>')
|
||||
MLTAG_ERROR("Unexpected trailing expression following value, metatag '" << tag.name << "'.\n")
|
||||
}
|
||||
// String.
|
||||
else if (s[0] == '\"')
|
||||
{
|
||||
s++;
|
||||
ptrdiff_t len = RunToEOS(s, e) - s;
|
||||
if ((s + len) == e)
|
||||
MLTAG_ERROR("Mangled string declaration, metatag '" << tag.name << "'.\n")
|
||||
|
||||
// Copy string.
|
||||
tag.GetValue() = String(s, s + len);
|
||||
|
||||
s += SkipSpace(s + len + 1, e) - s; // Jump over string.
|
||||
if (s == e)
|
||||
MLTAG_ERROR("Unexpected EOF after string declaration, metatag '" << tag.name << "'.\n")
|
||||
if (s[0] != '>')
|
||||
MLTAG_ERROR("Unexpected trailing expression following string object, metatag '" << tag.name << "'.\n")
|
||||
|
||||
tag.GetValue().s_value.ReplaceAll("\\n", "\n"); // convert CF
|
||||
}
|
||||
// Boolean.
|
||||
else if (!strncmp(s, "True", 4))
|
||||
{
|
||||
tag.GetValue() = true;
|
||||
s += SkipSpace(s + 4, e) - s;
|
||||
if (s[0] != '>')
|
||||
MLTAG_ERROR("Unexpected trailing expression following value, metatag '" << tag.name << "'.\n")
|
||||
}
|
||||
else if (!strncmp(s, "False", 5))
|
||||
{
|
||||
tag.GetValue() = false;
|
||||
s += SkipSpace(s + 5, e) - s;
|
||||
if (s[0] != '>')
|
||||
MLTAG_ERROR("Unexpected trailing expression following value, metatag '" << tag.name << "'.\n")
|
||||
}
|
||||
else
|
||||
MLTAG_ERROR("Unexpected '" << s[0] << "' in assignation, metatag '" << tag.name << "'.\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
MLTAG_ERROR("Unexpected trailing expression after metatag '" << tag.name << "' name declaration.\n")
|
||||
}
|
||||
if (es)
|
||||
es[0] = s;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Parser::LoadFromMemory(const char *data, size_t size, File &mfl)
|
||||
{
|
||||
mfl.Free();
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
// Read header tag, expected to be NML version.
|
||||
const char *pof = data, *eof = data + size;
|
||||
|
||||
#define MEM_MLP_ERROR(c) { (c); return false; }
|
||||
|
||||
Tag header_tag;
|
||||
if (!ParseTag(header_tag, pof, eof, &pof))
|
||||
MEM_MLP_ERROR(__LOG_E__ << "Invalid metafile.\n")
|
||||
if ((header_tag.name != "Version") && (header_tag.name != "NML"))
|
||||
MEM_MLP_ERROR(__LOG_E__ << "Unknown metafile variant.\n")
|
||||
|
||||
switch (header_tag.GetValue().GetType())
|
||||
{
|
||||
case Variant::VariantInteger:
|
||||
if (header_tag.GetInteger() > version)
|
||||
__LOG_W__ << "Newer version NML header found (" << header_tag.GetInteger() << ">" << version << ").\n";
|
||||
break;
|
||||
|
||||
case Variant::VariantFloat:
|
||||
if (header_tag.GetReal() > version)
|
||||
__LOG_W__ << "Newer version NML header found (" << header_tag.GetReal() << ">" << version << ").\n";
|
||||
break;
|
||||
|
||||
default:
|
||||
__LOG_W__ << "Unknown NML header version identification method.\n";
|
||||
break;
|
||||
}
|
||||
|
||||
// Read all root tags.
|
||||
while (pof < eof)
|
||||
{
|
||||
Tag *tag = mfl.tags.Add(new Tag)->Object();
|
||||
if (!ParseTag(*tag, pof, eof, &pof))
|
||||
return false;
|
||||
pof += SkipSpace(pof, eof) - pof;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Parser::Load(const char *path, File &file, bool verbose)
|
||||
{
|
||||
if (!path)
|
||||
return false;
|
||||
|
||||
Array <char> data;
|
||||
if (!Platform::Get().io->FileLoad(path, data, verbose))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
if (!LoadFromMemory(data.c_ptr(), data.GetSize(), file))
|
||||
return false;
|
||||
}
|
||||
catch (char *e)
|
||||
{
|
||||
__LOG_E__ << "Failed to load file LoadFromMemory. " << path << "\n";
|
||||
return false;
|
||||
}
|
||||
file.name = path;
|
||||
return true;
|
||||
}
|
||||
File *Parser::Load(const char *metafile, bool verbose)
|
||||
{
|
||||
AutoPtr <File> mfl(new File);
|
||||
if (mfl.IsNull())
|
||||
__ERR__(__LOG_E__ << "Failed to allocate file.\n", NULL)
|
||||
return Load(metafile, *mfl, verbose) ? mfl.Detach() : NULL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,97 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "metafile/nml.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::NML;
|
||||
|
||||
|
||||
static bool MetatagNameCompare(const Tag *o, const String &name) { return o->name == name; }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Tag *Tag::GetTagEx(const List <Tag *> &tg, const char *s, const File *, bool verbose)
|
||||
{
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
const char *path = s;
|
||||
const List <Tag *> *list = &tg;
|
||||
|
||||
Tag *tag = NULL;
|
||||
|
||||
while (s[0])
|
||||
{
|
||||
while (s[0] == ':')
|
||||
s++;
|
||||
if (s[0] == ';')
|
||||
break;
|
||||
|
||||
const char *t = s;
|
||||
while ((t[0] != ';') && (t[0] != ':') && t[0])
|
||||
t++;
|
||||
if (!t[0] && verbose)
|
||||
{
|
||||
if (t > s)
|
||||
__LOG_W__ << "incomplete path '" << path << "' (missing ';').\n";
|
||||
else __LOG_E__ << "unexpected end of path'" << path << "'.\n";
|
||||
}
|
||||
|
||||
// No more node to search.
|
||||
if (!list)
|
||||
{
|
||||
if (verbose)
|
||||
__LOG_W__ << "'" << path << "' is deeper than lowest tree node.\n";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
String node_name(s, t);
|
||||
s = t;
|
||||
tag = ListFindEx(*list, MetatagNameCompare, node_name);
|
||||
|
||||
if (tag == NULL)
|
||||
{
|
||||
if (verbose)
|
||||
__LOG__ << "!! Error '" << node_name << "' in '" << path << "' not found.\n";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (tag->GetValue().GetType())
|
||||
{
|
||||
case Variant::VariantNone:
|
||||
list = &tag->tags;
|
||||
break;
|
||||
|
||||
default:
|
||||
list = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
Tag *Tag::GetTag(const char *path, const File *root, bool verbose) const
|
||||
{
|
||||
return GetTagEx(tags, path, root, verbose);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Tag *Tag::GetTypedTag(const char *path, Variant::Type type, const File *root, bool verbose) const
|
||||
{
|
||||
Tag *t = Tag::GetTagEx(tags, path, root, verbose);
|
||||
if ((!t) || (t->GetValue().GetType() != type))
|
||||
return NULL;
|
||||
return t;
|
||||
}
|
||||
Tag *File::GetTypedTag(const char *path, Variant::Type type, bool verbose) const
|
||||
{
|
||||
Tag *t = Tag::GetTagEx(tags, path, this, verbose);
|
||||
if ((!t) || (t->GetValue().GetType() != type))
|
||||
return NULL;
|
||||
return t;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,152 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "metafile/nml.h"
|
||||
#include "ascii/ascii_encoder.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "filesystem/io_handle.h"
|
||||
#include "memory/nauto_ptr.h"
|
||||
#include "platform_config.h"
|
||||
#include "platform.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::NML;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Parser::SaveTag(IO::Handle &out, const Tag &tag, File::Binary method, uint idt)
|
||||
{
|
||||
//---------------------------------------------------------------------------
|
||||
#define OUTPUT_INDENT { for (uint n = 0; n < idt; n++) out << "\t"; }
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
if (tag.name.IsEmpty() && !tag.GetChildCount())
|
||||
return true; // silently skip this tag
|
||||
|
||||
OUTPUT_INDENT;
|
||||
out << "<" << tag.name.c_str();
|
||||
|
||||
switch (tag.GetValue().GetType())
|
||||
{
|
||||
case Variant::VariantNone:
|
||||
if (tag.GetChildCount())
|
||||
{
|
||||
out << "=\n";
|
||||
|
||||
NMLTagForeach(child, tag)
|
||||
if (!SaveTag(out, *child, method, idt + 1))
|
||||
return false;
|
||||
|
||||
OUTPUT_INDENT;
|
||||
}
|
||||
break;
|
||||
|
||||
case Variant::VariantBinary:
|
||||
{
|
||||
uint olen = (uint)~0;
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case File::Binary_UU:
|
||||
olen = nAsciiEncoder::UUEncode((uchar *)tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize());
|
||||
break;
|
||||
|
||||
case File::Binary_yEnc:
|
||||
olen = nAsciiEncoder::yEncode((uchar *)tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize());
|
||||
break;
|
||||
}
|
||||
|
||||
if (olen)
|
||||
{
|
||||
Array <uchar> aenc(olen, Alloc::Metatag);
|
||||
|
||||
if (aenc.IsValid())
|
||||
{
|
||||
uint asize = 0;
|
||||
switch (method)
|
||||
{
|
||||
case File::Binary_UU:
|
||||
asize = nAsciiEncoder::UUEncode((uchar *)tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize(), &aenc[0], olen);
|
||||
break;
|
||||
|
||||
case File::Binary_yEnc:
|
||||
asize = nAsciiEncoder::yEncode((uchar *)tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize(), &aenc[0], olen);
|
||||
break;
|
||||
}
|
||||
if (asize != olen)
|
||||
__LOG_W__ << "Internal ASCII encoding inconsistency detected while processing tag '" << tag.name << "'.\n";
|
||||
|
||||
char str[256];
|
||||
_snprintf(str, 255, "==%d:%d", asize, tag.GetValue().GetBinarySize()); // ==[encoded size:decoded size] is encoded binary.
|
||||
out << str;
|
||||
|
||||
if (method == File::Binary_yEnc) // @ marker select yEncoding.
|
||||
out << "@";
|
||||
out << "\n";
|
||||
|
||||
out.Write(aenc, asize);
|
||||
}
|
||||
else
|
||||
__LOG_E__ << "Tag '" << tag.name << "' failed to allocate internal binary buffer.\n";
|
||||
}
|
||||
// else __LOG_W__ << "NULL size ASCII encoded binary tag '" << tag.id << "'.\n";
|
||||
}
|
||||
break;
|
||||
|
||||
case Variant::VariantInteger:
|
||||
{
|
||||
char str[256];
|
||||
_snprintf(str, 255, "=%d", tag.GetInteger());
|
||||
out << str;
|
||||
}
|
||||
break;
|
||||
|
||||
case Variant::VariantFloat:
|
||||
{
|
||||
char str[256];
|
||||
_snprintf(str, 255, "=%f", tag.GetReal());
|
||||
out << str;
|
||||
}
|
||||
break;
|
||||
|
||||
case Variant::VariantString:
|
||||
out << "=\"" << tag.GetString() << "\"";
|
||||
break;
|
||||
|
||||
case Variant::VariantBool:
|
||||
out << "=" << (tag.GetBool() ? "True" : "False");
|
||||
break;
|
||||
|
||||
default:
|
||||
__ERR__(__LOG_E__ << "No method to output tag '" << tag.name << "' type.\n", false)
|
||||
}
|
||||
|
||||
out << ">\n";
|
||||
return true;
|
||||
}
|
||||
bool Parser::Save(IO::Handle &h, const File &file)
|
||||
{
|
||||
h << "<Version=1.0>\n";
|
||||
NMLFileForeach(tag, file)
|
||||
if (!SaveTag(h, *tag, file.GetBinaryMethod(), 0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool Parser::Save(const char *uri, const File &file)
|
||||
{
|
||||
if (!uri)
|
||||
return false;
|
||||
|
||||
AutoPtr <IO::Handle> h(Platform::Get().io->Open(uri, IO::ModeWrite));
|
||||
if (h.IsNull())
|
||||
__ERR__(__LOG_E__ << "Failed to open nml output '" << uri << "'.\n", false)
|
||||
|
||||
return Save(*h, file);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,65 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "metafile/nml_string.h"
|
||||
#include "metafile/nml.h"
|
||||
#include "filesystem/io_memory.h"
|
||||
#include "memory/nauto_ptr.h"
|
||||
#include "nstring/nstring.h"
|
||||
#include "log/log.h"
|
||||
|
||||
|
||||
namespace GS {
|
||||
namespace NML {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool TagToString(const Tag &tag, String &str)
|
||||
{
|
||||
IO::Memory memory_fs;
|
||||
|
||||
AutoPtr <IO::Handle> h(memory_fs.Open("file", IO::ModeWrite));
|
||||
if (h.IsNull() || !Parser::SaveTag(*h, tag))
|
||||
return false;
|
||||
h = NULL;
|
||||
|
||||
Array <char> data;
|
||||
if (!memory_fs.FileLoad("file", data))
|
||||
return false;
|
||||
|
||||
str.Set(data.Start(), data.End());
|
||||
return true;
|
||||
}
|
||||
bool TagFromString(const String &str, Tag &tag)
|
||||
{
|
||||
return Parser::ParseTag(tag, str.c_str(), &str.c_str()[str.Len()]);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool FileToString(const File &file, String &str)
|
||||
{
|
||||
IO::Memory memory_fs;
|
||||
|
||||
AutoPtr <IO::Handle> h(memory_fs.Open("file", IO::ModeWrite));
|
||||
if (h.IsNull() || !Parser::Save(*h, file))
|
||||
return false;
|
||||
h = NULL;
|
||||
|
||||
Array <char> data;
|
||||
if (!memory_fs.FileLoad("file", data))
|
||||
return false;
|
||||
|
||||
str.Set(data.Start(), data.End());
|
||||
return true;
|
||||
}
|
||||
bool FileFromString(const String &str, File &file)
|
||||
{
|
||||
return Parser::LoadFromMemory(str.c_str(), str.Len(), file);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
} // NML
|
||||
} // GS
|
||||
@@ -0,0 +1,121 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "metafile/nml.h"
|
||||
#include "filesystem/io_handle.h"
|
||||
#include "alloc/ialloc.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS::NML;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Tag *Tag::GetParent(Tag *root) const
|
||||
{
|
||||
ListForeachPtr(Tag *, child, root->GetTags())
|
||||
if (child == this)
|
||||
return root;
|
||||
|
||||
Tag *parent = NULL;
|
||||
ListForeachPtr(Tag *, child, root->GetTags())
|
||||
if ((parent = GetParent(child)) != NULL)
|
||||
break;
|
||||
|
||||
return parent;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Tag *Tag::AddChild(Tag *t)
|
||||
{
|
||||
if (!t)
|
||||
return NULL;
|
||||
if (value.type != Variant::VariantNone)
|
||||
__ERR__(__LOG_E__ << "Cannot add child to tag '" << name << "' as it is neither a pure tag or a node.\n", NULL)
|
||||
if (!tags.Add(t))
|
||||
return NULL;
|
||||
return t;
|
||||
}
|
||||
Tag *Tag::AddChild(const char *name)
|
||||
{ return AddChild(new Tag(name)); }
|
||||
Tag *Tag::AddChild(const char *name, bool v)
|
||||
{ return AddChild(new Tag(name, v)); }
|
||||
Tag *Tag::AddChild(const char *name, int v)
|
||||
{ return AddChild(new Tag(name, v)); }
|
||||
Tag *Tag::AddChild(const char *name, uint v)
|
||||
{ return AddChild(new Tag(name, v)); }
|
||||
Tag *Tag::AddChild(const char *name, float v)
|
||||
{ return AddChild(new Tag(name, v)); }
|
||||
Tag *Tag::AddChild(const char *name, const char *s)
|
||||
{ return AddChild(new Tag(name, s)); }
|
||||
Tag *Tag::AddChild(const char *name, void *buffer, size_t size)
|
||||
{ return AddChild(new Tag(name, buffer, size)); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Tag::Clone(const Tag &src, bool recursive)
|
||||
{
|
||||
Free();
|
||||
|
||||
value = src.GetValue();
|
||||
|
||||
if (recursive)
|
||||
ListForeachPtr(Tag *, ct, src.GetTags())
|
||||
AddChild(ct->Clone(true));
|
||||
|
||||
return true;
|
||||
}
|
||||
Tag *Tag::Clone(bool recursive) const
|
||||
{
|
||||
Tag *clone = new Tag(name);
|
||||
if (!clone)
|
||||
return NULL;
|
||||
|
||||
// Copy tag content.
|
||||
clone->GetValue() = value;
|
||||
|
||||
// Clone children.
|
||||
if (recursive)
|
||||
ListForeachPtr(Tag *, ct, tags)
|
||||
clone->AddChild(ct->Clone(true));
|
||||
|
||||
return clone;
|
||||
}
|
||||
uint Tag::DeleteChildren(const char *filter)
|
||||
{
|
||||
uint count = 0;
|
||||
|
||||
if (filter)
|
||||
{
|
||||
String _filter(filter);
|
||||
|
||||
ListForeachPtr(Tag *, t, tags)
|
||||
if (t->name == _filter)
|
||||
{
|
||||
tags.Remove(t);
|
||||
_safe_delete(t);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
ListDeleteAllPtr(Tag *, tags)
|
||||
|
||||
return count;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Tag::Free()
|
||||
{
|
||||
value.Free();
|
||||
DeleteChildren();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Tag::~Tag()
|
||||
{ Free(); }
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user