/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #ifndef __NMETALANG__ #define __NMETALANG__ #include "data/nvariant.h" #include "container/nlist.h" namespace GS { namespace IO { class Handle; } namespace NML { class Tag; class File; static const int version = 1; /// Metatag. class Tag { friend struct Parser; friend class File; protected: /// Locate a tag through its path. static Tag *GetTagEx(const List &tag, const char *path, const File *root = 0, bool verbose = false); List tags; Variant value; public: NPLACEMENT_NEW(Metatag) String name; /// Get this tag parent by exploring a given tag hierarchy. Tag *GetParent(Tag *) const; /// Get value. Variant &GetValue() { return value; } const Variant &GetValue() const { return value; } /// Remove a child tag from this tag. bool RemoveTag(Tag *t) { return tags.Remove(t); } /// Delete all child tags. uint DeleteChildren(const char *filter = 0); /// Get child count. uint GetChildCount() const { return tags.GetCount(); } /// Return the tag children list. const List &GetTags() const { return tags; } /// Add child to tag. Tag *AddChild(Tag *); Tag *AddChild(const char *); Tag *AddChild(const char *, bool); Tag *AddChild(const char *, int); Tag *AddChild(const char *, uint); Tag *AddChild(const char *, float); Tag *AddChild(const char *, const char *); Tag *AddChild(const char *, void *, size_t); /// Return tag child. Tag *GetTag(const char *path, const File * = 0, bool verbose = false) const; /// Return the tag at a given path only if it matches the required type. Tag *GetTypedTag(const char *path, Variant::Type, const File * = 0, bool verbose = false) const; bool GetBool() const { bool v; if (value.Get(v)) return v; return false; } int GetInteger() const { return value.i_value; } uint GetUnsigned() const { return value.u_value; } const char *GetString() const { return value.s_value; } float GetReal() const { return value.f_value; } void SetBool(bool v) { value = v; } void SetInteger(int v) { value = v; } void SetUnsigned(uint v) { value = v; } void SetString(const char *v) { value = v; } void SetReal(float v) { value = v; } Variant::Type GetType() const { return value.GetType(); } /// Clone a tag and optionally recurse and clone its children. bool Clone(const Tag &src, bool recursive = true); /// Clone this tag and optionally recurse and clone its children. Tag *Clone(bool recursive = true) const; /// Free the tag data, set its type to nVariant::VariantNone. void Free(); Tag() {} Tag(const char *n) : name(n) {} Tag(const char *n, bool v) : name(n), value(v) {} Tag(const char *n, int v) : name(n), value(v) {} Tag(const char *n, uint v) : name(n), value(v) {} Tag(const char *n, float v) : name(n), value(v) {} Tag(const char *n, const char *v) : name(n), value(v) {} Tag(const char *n, void *data, size_t size) : name(n), value(data, size) {} ~Tag(); }; /*! @short Meta file. A metafile contain the whole database in memory. This class is not meant to be used with heavy databases. Tags can be accessed using tag paths. A tag path is formatted as follow: "root:node:...:tag;". @note The closing hyphen is not required but warnings will be sent to the log if you don't use it. The node delimiter ':' can be repeated any number of time between nodes with no effect (eg: ":::node1::node2:;"). By definition a file is a node tag and cannot have a value. @author Emmanuel Julien (ejulien@gsworks.fr) */ class File { friend struct Parser; public: enum Binary { Binary_UU = 0, ///< UUEncoded. Binary_yEnc ///< yEncoded. }; protected: List tags; Binary binary_method; ///< Binary encoding method. public: String name; /// Get the file ASCII binary encoding method. Binary GetBinaryMethod() const { return binary_method; } const List &GetTags() const { return tags; } uint GetRootCount() const { return tags.GetCount(); } void Clear() { ListDeleteAllPtr(Tag *, tags); } bool isEmpty() const { return asbool(GetRootCount() == 0); } /// Add a root tag to the file. Tag *AddRoot(Tag *); Tag *AddRoot(const char *); Tag *AddRoot(const char *, bool); Tag *AddRoot(const char *, int); Tag *AddRoot(const char *, float); Tag *AddRoot(const char *, const char *); Tag *AddRoot(const char *, void *, size_t); /// Unlink a root tag from file. bool UnlinkRoot(Tag *); /// Return the tag at a given path. Tag *GetTag(const char *path, bool verbose = false) const { return Tag::GetTagEx(tags, path, this, verbose); } /// Return the tag at a given path only if it match the required type. Tag *GetTypedTag(const char *path, Variant::Type, bool verbose = false) const; bool GetBool(const char *path, bool _default = false, bool verbose = false) const; int GetInteger(const char *path, int _default = -1, bool verbose = false) const; float GetReal(const char *path, float _default = -1.f, bool verbose = false) const; const char *GetString(const char *path, const char *_default = 0, bool verbose = false) const; /// Duplicate the structure of a source file into this file. void Import(const File &, bool clear_before_import = true); /// Clone a file and all its tags. File *Clone() const; void Free(); File() : binary_method(Binary_yEnc) {} ~File(); }; /*! @short Meta file parser. @author Emmanuel Julien (ejulien@gsworks.fr) */ struct Parser { static const char *ParseTagPreprocessorDirective(Tag &tag, const char *s, const char *e); static bool IsMetafile(const char *); static bool SaveBinaryTag(IO::Handle &, const Tag &, File::Binary = File::Binary_yEnc); static bool SaveTag(IO::Handle &, const Tag &, File::Binary = File::Binary_yEnc, uint idt = 0); static bool ParseTag(Tag &, const char *s, const char *e, const char **r = 0); static bool LoadFromMemory(const char *, size_t, File &); static File *Load(const char *, bool verbose = true); static bool Load(const char *, File &, bool verbose = true); static bool Save(IO::Handle &, const File &); static bool Save(const char *, const File &); static bool SaveBinary(IO::Handle &, const File &); static bool SaveBinary(const char *, const File &); }; #define NMLTagForeach(__I__, __T__) ListForeachPtr(GS::NML::Tag *, __I__, (__T__).GetTags()) #define NMLFileForeach(__I__, __F__) ListForeachPtr(GS::NML::Tag *, __I__, (__F__).GetTags()) } // NML } // GS #endif // __NMETALANG__