Files
SingularityViewer/indra/llcommon/llsdutil.cpp
2010-04-02 02:48:44 -03:00

307 lines
7.2 KiB
C++

/**
* @file llsdutil.cpp
* @author Phoenix
* @date 2006-05-24
* @brief Implementation of classes, functions, etc, for using structured data.
*
* $LicenseInfo:firstyear=2006&license=viewergpl$
*
* Copyright (c) 2006-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llsdutil.h"
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h> // for htonl
#elif LL_LINUX || LL_SOLARIS
# include <netinet/in.h>
#elif LL_DARWIN
# include <arpa/inet.h>
#endif
#include "llsdserialize.h"
// U32
LLSD ll_sd_from_U32(const U32 val)
{
std::vector<U8> v;
U32 net_order = htonl(val);
v.resize(4);
memcpy(&(v[0]), &net_order, 4); /* Flawfinder: ignore */
return LLSD(v);
}
U32 ll_U32_from_sd(const LLSD& sd)
{
U32 ret;
std::vector<U8> v = sd.asBinary();
if (v.size() < 4)
{
return 0;
}
memcpy(&ret, &(v[0]), 4); /* Flawfinder: ignore */
ret = ntohl(ret);
return ret;
}
//U64
LLSD ll_sd_from_U64(const U64 val)
{
std::vector<U8> v;
U32 high, low;
high = (U32)(val >> 32);
low = (U32)val;
high = htonl(high);
low = htonl(low);
v.resize(8);
memcpy(&(v[0]), &high, 4); /* Flawfinder: ignore */
memcpy(&(v[4]), &low, 4); /* Flawfinder: ignore */
return LLSD(v);
}
U64 ll_U64_from_sd(const LLSD& sd)
{
U32 high, low;
std::vector<U8> v = sd.asBinary();
if (v.size() < 8)
{
return 0;
}
memcpy(&high, &(v[0]), 4); /* Flawfinder: ignore */
memcpy(&low, &(v[4]), 4); /* Flawfinder: ignore */
high = ntohl(high);
low = ntohl(low);
return ((U64)high) << 32 | low;
}
// IP Address (stored in net order in a U32, so don't need swizzling)
LLSD ll_sd_from_ipaddr(const U32 val)
{
std::vector<U8> v;
v.resize(4);
memcpy(&(v[0]), &val, 4); /* Flawfinder: ignore */
return LLSD(v);
}
U32 ll_ipaddr_from_sd(const LLSD& sd)
{
U32 ret;
std::vector<U8> v = sd.asBinary();
if (v.size() < 4)
{
return 0;
}
memcpy(&ret, &(v[0]), 4); /* Flawfinder: ignore */
return ret;
}
// Converts an LLSD binary to an LLSD string
LLSD ll_string_from_binary(const LLSD& sd)
{
std::vector<U8> value = sd.asBinary();
std::string str;
str.resize(value.size());
memcpy(&str[0], &value[0], value.size());
return str;
}
// Converts an LLSD string to an LLSD binary
LLSD ll_binary_from_string(const LLSD& sd)
{
std::vector<U8> binary_value;
std::string string_value = sd.asString();
for (std::string::iterator iter = string_value.begin();
iter != string_value.end(); ++iter)
{
binary_value.push_back(*iter);
}
binary_value.push_back('\0');
return binary_value;
}
char* ll_print_sd(const LLSD& sd)
{
const U32 bufferSize = 10 * 1024;
static char buffer[bufferSize];
std::ostringstream stream;
//stream.rdbuf()->pubsetbuf(buffer, bufferSize);
stream << LLSDOStreamer<LLSDXMLFormatter>(sd);
stream << std::ends;
strncpy(buffer, stream.str().c_str(), bufferSize);
buffer[bufferSize - 1] = '\0';
return buffer;
}
char* ll_pretty_print_sd(const LLSD& sd)
{
const U32 bufferSize = 10 * 1024;
static char buffer[bufferSize];
std::ostringstream stream;
//stream.rdbuf()->pubsetbuf(buffer, bufferSize);
stream << LLSDOStreamer<LLSDXMLFormatter>(sd, LLSDFormatter::OPTIONS_PRETTY);
stream << std::ends;
strncpy(buffer, stream.str().c_str(), bufferSize);
buffer[bufferSize - 1] = '\0';
return buffer;
}
//compares the structure of an LLSD to a template LLSD and stores the
//"valid" values in a 3rd LLSD. Default values pulled from the template
//if the tested LLSD does not contain the key/value pair.
//Excess values in the test LLSD are ignored in the resultant_llsd.
//If the llsd to test has a specific key to a map and the values
//are not of the same type, false is returned or if the LLSDs are not
//of the same value. Ordering of arrays matters
//Otherwise, returns true
BOOL compare_llsd_with_template(
const LLSD& llsd_to_test,
const LLSD& template_llsd,
LLSD& resultant_llsd)
{
if (
llsd_to_test.isUndefined() &&
template_llsd.isDefined() )
{
resultant_llsd = template_llsd;
return TRUE;
}
else if ( llsd_to_test.type() != template_llsd.type() )
{
resultant_llsd = LLSD();
return FALSE;
}
if ( llsd_to_test.isArray() )
{
//they are both arrays
//we loop over all the items in the template
//verifying that the to_test has a subset (in the same order)
//any shortcoming in the testing_llsd are just taken
//to be the rest of the template
LLSD data;
LLSD::array_const_iterator test_iter;
LLSD::array_const_iterator template_iter;
resultant_llsd = LLSD::emptyArray();
test_iter = llsd_to_test.beginArray();
for (
template_iter = template_llsd.beginArray();
(template_iter != template_llsd.endArray() &&
test_iter != llsd_to_test.endArray());
++template_iter)
{
if ( !compare_llsd_with_template(
*test_iter,
*template_iter,
data) )
{
resultant_llsd = LLSD();
return FALSE;
}
else
{
resultant_llsd.append(data);
}
++test_iter;
}
//so either the test or the template ended
//we do another loop now to the end of the template
//grabbing the default values
for (;
template_iter != template_llsd.endArray();
++template_iter)
{
resultant_llsd.append(*template_iter);
}
}
else if ( llsd_to_test.isMap() )
{
//now we loop over the keys of the two maps
//any excess is taken from the template
//excess is ignored in the test
LLSD value;
LLSD::map_const_iterator template_iter;
resultant_llsd = LLSD::emptyMap();
for (
template_iter = template_llsd.beginMap();
template_iter != template_llsd.endMap();
++template_iter)
{
if ( llsd_to_test.has(template_iter->first) )
{
//the test LLSD has the same key
if ( !compare_llsd_with_template(
llsd_to_test[template_iter->first],
template_iter->second,
value) )
{
resultant_llsd = LLSD();
return FALSE;
}
else
{
resultant_llsd[template_iter->first] = value;
}
}
else
{
//test llsd doesn't have it...take the
//template as default value
resultant_llsd[template_iter->first] =
template_iter->second;
}
}
}
else
{
//of same type...take the test llsd's value
resultant_llsd = llsd_to_test;
}
return TRUE;
}