summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/llfile.cpp18
-rw-r--r--indra/llcommon/llfile.h2
-rw-r--r--indra/llcommon/llsd.cpp201
-rw-r--r--indra/llcommon/llsd.h20
-rw-r--r--indra/llcommon/llstring.cpp69
-rw-r--r--indra/llcommon/llstring.h14
6 files changed, 317 insertions, 7 deletions
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index ddf239f306..9045324bf2 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -248,6 +248,24 @@ int LLFile::close(LLFILE * file)
return ret_value;
}
+std::string LLFile::getContents(const std::string& filename)
+{
+ LLFILE* fp = fopen(filename, "rb"); /* Flawfinder: ignore */
+ if (fp)
+ {
+ fseek(fp, 0, SEEK_END);
+ U32 length = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ std::vector<char> buffer(length);
+ size_t nread = fread(buffer.data(), 1, length, fp);
+ fclose(fp);
+
+ return std::string(buffer.data(), nread);
+ }
+
+ return LLStringUtil::null;
+}
int LLFile::remove(const std::string& filename, int supress_error)
{
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 2564671b13..74110343fc 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -67,6 +67,8 @@ public:
static int close(LLFILE * file);
+ static std::string getContents(const std::string& filename);
+
// perms is a permissions mask like 0777 or 0700. In most cases it will
// be overridden by the user's umask. It is ignored on Windows.
// mkdir() considers "directory already exists" to be SUCCESS.
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 663ceac22b..b36ff7d263 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -30,6 +30,7 @@
#include "linden_common.h"
#include "llsd.h"
+#include "llbase64.h"
#include "llerror.h"
#include "../llmath/llmath.h"
#include "llformat.h"
@@ -142,6 +143,8 @@ public:
virtual const String& asStringRef() const { static const std::string empty; return empty; }
+ virtual String asXMLRPCValue() const { return "<nil/>"; }
+
virtual bool has(const String&) const { return false; }
virtual LLSD get(const String&) const { return LLSD(); }
virtual LLSD getKeys() const { return LLSD::emptyArray(); }
@@ -222,6 +225,8 @@ namespace
virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; }
virtual LLSD::Real asReal() const { return mValue ? 1 : 0; }
virtual LLSD::String asString() const;
+
+ virtual LLSD::String asXMLRPCValue() const { return mValue ? "<boolean>1</boolean>" : "<boolean>0</boolean>"; }
};
LLSD::String ImplBoolean::asString() const
@@ -243,6 +248,8 @@ namespace
virtual LLSD::Integer asInteger() const { return mValue; }
virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const;
+
+ virtual LLSD::String asXMLRPCValue() const { return "<int>" + std::to_string(mValue) + "</int>"; }
};
LLSD::String ImplInteger::asString() const
@@ -259,6 +266,8 @@ namespace
virtual LLSD::Integer asInteger() const;
virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const;
+
+ virtual LLSD::String asXMLRPCValue() const { return "<double>" + std::to_string(mValue) + "</double>"; }
};
LLSD::Boolean ImplReal::asBoolean() const
@@ -286,9 +295,11 @@ namespace
virtual LLSD::URI asURI() const { return LLURI(mValue); }
virtual size_t size() const { return mValue.size(); }
virtual const LLSD::String& asStringRef() const { return mValue; }
+
+ virtual LLSD::String asXMLRPCValue() const { return "<string>" + LLStringFn::xml_encode(mValue) + "</string>"; }
};
- LLSD::Integer ImplString::asInteger() const
+ LLSD::Integer ImplString::asInteger() const
{
// This must treat "1.23" not as an error, but as a number, which is
// then truncated down to an integer. Hence, this code doesn't call
@@ -298,7 +309,7 @@ namespace
return (int)asReal();
}
- LLSD::Real ImplString::asReal() const
+ LLSD::Real ImplString::asReal() const
{
F64 v = 0.0;
std::istringstream i_stream(mValue);
@@ -323,6 +334,8 @@ namespace
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::UUID asUUID() const { return mValue; }
+
+ virtual LLSD::String asXMLRPCValue() const { return "<string>" + mValue.asString() + "</string>"; }
};
@@ -344,6 +357,8 @@ namespace
}
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::Date asDate() const { return mValue; }
+
+ virtual LLSD::String asXMLRPCValue() const { return "<dateTime.iso8601>" + mValue.toHTTPDateString("%FT%T") + "</dateTime.iso8601>"; }
};
@@ -355,6 +370,8 @@ namespace
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::URI asURI() const { return mValue; }
+
+ virtual LLSD::String asXMLRPCValue() const { return "<string>" + LLStringFn::xml_encode(mValue.asString()) + "</string>"; }
};
@@ -365,13 +382,15 @@ namespace
ImplBinary(const LLSD::Binary& v) : Base(v) { }
virtual const LLSD::Binary& asBinary() const{ return mValue; }
+
+ virtual LLSD::String asXMLRPCValue() const { return "<base64>" + LLBase64::encode(mValue.data(), mValue.size()) + "</base64>"; }
};
class ImplMap : public LLSD::Impl
{
private:
- typedef std::map<LLSD::String, LLSD> DataMap;
+ typedef std::map<LLSD::String, LLSD> DataMap;
DataMap mData;
@@ -387,6 +406,19 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
+ virtual LLSD::String asXMLRPCValue() const
+ {
+ std::ostringstream os;
+ os << "<struct>";
+ for (const auto& it : mData)
+ {
+ os << "<member><name>" << LLStringFn::xml_encode(it.first) << "</name>"
+ << it.second.asXMLRPCValue() << "</member>";
+ }
+ os << "</struct>";
+ return os.str();
+ }
+
virtual bool has(const LLSD::String&) const;
using LLSD::Impl::get; // Unhiding get(size_t)
@@ -511,7 +543,7 @@ namespace
class ImplArray : public LLSD::Impl
{
private:
- typedef std::vector<LLSD> DataVector;
+ typedef std::vector<LLSD> DataVector;
DataVector mData;
@@ -527,6 +559,18 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
+ virtual LLSD::String asXMLRPCValue() const
+ {
+ std::ostringstream os;
+ os << "<array><data>";
+ for (const auto& it : mData)
+ {
+ os << it.asXMLRPCValue();
+ }
+ os << "</data></array>";
+ return os.str();
+ }
+
using LLSD::Impl::get; // Unhiding get(LLSD::String)
using LLSD::Impl::erase; // Unhiding erase(LLSD::String)
using LLSD::Impl::ref; // Unhiding ref(LLSD::String)
@@ -872,6 +916,155 @@ const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); }
const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); }
+LLSD::String LLSD::asXMLRPCValue() const { return "<value>" + safe(impl).asXMLRPCValue() + "</value>"; }
+
+static bool inline check(bool condition, const char* warning_message)
+{
+ if (!condition)
+ {
+ LL_WARNS() << warning_message << LL_ENDL;
+ }
+
+ return condition;
+}
+
+static bool parseXMLRPCArrayValue(LLSD& target, LLSD::TreeNode* node)
+{
+ LLSD::TreeNode* data = node->getFirstChild();
+ if (!check(data, "No array inner XML element (<data> expected)") ||
+ !check(data->hasName("data"), "Invalid array inner XML element (<data> expected)") ||
+ !check(!data->getNextSibling(), "Multiple array inner XML elements (single <data> expected)"))
+ return false;
+
+ for (LLSD::TreeNode* item = data->getFirstChild(); item; item = item->getNextSibling())
+ {
+ LLSD value;
+ if (!value.fromXMLRPCValue(item))
+ return false;
+
+ target.append(value);
+ }
+
+ return true;
+}
+
+static bool parseXMLRPCStructValue(LLSD& target, LLSD::TreeNode* node)
+{
+ for (LLSD::TreeNode* item = node->getFirstChild(); item; item = item->getNextSibling())
+ {
+ if (!check(item->hasName("member"), "Invalid struct inner XML element (<member> expected)"))
+ return false;
+
+ std::string name;
+ LLSD value;
+ for (LLSD::TreeNode* subitem = item->getFirstChild(); subitem; subitem = subitem->getNextSibling())
+ {
+ if (subitem->hasName("name"))
+ {
+ name = LLStringFn::xml_decode(subitem->getTextContents());
+ }
+ else if (!value.fromXMLRPCValue(subitem))
+ {
+ return false;
+ }
+ }
+ if (!check(!name.empty(), "Empty struct member name"))
+ return false;
+
+ target.insert(name, value);
+ }
+
+ return true;
+}
+
+bool LLSD::fromXMLRPCValue(TreeNode* node)
+{
+ clear();
+
+ llassert(node);
+ if (!node)
+ return false;
+
+ if (!check(node->hasName("value"), "Invalid XML element (<value> expected)"))
+ return false;
+
+ TreeNode* inner = node->getFirstChild();
+ if (!inner)
+ {
+ check(false, "No inner XML element (value type expected)");
+ // Value with no type qualifier is treated as string
+ assign(LLStringFn::xml_decode(node->getTextContents()));
+ return true;
+ }
+
+ if (!check(!inner->getNextSibling(), "Multiple inner XML elements (single expected)"))
+ return false;
+
+ if (inner->hasName("string"))
+ {
+ assign(LLStringFn::xml_decode(inner->getTextContents()));
+ return true;
+ }
+
+ if (inner->hasName("int") || inner->hasName("i4"))
+ {
+ assign(std::stoi(inner->getTextContents()));
+ return true;
+ }
+
+ if (inner->hasName("double"))
+ {
+ assign(std::stod(inner->getTextContents()));
+ return true;
+ }
+
+ if (inner->hasName("boolean"))
+ {
+ assign(!!std::stoi(inner->getTextContents()));
+ return true;
+ }
+
+ if (inner->hasName("dateTime.iso8601"))
+ {
+ assign(Date(inner->getTextContents()));
+ return true;
+ }
+
+ if (inner->hasName("base64"))
+ {
+ std::string decoded = LLBase64::decodeAsString(inner->getTextContents());
+ Binary binary(decoded.size());
+ memcpy(binary.data(), decoded.data(), decoded.size());
+ assign(binary);
+ return true;
+ }
+
+ if (inner->hasName("array"))
+ {
+ if (!parseXMLRPCArrayValue(*this, inner))
+ {
+ clear();
+ return false;
+ }
+ return true;
+ }
+
+ if (inner->hasName("struct"))
+ {
+ if (!parseXMLRPCStructValue(*this, inner))
+ {
+ clear();
+ return false;
+ }
+ return true;
+ }
+
+ check(false, "Unknown inner XML element (known value type expected)");
+ // Value with unknown type qualifier is treated as string
+ assign(LLStringFn::xml_decode(inner->getTextContents()));
+ return true;
+}
+
// const char * helpers
LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
void LLSD::assign(const char* v)
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index a5e735b561..5532decfc3 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -259,10 +259,24 @@ public:
UUID asUUID() const;
Date asDate() const;
URI asURI() const;
- const Binary& asBinary() const;
+ const Binary& asBinary() const;
// asStringRef on any non-string type will return a ref to an empty string.
- const String& asStringRef() const;
+ const String& asStringRef() const;
+
+ // Return "<value><((type))>((scalar value or recursive calls))</((type))></value>"
+ // See http://xmlrpc.com/spec.md
+ String asXMLRPCValue() const;
+
+ struct TreeNode
+ {
+ virtual bool hasName(const String& name) const = 0;
+ virtual String getTextContents() const = 0;
+ virtual TreeNode* getFirstChild() const = 0;
+ virtual TreeNode* getNextSibling() const = 0;
+ };
+
+ bool fromXMLRPCValue(TreeNode* node);
operator Boolean() const { return asBoolean(); }
operator Integer() const { return asInteger(); }
@@ -275,7 +289,7 @@ public:
// This is needed because most platforms do not automatically
// convert the boolean negation as a bool in an if statement.
- bool operator!() const {return !asBoolean();}
+ bool operator!() const { return !asBoolean(); }
//@}
/** @name Character Pointer Helpers
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 514d73b24b..6f3d193d6b 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -1208,6 +1208,75 @@ namespace LLStringFn
return output;
}
+ using literals_t = std::map<char, std::string>;
+ static const literals_t xml_elem_literals =
+ {
+ { '<', "&lt;" },
+ { '>', "&gt;" },
+ { '&', "&amp;" }
+ };
+ static const literals_t xml_attr_literals =
+ {
+ { '"', "&quot;" },
+ { '\'', "&apos;" }
+ };
+
+ static void literals_encode(std::string& text, const literals_t& literals)
+ {
+ for (const std::pair<char, std::string> it : literals)
+ {
+ std::string::size_type pos = 0;
+ while ((pos = text.find(it.first, pos)) != std::string::npos)
+ {
+ text.replace(pos, 1, it.second);
+ pos += it.second.size();
+ }
+ }
+ }
+
+ static void literals_decode(std::string& text, const literals_t& literals)
+ {
+ for (const std::pair<char, std::string> it : literals)
+ {
+ std::string::size_type pos = 0;
+ while ((pos = text.find(it.second, pos)) != std::string::npos)
+ {
+ text[pos++] = it.first;
+ text.erase(pos, it.second.size() - 1);
+ }
+ }
+ }
+
+ /**
+ * @brief Replace all characters that are not allowed in XML 1.0
+ * with corresponding literals: [ < > & ] => [ &lt; &gt; &amp; ]
+ */
+ std::string xml_encode(const std::string& input, bool for_attribute)
+ {
+ std::string result(input);
+ literals_encode(result, xml_elem_literals);
+ if (for_attribute)
+ {
+ literals_encode(result, xml_attr_literals);
+ }
+ return result;
+ }
+
+ /**
+ * @brief Replace some of XML literals that are defined in XML 1.0
+ * with corresponding characters: [ &lt; &gt; &amp; ] => [ < > & ]
+ */
+ std::string xml_decode(const std::string& input, bool for_attribute)
+ {
+ std::string result(input);
+ literals_decode(result, xml_elem_literals);
+ if (for_attribute)
+ {
+ literals_decode(result, xml_attr_literals);
+ }
+ return result;
+ }
+
/**
* @brief Replace all control characters (c < 0x20) with replacement in
* string.
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 123f4184b5..b69a068830 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -890,6 +890,20 @@ namespace LLStringFn
/**
+ * @brief Replace all characters that are not allowed in XML 1.0
+ * with corresponding literals: [ < > & ] => [ &lt; &gt; &amp; ]
+ */
+ LL_COMMON_API std::string xml_encode(const std::string& input, bool for_attribute = false);
+
+
+ /**
+ * @brief Replace some of XML literals that are defined in XML 1.0
+ * with corresponding characters: [ &lt; &gt; &amp; ] => [ < > & ]
+ */
+ LL_COMMON_API std::string xml_decode(const std::string& input, bool for_attribute = false);
+
+
+ /**
* @brief Replace all control characters (0 <= c < 0x20) with replacement in
* string. This is safe for utf-8
*