ParamNode: switch to utf8, ToXML -> ToXMLString, test tweak, PCH tweak

This changes ParamNode to use UTF8 values internally (XMB files are UTF8
since cb9d0733ef).
This removes the need for a lot of conversions, speeding things up and
allows cleaning up the validator interface & a few other callsites.
ConstructJSVal could be a tad slower because of UTF8->16 conversions
within Spidermonkey; but the difference is unlikely to be noticeable in
practica.

Also:
- Changes `ToXML` to `ToXMLString` for clarity.
- Add a simple "op" test & show a particular behaviour of merge nodes
that I intend to change somewhat in D3830.
- Remove Component.h from simulation2 PCH - brought in too much.

Tested by: langbart
Differential Revision: https://code.wildfiregames.com/D3834
This was SVN commit r25228.
This commit is contained in:
wraitii 2021-04-11 09:23:10 +00:00
parent fcc6bbe797
commit 35ed55cfd6
22 changed files with 224 additions and 226 deletions

View file

@ -132,7 +132,7 @@ bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefi
XMLWriter_File shaderFile;
shaderFile.SetPrettyPrint(false);
shaderFile.XMB(XeroFile);
bool ok = CXeromyces::ValidateEncoded("shader", wstring_from_utf8(name), shaderFile.GetOutput());
bool ok = CXeromyces::ValidateEncoded("shader", name, shaderFile.GetOutput());
if (!ok)
return false;
}

View file

@ -229,7 +229,7 @@ public:
RelaxNGValidator v;
TS_ASSERT(v.LoadGrammar("<element xmlns='http://relaxng.org/ns/structure/1.0' datatypeLibrary='http://www.w3.org/2001/XMLSchema-datatypes' name='test'><data type='decimal'/></element>"));
TS_ASSERT(v.Validate(L"doc", L"<test>2.0</test>"));
TS_ASSERT(v.Validate("doc", "<test>2.0</test>"));
copyFile(srcDAE, testDAE);
copyFile(srcSkeletonDefs, testSkeletonDefs);
@ -237,7 +237,7 @@ public:
TS_ASSERT(modeldef);
if (modeldef) TS_ASSERT_PATH_EQUALS(modeldef->GetName(), testBase);
TS_ASSERT(v.Validate(L"doc", L"<test>2.0</test>"));
TS_ASSERT(v.Validate("doc", "<test>2.0</test>"));
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -23,7 +23,6 @@
// The simulation has many header files (component interfaces) which are quick to compile on their own
// but bring in a lot of headers indirectly. Adding these to the precompiled header
// cuts down compilation time by about half.
#include "simulation2/system/Component.h"
#include "simulation2/system/Interface.h"
#include "simulation2/system/InterfaceScripted.h"
#include "maths/FixedVector2D.h"

View file

