Nicer XML-writing system

This was SVN commit r1711.
This commit is contained in:
Ykkrosh
2005-01-11 20:15:39 +00:00
parent cc0acc8691
commit fc4a34d768
4 changed files with 348 additions and 101 deletions
+1 -1
View File
@@ -149,7 +149,7 @@ void CMapReader::ApplyData(CFileUnpacker& unpacker, CTerrain *pTerrain, CUnitMan
CObjectEntry* objentry=m_ObjectTypes[m_Objects[i].m_ObjectIndex];
if (objentry && objentry->m_Model) {
// Hijack the standard actor instantiation for actors that correspond to entities.
// Not an ideal solution; we'll have to figure out a map format that can define entities seperately or somesuch.
// Not an ideal solution; we'll have to figure out a map format that can define entities separately or somesuch.
CBaseEntity* templateObject = g_EntityTemplateCollection.getTemplateByActor( objentry );
+60 -100
View File
@@ -12,6 +12,7 @@
#include "Unit.h"
#include "ps/Xeromyces.h"
#include "ps/XMLWriter.h"
#include "lib/res/vfs.h"
@@ -201,7 +202,7 @@ bool CObjectEntry::Load(const char* filename)
XMBElementList children = root.getChildNodes();
for (int i = 0; i < children.Count; ++i) {
// Get node
XMBElement child = children.item(i);
int element_name = child.getNodeName();
@@ -220,15 +221,19 @@ bool CObjectEntry::Load(const char* filename)
m_Material = element_value;
else if (element_name == el_properties) {
XMBAttributeList attributes=child.getAttributes();
for (int j = 0; j < attributes.Count; ++j) {
XMBAttribute attrib=attributes.item(j);
int attrib_name = attrib.Name;
if (attrib_name == at_autoflatten) {
CStr str= (CStr) attrib.Value;
CStr str (attrib.Value);
m_Properties.m_AutoFlatten=str.ToInt() ? true : false;
} else if (attrib_name == at_castshadows) {
CStr str= (CStr) attrib.Value;
CStr str = (attrib.Value);
m_Properties.m_CastShadows=str.ToInt() ? true : false;
}
}
@@ -244,9 +249,9 @@ bool CObjectEntry::Load(const char* filename)
if (attributes.Count) {
Anim anim;
anim.m_AnimName = (CStr)attributes.getNamedItem(at_name);
anim.m_FileName = (CStr)attributes.getNamedItem(at_file);
CStr speedstr = (CStr)attributes.getNamedItem(at_speed);
anim.m_AnimName = attributes.getNamedItem(at_name);
anim.m_FileName = attributes.getNamedItem(at_file);
CStr speedstr = attributes.getNamedItem(at_speed);
anim.m_Speed=float(speedstr.ToInt())/100.0f;
if (anim.m_Speed<=0.0) anim.m_Speed=1.0f;
@@ -265,8 +270,8 @@ bool CObjectEntry::Load(const char* filename)
if (attributes.Count) {
Prop prop;
prop.m_PropPointName = (CStr)attributes.getNamedItem(at_attachpoint);
prop.m_ModelName = (CStr)attributes.getNamedItem(at_model);
prop.m_PropPointName = attributes.getNamedItem(at_attachpoint);
prop.m_ModelName = attributes.getNamedItem(at_model);
m_Props.push_back(prop);
}
@@ -278,72 +283,8 @@ bool CObjectEntry::Load(const char* filename)
}
// TODO: Make this less hacky, and maybe make it part of the VFS
void vfs_printf(Handle h, const char* fmt, ...)
{
va_list va;
va_start(va, fmt);
char buf[1024];
int r = vsnprintf(buf, sizeof(buf), fmt, va);
if (r < 0 || r >= sizeof(buf))
{
// TODO: Handle this properly
debug_warn("Argh - too much stuff in vfs_printf");
return;
}
char *bufp = buf;
if (vfs_io(h, strlen(buf), (void**)&bufp) < 0)
{
debug_warn("vfs_io failed");
}
}
bool CObjectEntry::Save(const char* filename)
{
/*
FILE* fp=fopen(filename,"w");
if (!fp) return false;
// write XML header
fprintf(fp,"<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>\n\n");
fprintf(fp,"<!DOCTYPE Object SYSTEM \"/art/actors/object.dtd\">\n\n");
// write the object itself
fprintf(fp,"<!-- File automatically generated by ScEd -->\n");
fprintf(fp,"<Object>\n");
fprintf(fp,"\t<Name>%s</Name>\n",(const char*) m_Name);
fprintf(fp,"\t<ModelName>%s</ModelName>\n",(const char*) m_ModelName);
fprintf(fp,"\t<TextureName>%s</TextureName>\n",(const char*) m_TextureName);
if(m_Material.Trim(PS_TRIM_BOTH).Length())
fprintf(fp,"\t<Material>%s</Material>\n", (const char*)m_Material);
fprintf(fp,"\t<Properties\n");
fprintf(fp,"\t\tautoflatten=\"%d\"\n",m_Properties.m_AutoFlatten ? 1 : 0);
fprintf(fp,"\t\tcastshadows=\"%d\"\n",m_Properties.m_CastShadows ? 1 : 0);
fprintf(fp,"\t/>\n");
if (m_Animations.size()>0) {
fprintf(fp,"\t<Animations>\n");
for (uint i=0;i<m_Animations.size();i++) {
fprintf(fp,"\t\t<Animation name=\"%s\" file=\"%s\" speed=\"%d\"/>\n",(const char*) m_Animations[i].m_AnimName,(const char*) m_Animations[i].m_FileName,int(m_Animations[i].m_Speed*100));
}
fprintf(fp,"\t</Animations>\n");
}
if (m_Props.size()>0) {
fprintf(fp,"\t<Props>\n");
for (uint i=0;i<m_Props.size();i++) {
fprintf(fp,"\t\t<Prop attachpoint=\"%s\" model=\"%s\"/>\n",(const char*) m_Props[i].m_PropPointName,(const char*) m_Props[i].m_ModelName);
}
fprintf(fp,"\t</Props>\n");
}
fprintf(fp,"</Object>\n");
fclose(fp);
return true;
*/
Handle h = vfs_open(filename, FILE_WRITE|FILE_NO_AIO);
if (h <= 0)
{
@@ -351,43 +292,62 @@ bool CObjectEntry::Save(const char* filename)
return false;
}
// write XML header
vfs_printf(h,"<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>\n\n");
vfs_printf(h,"<!DOCTYPE Object SYSTEM \"/art/actors/object.dtd\">\n\n");
XML_Start("iso-8859-1");
XML_Doctype("Object", "/art/actors/object.dtd");
// write the object itself
vfs_printf(h,"<!-- File automatically generated by ScEd -->\n");
vfs_printf(h,"<Object>\n");
vfs_printf(h,"\t<Name>%s</Name>\n",(const char*) m_Name);
vfs_printf(h,"\t<ModelName>%s</ModelName>\n",(const char*) m_ModelName);
vfs_printf(h,"\t<TextureName>%s</TextureName>\n",(const char*) m_TextureName);
XML_Comment("File automatically generated by ScEd");
if(m_Material.Trim(PS_TRIM_BOTH).Length())
vfs_printf(h,"\t<Material>%s</Material>\n", (const char*)m_Material);
{
XML_Element("Object");
vfs_printf(h,"\t<Properties\n");
vfs_printf(h,"\t\tautoflatten=\"%d\"\n",m_Properties.m_AutoFlatten ? 1 : 0);
vfs_printf(h,"\t\tcastshadows=\"%d\"\n",m_Properties.m_CastShadows ? 1 : 0);
vfs_printf(h,"\t/>\n");
XML_Setting("Name", m_Name);
XML_Setting("ModelName", m_ModelName);
XML_Setting("TextureName", m_TextureName);
if (m_Animations.size()>0) {
vfs_printf(h,"\t<Animations>\n");
for (uint i=0;i<m_Animations.size();i++) {
vfs_printf(h,"\t\t<Animation name=\"%s\" file=\"%s\" speed=\"%d\"/>\n",(const char*) m_Animations[i].m_AnimName,(const char*) m_Animations[i].m_FileName,int(m_Animations[i].m_Speed*100));
if(m_Material.Trim(PS_TRIM_BOTH).Length())
XML_Setting("Material", m_Material);
{
XML_Element("Properties");
XML_Attribute("autoflatten", m_Properties.m_AutoFlatten ? 1 : 0);
XML_Attribute("castshadows", m_Properties.m_CastShadows ? 1 : 0);
}
vfs_printf(h,"\t</Animations>\n");
}
if (m_Props.size()>0) {
vfs_printf(h,"\t<Props>\n");
for (uint i=0;i<m_Props.size();i++) {
vfs_printf(h,"\t\t<Prop attachpoint=\"%s\" model=\"%s\"/>\n",(const char*) m_Props[i].m_PropPointName,(const char*) m_Props[i].m_ModelName);
if (m_Animations.size()>0)
{
XML_Element("Animations");
for (uint i=0;i<m_Animations.size();i++)
{
XML_Element("Animation");
XML_Attribute("name", m_Animations[i].m_AnimName);
XML_Attribute("file", m_Animations[i].m_FileName);
XML_Attribute("speed", int(m_Animations[i].m_Speed*100));
}
}
if (m_Props.size()>0)
{
XML_Element("Props");
for (uint i=0;i<m_Props.size();i++)
{
XML_Element("Prop");
XML_Attribute("attachpoint", m_Props[i].m_PropPointName);
XML_Attribute("model", m_Props[i].m_ModelName);
}
}
vfs_printf(h,"\t</Props>\n");
}
vfs_printf(h,"</Object>\n");
if (! XML_StoreVFS(h))
{
// Error occurred while saving data
debug_warn("actor save failed");
vfs_close(h);
return false;
}
vfs_close(h);
return true;
}
+155
View File
@@ -0,0 +1,155 @@
#include "precompiled.h"
#include "XMLWriter.h"
#include "ps/CLogger.h"
#include "lib/res/vfs.h"
enum { EL_ATTR, EL_TEXT, EL_SUBEL };
XMLWriter_File::XMLWriter_File(const char* encoding)
: m_LastElement(NULL), m_Indent(0)
{
m_Data = "<?xml version=\"1.0\" encoding=\"";
m_Data += encoding;
m_Data += "\" standalone=\"no\"?>\n";
}
void XMLWriter_File::Doctype(const char* type, const char* dtd)
{
m_Data += "<!DOCTYPE ";
m_Data += type;
m_Data += " SYSTEM \"";
m_Data += dtd;
m_Data += "\">\n";
}
bool XMLWriter_File::StoreVFS(Handle h)
{
if (m_LastElement) debug_warn("ERROR: Saving XML while an element is still open");
void* data = (void*)m_Data.data();
int err = vfs_io(h, m_Data.Length(), &data);
if (err < 0)
{
LOG(ERROR, "xml", "Error saving XML data through VFS: %lld", h);
return false;
}
return true;
}
void XMLWriter_File::Comment(const char* text)
{
ElementStart(NULL, "!-- ");
m_Data += text;
m_Data += " -->";
--m_Indent;
}
CStr XMLWriter_File::Indent()
{
return std::string(m_Indent, '\t');
}
void XMLWriter_File::ElementStart(XMLWriter_Element* element, const char* name)
{
if (m_LastElement) m_LastElement->Close(EL_SUBEL);
m_LastElement = element;
m_Data += "\n" + Indent() + "<" + name;
++m_Indent;
}
void XMLWriter_File::ElementClose()
{
m_Data += ">";
}
void XMLWriter_File::ElementEnd(const char* name, int type)
{
--m_Indent;
m_LastElement = NULL;
switch (type)
{
case EL_ATTR:
m_Data += " />";
break;
case EL_TEXT:
m_Data += "</";
m_Data += name;
m_Data += ">";
break;
case EL_SUBEL:
m_Data += "\n" + Indent() + "</" + name += ">";
break;
default:
assert(0);
}
}
void XMLWriter_File::ElementText(const char* text)
{
m_Data += text;
}
XMLWriter_Element::XMLWriter_Element(XMLWriter_File& file, const char* name)
: m_File(&file), m_Name(name), m_Type(EL_ATTR)
{
m_File->ElementStart(this, name);
}
XMLWriter_Element::~XMLWriter_Element()
{
m_File->ElementEnd(m_Name, m_Type);
}
void XMLWriter_Element::Close(int type)
{
m_File->ElementClose();
m_Type = type;
}
void XMLWriter_Element::Text(const char* text)
{
Close(EL_TEXT);
m_File->ElementText(text);
}
template <> void XMLWriter_File::ElementAttribute<CStr>(const char* name, CStr& value, bool newelement)
{
if (newelement)
{
ElementStart(NULL, name);
m_Data += ">";
ElementText(value);
ElementEnd(name, EL_TEXT);
}
else
{
assert(m_LastElement && m_LastElement->m_Type == EL_ATTR);
m_Data += " ";
m_Data += name;
m_Data += "=\"" + value + "\"";
}
}
// Attribute/setting value-to-string template specialisations:
// Use CStr's conversion for most types:
#define TYPE(T) \
template <> void XMLWriter_File::ElementAttribute<T>(const char* name, T& value, bool newelement) \
{ \
ElementAttribute(name, CStr(value), newelement); \
}
TYPE(int)
TYPE(float)
TYPE(double)
TYPE(const char*)
+132
View File
@@ -0,0 +1,132 @@
#ifndef XMLWRITER_H
#define XMLWRITER_H
/*
System for writing simple XML files, with human-readable formatting.
Example usage:
XML_Start("utf-8");
XML_Doctype("Scenario", "/maps/scenario.dtd");
{
XML_Element("Scenario");
{
XML_Element("Entities");
for (...)
{
XML_Element("Entity");
{
XML_Element("Template");
XML_Text(entity.name);
}
// Or equivalently:
XML_Setting("Template", entity.name);
{
XML_Element("Position");
XML_Attribute("x", entity.x);
XML_Attribute("y", entity.y);
XML_Attribute("z", entity.z);
}
{
XML_Element("Orientation");
XML_Attribute("angle", entity.angle);
}
}
}
}
Handle h = vfs_open("/test.xml", FILE_WRITE|FILE_NO_AIO);
XML_StoreVFS(h);
In general, "{ XML_Element(name); ... }" means "<name> ... </name>" -- the
scoping braces are important to indicate where an element ends.
XML_Attribute/XML_Setting are templated. To support more types, alter the
end of XMLWriter.cpp.
*/
// Encoding should usually be "iso-8859-1" or "utf-8"
#define XML_Start(encoding) XMLWriter_File xml_file_ (encoding)
// Set the doctype/DTD (e.g. "Object", "/art/actors/object.dtd")
#define XML_Doctype(type, dtd) xml_file_.Doctype(type, dtd)
// Add a comment to the XML file: <!-- text -->
#define XML_Comment(text) xml_file_.Comment(text)
// Start a new element: <name ...>
#define XML_Element(name) XMLWriter_Element xml_element_ (xml_file_, name)
// Add text to the interior of the current element: ...>text</...>
#define XML_Text(text) xml_element_.Text(text)
// Add an attribute to the current element: <... name="value" ...>
#define XML_Attribute(name, value) xml_element_.Attribute(name, value)
// Add a 'setting': <name>value</name>
#define XML_Setting(name, value) xml_element_.Setting(name, value)
// Output the XML file to a VFS handle, which must be opened with FILE_WRITE|FILE_NO_AIO.
// Returns true on success, false (and logs an error) on failure.
#define XML_StoreVFS(handle) xml_file_.StoreVFS(handle)
#include "ps/CStr.h"
#include "lib/res/handle.h"
class XMLWriter_Element;
class XMLWriter_File
{
public:
XMLWriter_File(const char* encoding);
void Doctype(const char* type, const char* dtd);
void Comment(const char* text);
bool StoreVFS(Handle h);
private:
friend class XMLWriter_Element;
void ElementStart(XMLWriter_Element* element, const char* name);
void ElementText(const char* text);
template <typename T> void ElementAttribute(const char* name, T& value, bool newelement);
void ElementClose();
void ElementEnd(const char* name, int type);
CStr Indent();
CStr m_Data;
int m_Indent;
XMLWriter_Element* m_LastElement;
};
class XMLWriter_Element
{
public:
XMLWriter_Element(XMLWriter_File& file, const char* name);
~XMLWriter_Element();
void Text(const char* text);
template <typename T> void Attribute(const char* name, T value) { m_File->ElementAttribute(name, value, false); }
template <typename T> void Setting(const char* name, T value) { m_File->ElementAttribute(name, value, true); }
void Close(int type);
private:
friend class XMLWriter_File;
XMLWriter_File* m_File;
CStr m_Name;
int m_Type;
};
#endif // XMLWRITER_H