@ -127,14 +127,14 @@ bool RelaxNGValidator::LoadGrammarFile(const PIVFS& vfs, const VfsPath& grammarP
return LoadGrammar(file.DecodeUTF8());
}
bool RelaxNGValidator::Validate(const std::wstring& filename, const std::wstring& document) const
bool RelaxNGValidator::Validate(const std::string& filename, const std::string& document) const
{
std::string docutf8 = "<?xml version='1.0' encoding='utf-8'?>" + utf8_from_wstring(document);
std::string docutf8 = "<?xml version='1.0' encoding='utf-8'?>" + document;
return ValidateEncoded(filename, docutf8);
}
bool RelaxNGValidator::ValidateEncoded(const std::wstring& filename, const std::string& document) const
bool RelaxNGValidator::ValidateEncoded(const std::string& filename, const std::string& document) const
{
TIMER_ACCRUE(xml_validation);
@ -144,10 +144,10 @@ bool RelaxNGValidator::ValidateEncoded(const std::wstring& filename, const std::
return false;
}
xmlDocPtr doc = xmlReadMemory(document.c_str(), (int)document.size(), utf8_from_wstring(filename).c_str(), NULL, XML_PARSE_NONET);
xmlDocPtr doc = xmlReadMemory(document.c_str(), (int)document.size(), filename.c_str(), NULL, XML_PARSE_NONET);
if (doc == NULL)
{
LOGERROR("RelaxNGValidator: Failed to parse document '%s'", utf8_from_wstring(filename).c_str());
LOGERROR("RelaxNGValidator: Failed to parse document '%s'", filename.c_str());
return false;
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2015 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -40,9 +40,9 @@ public:
MD5 GetGrammarHash() const { return m_Hash; }
bool Validate(const std::wstring& filename, const std::wstring& document) const;
bool Validate(const std::string& filename, const std::string& document) const;
bool ValidateEncoded(const std::wstring& filename, const std::string& document) const;
bool ValidateEncoded(const std::string& filename, const std::string& document) const;
bool ValidateEncoded(xmlDocPtr doc) const;

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -92,7 +92,7 @@ bool CXeromyces::AddValidator(const PIVFS& vfs, const std::string& name, const V
return true;
}
bool CXeromyces::ValidateEncoded(const std::string& name, const std::wstring& filename, const std::string& document)
bool CXeromyces::ValidateEncoded(const std::string& name, const std::string& filename, const std::string& document)
{
std::lock_guard<std::mutex> lock(g_ValidatorCacheLock);
return GetValidator(name).ValidateEncoded(filename, document);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2015 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -74,7 +74,7 @@ public:
static bool AddValidator(const PIVFS& vfs, const std::string& name, const VfsPath& grammarPath);
static bool ValidateEncoded(const std::string& name, const std::wstring& filename, const std::string& document);
static bool ValidateEncoded(const std::string& name, const std::string& filename, const std::string& document);
private:
static RelaxNGValidator& GetValidator(const std::string& name);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2015 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -39,21 +39,21 @@ public:
RelaxNGValidator v;
TS_ASSERT(v.LoadGrammar("<element xmlns='http://relaxng.org/ns/structure/1.0' name='test'><empty/></element>"));
TS_ASSERT(v.Validate(L"doc", L"<test/>"));
TS_ASSERT(v.Validate("doc", "<test/>"));
{
TestLogger logger;
TS_ASSERT(!v.Validate(L"doc", L"<bogus/>"));
TS_ASSERT(!v.Validate("doc", "<bogus/>"));
TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "Validation error: doc:1: Expecting element test, got bogus");
}
{
TestLogger logger;
TS_ASSERT(!v.Validate(L"doc", L"bogus"));
TS_ASSERT(!v.Validate("doc", "bogus"));
TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "RelaxNGValidator: Failed to parse document");
}
TS_ASSERT(v.Validate(L"doc", L"<test/>"));
TS_ASSERT(v.Validate("doc", "<test/>"));
}
void test_interleave()
@ -68,20 +68,20 @@ public:
RelaxNGValidator v;
TS_ASSERT(v.LoadGrammar("<element xmlns='http://relaxng.org/ns/structure/1.0' datatypeLibrary='http://www.w3.org/2001/XMLSchema-datatypes' name='test'><data type='decimal'><param name='minInclusive'>1.5</param></data></element>"));
TS_ASSERT(v.Validate(L"doc", L"<test>2.0</test>"));
TS_ASSERT(v.Validate("doc", "<test>2.0</test>"));
TestLogger logger;
TS_ASSERT(!v.Validate(L"doc", L"<test>x</test>"));
TS_ASSERT(!v.Validate(L"doc", L"<test>1.0</test>"));
TS_ASSERT(!v.Validate("doc", "<test>x</test>"));
TS_ASSERT(!v.Validate("doc", "<test>1.0</test>"));
RelaxNGValidator w;
TS_ASSERT(w.LoadGrammar("<element xmlns='http://relaxng.org/ns/structure/1.0' datatypeLibrary='http://www.w3.org/2001/XMLSchema-datatypes' name='test'><data type='integer'></data></element>"));
TS_ASSERT(w.Validate(L"doc", L"<test>2</test>"));
TS_ASSERT(w.Validate("doc", "<test>2</test>"));
TS_ASSERT(!w.Validate(L"doc", L"<test>x</test>"));
TS_ASSERT(!w.Validate(L"doc", L"<test>2.0</test>"));
TS_ASSERT(!w.Validate("doc", "<test>x</test>"));
TS_ASSERT(!w.Validate("doc", "<test>2.0</test>"));
}
void test_broken_grammar()
@ -92,6 +92,6 @@ public:
TS_ASSERT(!v.LoadGrammar("whoops"));
TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "RelaxNGValidator: Failed to compile schema");
TS_ASSERT(!v.Validate(L"doc", L"<test/>"));
TS_ASSERT(!v.Validate("doc", "<test/>"));
}
};

View file

@ -97,7 +97,7 @@ std::vector<std::string> Interface::GetTemplates(const std::vector<std::string>&
const CParamNode* node = cmpTemplateManager->GetTemplate(templateName);
if (node != nullptr)
templates.push_back(utf8_from_wstring(node->ToXML()));
templates.push_back(node->ToXMLString());
}
return templates;

View file

@ -138,12 +138,12 @@ public:
virtual void Init(const CParamNode& paramNode)
{
std::wstring anchor = paramNode.GetChild("Anchor").ToString();
if (anchor == L"pitch")
const std::string& anchor = paramNode.GetChild("Anchor").ToString();
if (anchor == "pitch")
m_AnchorType = PITCH;
else if (anchor == L"pitch-roll")
else if (anchor == "pitch-roll")
m_AnchorType = PITCH_ROLL;
else if (anchor == L"roll")
else if (anchor == "roll")
m_AnchorType = ROLL;
else
m_AnchorType = UPRIGHT;

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -89,7 +89,7 @@ void CCmpRallyPointRenderer::Init(const CParamNode& paramNode)
// ---------------------------------------------------------------------------------------------
// Load some XML configuration data (schema guarantees that all these nodes are valid)
m_MarkerTemplate = paramNode.GetChild("MarkerTemplate").ToString();
m_MarkerTemplate = paramNode.GetChild("MarkerTemplate").ToWString();
const CParamNode& lineDashColor = paramNode.GetChild("LineDashColor");
m_LineDashColor = CColor(
lineDashColor.GetChild("@r").ToInt()/255.f,
@ -99,11 +99,11 @@ void CCmpRallyPointRenderer::Init(const CParamNode& paramNode)
);
m_LineThickness = paramNode.GetChild("LineThickness").ToFixed().ToFloat();
m_LineTexturePath = paramNode.GetChild("LineTexture").ToString();
m_LineTextureMaskPath = paramNode.GetChild("LineTextureMask").ToString();
m_LineStartCapType = SOverlayTexturedLine::StrToLineCapType(paramNode.GetChild("LineStartCap").ToString());
m_LineEndCapType = SOverlayTexturedLine::StrToLineCapType(paramNode.GetChild("LineEndCap").ToString());
m_LinePassabilityClass = paramNode.GetChild("LinePassabilityClass").ToUTF8();
m_LineTexturePath = paramNode.GetChild("LineTexture").ToWString();
m_LineTextureMaskPath = paramNode.GetChild("LineTextureMask").ToWString();
m_LineStartCapType = SOverlayTexturedLine::StrToLineCapType(paramNode.GetChild("LineStartCap").ToWString());
m_LineEndCapType = SOverlayTexturedLine::StrToLineCapType(paramNode.GetChild("LineEndCap").ToWString());
m_LinePassabilityClass = paramNode.GetChild("LinePassabilityClass").ToString();
// ---------------------------------------------------------------------------------------------
// Load some textures

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -172,15 +172,15 @@ public:
{
// textured quad mode (dynamic, for units)
m_OverlayDescriptor.m_Type = DYNAMIC_QUAD;
m_OverlayDescriptor.m_QuadTexture = CStrIntern(TEXTUREBASEPATH + textureNode.GetChild("MainTexture").ToUTF8());
m_OverlayDescriptor.m_QuadTextureMask = CStrIntern(TEXTUREBASEPATH + textureNode.GetChild("MainTextureMask").ToUTF8());
m_OverlayDescriptor.m_QuadTexture = CStrIntern(TEXTUREBASEPATH + textureNode.GetChild("MainTexture").ToString());
m_OverlayDescriptor.m_QuadTextureMask = CStrIntern(TEXTUREBASEPATH + textureNode.GetChild("MainTextureMask").ToString());
}
else if (outlineNode.IsOk())
{
// textured outline mode (static, for buildings)
m_OverlayDescriptor.m_Type = STATIC_OUTLINE;
m_OverlayDescriptor.m_LineTexture = CStrIntern(TEXTUREBASEPATH + outlineNode.GetChild("LineTexture").ToUTF8());
m_OverlayDescriptor.m_LineTextureMask = CStrIntern(TEXTUREBASEPATH + outlineNode.GetChild("LineTextureMask").ToUTF8());
m_OverlayDescriptor.m_LineTexture = CStrIntern(TEXTUREBASEPATH + outlineNode.GetChild("LineTexture").ToString());
m_OverlayDescriptor.m_LineTextureMask = CStrIntern(TEXTUREBASEPATH + outlineNode.GetChild("LineTextureMask").ToString());
m_OverlayDescriptor.m_LineThickness = outlineNode.GetChild("LineThickness").ToFloat();
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -157,7 +157,7 @@ const CParamNode* CCmpTemplateManager::GetTemplate(const std::string& templateNa
// Compute validity, if it's not computed before
if (m_TemplateSchemaValidity.find(templateName) == m_TemplateSchemaValidity.end())
{
m_TemplateSchemaValidity[templateName] = m_Validator.Validate(wstring_from_utf8(templateName), fileData.ToXML());
m_TemplateSchemaValidity[templateName] = m_Validator.Validate(templateName, fileData.ToXMLString());
// Show error on the first failure to validate the template
if (!m_TemplateSchemaValidity[templateName])

View file

@ -257,7 +257,7 @@ public:
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
if (cmpPathfinder)
{
m_PassClassName = paramNode.GetChild("PassabilityClass").ToUTF8();
m_PassClassName = paramNode.GetChild("PassabilityClass").ToString();
m_PassClass = cmpPathfinder->GetPassabilityClass(m_PassClassName);
m_Clearance = cmpPathfinder->GetClearance(m_PassClass);

View file

@ -203,7 +203,7 @@ public:
m_IsFoundationActor = paramNode.GetChild("Foundation").IsOk() && paramNode.GetChild("FoundationActor").IsOk();
m_BaseActorName = paramNode.GetChild(m_IsFoundationActor ? "FoundationActor" : "Actor").ToString();
m_BaseActorName = paramNode.GetChild(m_IsFoundationActor ? "FoundationActor" : "Actor").ToWString();
ParseActorName(m_BaseActorName);
m_VisibleInAtlasOnly = paramNode.GetChild("VisibleInAtlasOnly").ToBool();

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -172,12 +172,12 @@ PathfinderPassability::PathfinderPassability(pass_class_t mask, const CParamNode
if (node.GetChild("Obstructions").IsOk())
{
std::wstring obstructions = node.GetChild("Obstructions").ToString();
if (obstructions == L"none")
const std::string& obstructions = node.GetChild("Obstructions").ToString();
if (obstructions == "none")
m_Obstructions = NONE;
else if (obstructions == L"pathfinding")
else if (obstructions == "pathfinding")
m_Obstructions = PATHFINDING;
else if (obstructions == L"foundation")
else if (obstructions == "foundation")
m_Obstructions = FOUNDATION;
else
{

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -22,11 +22,6 @@
#include "ps/CLogger.h"
class CSimContext;
class CParamNode;
class ISerializer;
class IDeserializer;
class CComponentTypeScript
{
NONCOPYABLE(CComponentTypeScript);
@ -72,4 +67,59 @@ private:
JS::PersistentRootedValue m_Instance;
};
#define REGISTER_COMPONENT_SCRIPT_WRAPPER(cname) \
void RegisterComponentType_##cname(CComponentManager& mgr) \
{ \
mgr.RegisterComponentTypeScriptWrapper(CCmp##cname::GetInterfaceId(), CID_##cname, CCmp##cname::Allocate, CCmp##cname::Deallocate, #cname, CCmp##cname::GetSchema()); \
CCmp##cname::ClassInit(mgr); \
}
#define DEFAULT_SCRIPT_WRAPPER(cname) \
static void ClassInit(CComponentManager& UNUSED(componentManager)) { } \
static IComponent* Allocate(const ScriptInterface& scriptInterface, JS::HandleValue instance) \
{ \
return new CCmp##cname(scriptInterface, instance); \
} \
static void Deallocate(IComponent* cmp) \
{ \
delete static_cast<CCmp##cname*> (cmp); \
} \
CCmp##cname(const ScriptInterface& scriptInterface, JS::HandleValue instance) : m_Script(scriptInterface, instance) { } \
static std::string GetSchema() \
{ \
return "<a:component type='script-wrapper'/><empty/>"; \
} \
virtual void Init(const CParamNode& paramNode) \
{ \
m_Script.Init(paramNode, GetEntityId()); \
} \
virtual void Deinit() \
{ \
m_Script.Deinit(); \
} \
virtual void HandleMessage(const CMessage& msg, bool global) \
{ \
m_Script.HandleMessage(msg, global); \
} \
virtual void Serialize(ISerializer& serialize) \
{ \
m_Script.Serialize(serialize); \
} \
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) \
{ \
m_Script.Deserialize(paramNode, deserialize, GetEntityId()); \
} \
virtual JS::Value GetJSInstance() const \
{ \
return m_Script.GetInstance(); \
} \
virtual int GetComponentTypeId() const \
{ \
return CID_##cname; \
} \
private: \
CComponentTypeScript m_Script; \
public:
#endif // INCLUDED_SCRIPTCOMPONENT

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -34,13 +34,6 @@
CCmp##cname::ClassInit(mgr); \
}
#define REGISTER_COMPONENT_SCRIPT_WRAPPER(cname) \
void RegisterComponentType_##cname(CComponentManager& mgr) \
{ \
mgr.RegisterComponentTypeScriptWrapper(CCmp##cname::GetInterfaceId(), CID_##cname, CCmp##cname::Allocate, CCmp##cname::Deallocate, #cname, CCmp##cname::GetSchema()); \
CCmp##cname::ClassInit(mgr); \
}
#define DEFAULT_COMPONENT_ALLOCATOR(cname) \
static IComponent* Allocate(const ScriptInterface&, JS::HandleValue) { return new CCmp##cname(); } \
static void Deallocate(IComponent* cmp) { delete static_cast<CCmp##cname*> (cmp); } \
@ -49,53 +42,6 @@
return CID_##cname; \
}
#define DEFAULT_SCRIPT_WRAPPER(cname) \
static void ClassInit(CComponentManager& UNUSED(componentManager)) { } \
static IComponent* Allocate(const ScriptInterface& scriptInterface, JS::HandleValue instance) \
{ \
return new CCmp##cname(scriptInterface, instance); \
} \
static void Deallocate(IComponent* cmp) \
{ \
delete static_cast<CCmp##cname*> (cmp); \
} \
CCmp##cname(const ScriptInterface& scriptInterface, JS::HandleValue instance) : m_Script(scriptInterface, instance) { } \
static std::string GetSchema() \
{ \
return "<a:component type='script-wrapper'/><empty/>"; \
} \
virtual void Init(const CParamNode& paramNode) \
{ \
m_Script.Init(paramNode, GetEntityId()); \
} \
virtual void Deinit() \
{ \
m_Script.Deinit(); \
} \
virtual void HandleMessage(const CMessage& msg, bool global) \
{ \
m_Script.HandleMessage(msg, global); \
} \
virtual void Serialize(ISerializer& serialize) \
{ \
m_Script.Serialize(serialize); \
} \
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) \
{ \
m_Script.Deserialize(paramNode, deserialize, GetEntityId()); \
} \
virtual JS::Value GetJSInstance() const \
{ \
return m_Script.GetInstance(); \
} \
virtual int GetComponentTypeId() const \
{ \
return CID_##cname; \
} \
private: \
CComponentTypeScript m_Script; \
public:
#define DEFAULT_MOCK_COMPONENT() \
virtual int GetComponentTypeId() const \
{ \

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -29,7 +29,6 @@
#include <sstream>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/join.hpp> // this isn't in string.hpp in old Boosts
static CParamNode g_NullNode(false);
@ -70,7 +69,7 @@ void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
ResetScriptVal();
std::string name = xmb.GetElementString(element.GetNodeName()); // TODO: is GetElementString inefficient?
CStrW value = element.GetText().FromUTF8();
CStr value = element.GetText();
bool hasSetValue = false;
@ -115,11 +114,11 @@ void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
}
else if (attr.Name == at_op)
{
if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"add")
if (attr.Value == "add")
op = ADD;
else if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"mul")
else if (attr.Value == "mul")
op = MUL;
else if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"mul_round")
else if (attr.Value == "mul_round")
op = MUL_ROUND;
else
LOGWARNING("Invalid op '%ls'", attr.Value);
@ -129,30 +128,30 @@ void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
{
XERO_ITER_ATTR(element, attr)
{
if (attr.Name == at_datatype && std::wstring(attr.Value.begin(), attr.Value.end()) == L"tokens")
if (attr.Name == at_datatype && attr.Value == "tokens")
{
CParamNode& node = m_Childs[name];
// Split into tokens
std::vector<std::wstring> oldTokens;
std::vector<std::wstring> newTokens;
std::vector<std::string> oldTokens;
std::vector<std::string> newTokens;
if (!replacing && !node.m_Value.empty()) // ignore the old tokens if replace="" was given
boost::algorithm::split(oldTokens, node.m_Value, boost::algorithm::is_space(), boost::algorithm::token_compress_on);
if (!value.empty())
boost::algorithm::split(newTokens, value, boost::algorithm::is_space(), boost::algorithm::token_compress_on);
// Merge the two lists
std::vector<std::wstring> tokens = oldTokens;
std::vector<std::string> tokens = oldTokens;
for (size_t i = 0; i < newTokens.size(); ++i)
{
if (newTokens[i][0] == L'-')
if (newTokens[i][0] == '-')
{
std::vector<std::wstring>::iterator tokenIt = std::find(tokens.begin(), tokens.end(), newTokens[i].substr(1));
std::vector<std::string>::iterator tokenIt = std::find(tokens.begin(), tokens.end(), newTokens[i].substr(1));
if (tokenIt != tokens.end())
tokens.erase(tokenIt);
else
LOGWARNING("[ParamNode] Could not remove token '%s' from node '%s'%s; not present in list nor inherited (possible typo?)",
utf8_from_wstring(newTokens[i].substr(1)), name, sourceIdentifier ? (" in '" + utf8_from_wstring(sourceIdentifier) + "'").c_str() : "");
newTokens[i].substr(1), name, sourceIdentifier ? (" in '" + utf8_from_wstring(sourceIdentifier) + "'").c_str() : "");
}
else
{
@ -161,7 +160,7 @@ void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
}
}
node.m_Value = boost::algorithm::join(tokens, L" ");
node.m_Value = boost::algorithm::join(tokens, " ");
hasSetValue = true;
break;
}
@ -174,18 +173,18 @@ void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
{
// TODO: Support parsing of data types other than fixed; log warnings in other cases
fixed oldval = node.ToFixed();
fixed mod = fixed::FromString(CStrW(value));
fixed mod = fixed::FromString(value);
switch (op)
{
case ADD:
node.m_Value = (oldval + mod).ToString().FromUTF8();
node.m_Value = (oldval + mod).ToString();
break;
case MUL:
node.m_Value = oldval.Multiply(mod).ToString().FromUTF8();
node.m_Value = oldval.Multiply(mod).ToString();
break;
case MUL_ROUND:
node.m_Value = fixed::FromInt(oldval.Multiply(mod).ToInt_RoundToNearest()).ToString().FromUTF8();
node.m_Value = fixed::FromInt(oldval.Multiply(mod).ToInt_RoundToNearest()).ToString();
break;
default:
break;
@ -226,7 +225,7 @@ void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
continue;
// Add any others
std::string attrName = xmb.GetAttributeString(attr.Name);
node.m_Childs["@" + attrName].m_Value = attr.Value.FromUTF8();
node.m_Childs["@" + attrName].m_Value = attr.Value;
}
}
@ -243,47 +242,39 @@ bool CParamNode::IsOk() const
return m_IsOk;
}
const std::wstring& CParamNode::ToString() const
const std::wstring CParamNode::ToWString() const
{
return wstring_from_utf8(m_Value);
}
const std::string& CParamNode::ToString() const
{
return m_Value;
}
const std::string CParamNode::ToUTF8() const
{
return utf8_from_wstring(m_Value);
}
const CStrIntern CParamNode::ToUTF8Intern() const
{
return CStrIntern(utf8_from_wstring(m_Value));
return CStrIntern(m_Value);
}
int CParamNode::ToInt() const
{
int ret = 0;
std::wstringstream strm;
strm << m_Value;
strm >> ret;
return ret;
return std::strtol(m_Value.c_str(), nullptr, 10);
}
fixed CParamNode::ToFixed() const
{
return fixed::FromString(CStrW(m_Value));
return fixed::FromString(m_Value);
}
float CParamNode::ToFloat() const
{
float ret = 0;
std::wstringstream strm;
strm << m_Value;
strm >> ret;
return ret;
return std::strtof(m_Value.c_str(), nullptr);
}
bool CParamNode::ToBool() const
{
if (m_Value == L"true")
if (m_Value == "true")
return true;
else
return false;
@ -294,40 +285,39 @@ const CParamNode::ChildrenMap& CParamNode::GetChildren() const
return m_Childs;
}
std::wstring CParamNode::EscapeXMLString(const std::wstring& str)
std::string CParamNode::EscapeXMLString(const std::string& str)
{
std::wstring ret;
std::string ret;
ret.reserve(str.size());
// TODO: would be nice to check actual v1.0 XML codepoints,
// but our UTF8 validation routines are lacking.
for (size_t i = 0; i < str.size(); ++i)
{
wchar_t c = str[i];
char c = str[i];
switch (c)
{
case '<': ret += L"&lt;"; break;
case '>': ret += L"&gt;"; break;
case '&': ret += L"&amp;"; break;
case '"': ret += L"&quot;"; break;
case '\t': ret += L"&#9;"; break;
case '\n': ret += L"&#10;"; break;
case '\r': ret += L"&#13;"; break;
case '<': ret += "&lt;"; break;
case '>': ret += "&gt;"; break;
case '&': ret += "&amp;"; break;
case '"': ret += "&quot;"; break;
case '\t': ret += "&#9;"; break;
case '\n': ret += "&#10;"; break;
case '\r': ret += "&#13;"; break;
default:
if ((0x20 <= c && c <= 0xD7FF) || (0xE000 <= c && c <= 0xFFFD))
ret += c;
else
ret += 0xFFFD;
ret += c;
}
}
return ret;
}
std::wstring CParamNode::ToXML() const
std::string CParamNode::ToXMLString() const
{
std::wstringstream strm;
ToXML(strm);
std::stringstream strm;
ToXMLString(strm);
return strm.str();
}
void CParamNode::ToXML(std::wostream& strm) const
void CParamNode::ToXMLString(std::ostream& strm) const
{
strm << m_Value;
@ -338,9 +328,7 @@ void CParamNode::ToXML(std::wostream& strm) const
if (it->first.length() && it->first[0] == '@')
continue;
std::wstring name (it->first.begin(), it->first.end());
strm << L"<" << name;
strm << "<" << it->first;
// Output the child's attributes first
ChildrenMap::const_iterator cit = it->second.m_Childs.begin();
@ -348,16 +336,16 @@ void CParamNode::ToXML(std::wostream& strm) const
{
if (cit->first.length() && cit->first[0] == '@')
{
std::wstring attrname (cit->first.begin()+1, cit->first.end());
strm << L" " << attrname << L"=\"" << EscapeXMLString(cit->second.m_Value) << L"\"";
std::string attrname (cit->first.begin()+1, cit->first.end());
strm << " " << attrname << "=\"" << EscapeXMLString(cit->second.m_Value) << "\"";
}
}
strm << L">";
strm << ">";
it->second.ToXML(strm);
it->second.ToXMLString(strm);
strm << L"</" << name << ">";
strm << "</" << it->first << ">";
}
}
@ -387,8 +375,8 @@ void CParamNode::ConstructJSVal(const ScriptRequest& rq, JS::MutableHandleValue
}
// Just a string
utf16string text(m_Value.begin(), m_Value.end());
JS::RootedString str(rq.cx, JS_AtomizeAndPinUCStringN(rq.cx, reinterpret_cast<const char16_t*>(text.data()), text.length()));
JS::RootedString str(rq.cx, JS_NewStringCopyUTF8Z(rq.cx, JS::ConstUTF8CharsZ(m_Value.data(), m_Value.size())));
str.set(JS_AtomizeAndPinJSString(rq.cx, str));
if (str)
{
ret.setString(str);

View file

@ -196,14 +196,14 @@ public:
bool IsOk() const;
/**
* Returns the content of this node as a string
* Returns the content of this node as a wstring
*/
const std::wstring& ToString() const;
const std::wstring ToWString() const;
/**
* Returns the content of this node as an 8-bit string
* Returns the content of this node as an UTF8 string
*/
const std::string ToUTF8() const;
const std::string& ToString() const;
/**
* Returns the content of this node as an internalized 8-bit string. Should only be used for
@ -234,12 +234,12 @@ public:
/**
* Returns the content of this node and its children as an XML string
*/
std::wstring ToXML() const;
std::string ToXMLString() const;
/**
* Write the content of this node and its children as an XML string, to the stream
*/
void ToXML(std::wostream& strm) const;
void ToXMLString(std::ostream& strm) const;
/**
* Returns a JS::Value representation of this node and its children.
@ -259,9 +259,12 @@ public:
/**
* Escapes a string so that it is well-formed XML content/attribute text.
* (Replaces "&" with "&amp;" etc, and replaces invalid characters with U+FFFD.)
* (Replaces "&" with "&amp;" etc)
*/
static std::wstring EscapeXMLString(const std::wstring& str);
static std::string EscapeXMLString(const std::string& str);
std::string m_Name;
u32 m_Index;
private:
@ -279,7 +282,7 @@ private:
void ConstructJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret) const;
std::wstring m_Value;
std::string m_Value;
ChildrenMap m_Childs;
bool m_IsOk;

View file

@ -66,21 +66,21 @@ public:
const CParamNode* basic = tempMan->LoadTemplate(ent2, "basic");
TS_ASSERT(basic != NULL);
TS_ASSERT_WSTR_EQUALS(basic->ToXML(), L"<Test1A>12345</Test1A>");
TS_ASSERT_STR_EQUALS(basic->ToXMLString(), "<Test1A>12345</Test1A>");
const CParamNode* inherit2 = tempMan->LoadTemplate(ent2, "inherit2");
TS_ASSERT(inherit2 != NULL);
TS_ASSERT_WSTR_EQUALS(inherit2->ToXML(), L"<Test1A a=\"a2\" b=\"b1\" c=\"c1\"><d>d2</d><e>e1</e><f>f1</f><g>g2</g></Test1A>");
TS_ASSERT_STR_EQUALS(inherit2->ToXMLString(), "<Test1A a=\"a2\" b=\"b1\" c=\"c1\"><d>d2</d><e>e1</e><f>f1</f><g>g2</g></Test1A>");
const CParamNode* inherit1 = tempMan->LoadTemplate(ent2, "inherit1");
TS_ASSERT(inherit1 != NULL);
TS_ASSERT_WSTR_EQUALS(inherit1->ToXML(), L"<Test1A a=\"a1\" b=\"b1\" c=\"c1\"><d>d1</d><e>e1</e><f>f1</f></Test1A>");
TS_ASSERT_STR_EQUALS(inherit1->ToXMLString(), "<Test1A a=\"a1\" b=\"b1\" c=\"c1\"><d>d1</d><e>e1</e><f>f1</f></Test1A>");
const CParamNode* actor = tempMan->LoadTemplate(ent2, "actor|example1");
TS_ASSERT(actor != NULL);
TS_ASSERT_WSTR_EQUALS(actor->ToXML(),
L"<Footprint><Circle radius=\"2.0\"></Circle><Height>1.0</Height></Footprint><Selectable><EditorOnly></EditorOnly><Overlay><Texture><MainTexture>128x128/ellipse.png</MainTexture><MainTextureMask>128x128/ellipse_mask.png</MainTextureMask></Texture></Overlay></Selectable>"
L"<VisualActor><Actor>example1</Actor><ActorOnly></ActorOnly><SilhouetteDisplay>false</SilhouetteDisplay><SilhouetteOccluder>false</SilhouetteOccluder><VisibleInAtlasOnly>false</VisibleInAtlasOnly></VisualActor>");
TS_ASSERT_STR_EQUALS(actor->ToXMLString(),
"<Footprint><Circle radius=\"2.0\"></Circle><Height>1.0</Height></Footprint><Selectable><EditorOnly></EditorOnly><Overlay><Texture><MainTexture>128x128/ellipse.png</MainTexture><MainTextureMask>128x128/ellipse_mask.png</MainTextureMask></Texture></Overlay></Selectable>"
"<VisualActor><Actor>example1</Actor><ActorOnly></ActorOnly><SilhouetteDisplay>false</SilhouetteDisplay><SilhouetteOccluder>false</SilhouetteOccluder><VisibleInAtlasOnly>false</VisibleInAtlasOnly></VisualActor>");
}
void test_LoadTemplate_scriptcache()

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -41,12 +41,12 @@ public:
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <Foo> 1 </Foo><Bar>2<Baz>3</Baz>4</Bar><Qux/></test>"), PSRETURN_OK);
TS_ASSERT(node.GetChild("test").IsOk());
TS_ASSERT(!node.GetChild("Test").IsOk());
TS_ASSERT_WSTR_EQUALS(node.GetChild("test").ToString(), L"");
TS_ASSERT_STR_EQUALS(node.GetChild("test").ToString(), "");
TS_ASSERT(node.GetChild("test").GetChild("Foo").IsOk());
TS_ASSERT_EQUALS(node.GetChild("test").GetChild("Foo").ToInt(), 1);
TS_ASSERT_WSTR_EQUALS(node.GetChild("test").GetChild("Foo").ToString(), L"1");
TS_ASSERT_STR_EQUALS(node.GetChild("test").GetChild("Foo").ToString(), "1");
TS_ASSERT_EQUALS(node.GetChild("test").GetChild("Bar").ToInt(), 24);
TS_ASSERT_WSTR_EQUALS(node.GetChild("test").GetChild("Bar").ToString(), L"24");
TS_ASSERT_STR_EQUALS(node.GetChild("test").GetChild("Bar").ToString(), "24");
TS_ASSERT_EQUALS(node.GetChild("test").GetChild("Bar").GetChild("Baz").ToInt(), 3);
TS_ASSERT(node.GetChild("test").GetChild("Qux").IsOk());
TS_ASSERT(!node.GetChild("test").GetChild("Qux").GetChild("Baz").IsOk());
@ -58,7 +58,7 @@ public:
TS_ASSERT(!nullTwo.IsOk());
TS_ASSERT(!nullThree.IsOk());
TS_ASSERT_WSTR_EQUALS(nullOne.ToString(), L"");
TS_ASSERT_STR_EQUALS(nullOne.ToString(), "");
TS_ASSERT(nullOne.ToInt() == 0);
TS_ASSERT(nullOne.ToFixed().ToDouble() == 0);
}
@ -79,11 +79,11 @@ public:
TS_ASSERT_EQUALS(node.GetChild("test").GetChild("w").GetChild("@a").ToInt(), 4);
}
void test_ToXML()
void test_ToXMLString()
{
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test x='1' y='2'> <z>3</z> <w a='4'/></test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test x=\"1\" y=\"2\"><w a=\"4\"></w><z>3</z></test>");
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test x=\"1\" y=\"2\"><w a=\"4\"></w><z>3</z></test>");
}
void test_overlay_basic()
@ -91,7 +91,7 @@ public:
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test x='1' y='2'> <a>3</a> <b>4</b> </test>"), PSRETURN_OK);
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test y='5' z='6'> <b>7</b> <c>8</c> </test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test x=\"1\" y=\"5\" z=\"6\"><a>3</a><b>7</b><c>8</c></test>");
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test x=\"1\" y=\"5\" z=\"6\"><a>3</a><b>7</b><c>8</c></test>");
}
void test_overlay_disable()
@ -99,7 +99,7 @@ public:
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a>1</a> <b>2</b> </test>"), PSRETURN_OK);
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a disable=''/> <c disable=''/> </test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><b>2</b></test>");
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test><b>2</b></test>");
}
void test_overlay_replace()
@ -107,7 +107,7 @@ public:
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a x='1'>2<b/></a> <c y='3'/></test>"), PSRETURN_OK);
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a replace=''><d/></a> <e replace=''/> </test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a><d></d></a><c y=\"3\"></c><e></e></test>");
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test><a><d></d></a><c y=\"3\"></c><e></e></test>");
}
void test_overlay_tokens()
@ -115,24 +115,24 @@ public:
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a datatype='tokens'>x y</a><b datatype='tokens'>a b\nc\td</b><c datatype='tokens'>m n</c></test>"), PSRETURN_OK);
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a datatype='tokens'>-y z w</a><c datatype='tokens' replace=''>n o</c></test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a datatype=\"tokens\">x z w</a><b datatype=\"tokens\">a b c d</b><c datatype=\"tokens\">n o</c></test>");
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test><a datatype=\"tokens\">x z w</a><b datatype=\"tokens\">a b c d</b><c datatype=\"tokens\">n o</c></test>");
}
void test_overlay_remove_nonexistent_token()
{
// regression test; this used to cause a crash because of a failure to check whether the token being removed was present
TestLogger nolog;
TestLogger logger;
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a datatype='tokens'>-nonexistenttoken X</a></test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a datatype=\"tokens\">X</a></test>");
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test><a datatype=\"tokens\">X</a></test>");
}
void test_overlay_remove_empty_token()
{
TestLogger nolog;
TestLogger logger;
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a datatype='tokens'> Y - X </a></test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a datatype=\"tokens\">Y X</a></test>");
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test><a datatype=\"tokens\">Y X</a></test>");
}
void test_overlay_filtered()
@ -140,12 +140,12 @@ public:
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a><b/></a> <c>toberemoved</c> <d><e/></d> </test>"), PSRETURN_OK);
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test filtered=\"\"> <a/> <d><f/></d> <g/> </test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a><b></b></a><d><e></e><f></f></d><g></g></test>");
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test><a><b></b></a><d><e></e><f></f></d><g></g></test>");
CParamNode node2;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node2, "<test> <a><b>b</b><c>c</c><d>d</d><e>e</e></a> <f/> </test>"), PSRETURN_OK);
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node2, "<test filtered=\"\"> <a filtered=\"\"><b merge=\"\"/><c>c2</c><d/></a> </test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node2.ToXML(), L"<test><a><b>b</b><c>c2</c><d></d></a></test>");
TS_ASSERT_STR_EQUALS(node2.ToXMLString(), "<test><a><b>b</b><c>c2</c><d></d></a></test>");
}
void test_overlay_merge()
@ -153,7 +153,16 @@ public:
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a><b>foo</b><c>bar</c></a> <x><y><z>foo</z></y></x> </test>"), PSRETURN_OK);
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a merge=\"\"><b>test</b><d>baz</d></a> <i merge=\"\"><j>willnotbeincluded</j></i> <x merge=\"\"><y merge=\"\"><v>text</v></y><w>more text</w></x> </test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a><b>test</b><c>bar</c><d>baz</d></a><x><w>more text</w><y><v>text</v><z>foo</z></y></x></test>");
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test><a><b>test</b><c>bar</c><d>baz</d></a><x><w>more text</w><y><v>text</v><z>foo</z></y></x></test>");
}
void test_overlay_merge_empty()
{
// 'merge' nodes don't change the original value.
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test><a>foo</a><c>bar</c></test>"), PSRETURN_OK);
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test><a merge=\"\"/><b merge=\"\">skipped</b><c merge=\"\">replaced</c></test>"), PSRETURN_OK);
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test><a>foo</a><c>bar</c></test>");
}
void test_overlay_filtered_merge()
@ -161,7 +170,15 @@ public:
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a><b/></a> <c><x/></c> <Health><Max>1200</Max></Health> </test>"), PSRETURN_OK);
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test filtered=\"\"> <c merge=\"\"/> <d>bar</d> <e merge=\"\"/> <Health><Initial>1</Initial></Health> </test>"), PSRETURN_OK);
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><Health><Initial>1</Initial><Max>1200</Max></Health><c><x></x></c><d>bar</d></test>");
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test><Health><Initial>1</Initial><Max>1200</Max></Health><c><x></x></c><d>bar</d></test>");
}
void test_overlay_ops()
{
CParamNode node;
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test><a>5</a><b>5</b><c>5</c></test>"), PSRETURN_OK);
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test><a op='add'>5</a><b op='mul'>3</b><c op='mul_round'>0.55</c></test>"), PSRETURN_OK);
TS_ASSERT_STR_EQUALS(node.ToXMLString(), "<test><a>10</a><b>15</b><c>3</c></test>");
}
void test_types()
@ -170,7 +187,7 @@ public:
TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test><n>+010.75</n><t>true</t></test>"), PSRETURN_OK);
TS_ASSERT(node.GetChild("test").IsOk());
TS_ASSERT(node.GetChild("test").GetChild("n").IsOk());
TS_ASSERT_EQUALS(node.GetChild("test").GetChild("n").ToString(), L"+010.75");
TS_ASSERT_EQUALS(node.GetChild("test").GetChild("n").ToString(), "+010.75");
TS_ASSERT_EQUALS(node.GetChild("test").GetChild("n").ToInt(), 10);
TS_ASSERT_EQUALS(node.GetChild("test").GetChild("n").ToFixed().ToDouble(), 10.75);
TS_ASSERT_EQUALS(node.GetChild("test").GetChild("n").ToBool(), false);
@ -179,14 +196,9 @@ public:
void test_escape()
{
TS_ASSERT_WSTR_EQUALS(CParamNode::EscapeXMLString(L"test"), L"test");
TS_ASSERT_WSTR_EQUALS(CParamNode::EscapeXMLString(L"x < y << z"), L"x &lt; y &lt;&lt; z");
TS_ASSERT_WSTR_EQUALS(CParamNode::EscapeXMLString(L"x < y \"&' y > z ]]> "), L"x &lt; y &quot;&amp;' y &gt; z ]]&gt; ");
TS_ASSERT_WSTR_EQUALS(CParamNode::EscapeXMLString(L" \r\n\t "), L" &#13;&#10;&#9; ");
wchar_t r = 0xFFFD;
wchar_t a[] = { 1, 2, 3, 4, 5, 6, 7, 8, /* 9, 10, */ 11, 12, /* 13, */ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0xD7FF, 0xD800, 0xDFFF, 0xE000, 0xFFFE, 0xFFFF, 0 };
wchar_t b[] = { r, r, r, r, r, r, r, r, /*&#9;&#10;*/ r, r, /*&#13;*/ r, r, r, r, r, r, r, r, r, r, r, r, r, r, r, r, r, r, 32, 0xD7FF, r, r, 0xE000, r, r, 0 };
TS_ASSERT_WSTR_EQUALS(CParamNode::EscapeXMLString(a), b);
TS_ASSERT_STR_EQUALS(CParamNode::EscapeXMLString("test"), "test");
TS_ASSERT_STR_EQUALS(CParamNode::EscapeXMLString("x < y << z"), "x &lt; y &lt;&lt; z");
TS_ASSERT_STR_EQUALS(CParamNode::EscapeXMLString("x < y \"&' y > z ]]> "), "x &lt; y &quot;&amp;' y &gt; z ]]&gt; ");
TS_ASSERT_STR_EQUALS(CParamNode::EscapeXMLString(" \r\n\t "), " &#13;&#10;&#9; ");
}
};