PageRenderTime 83ms CodeModel.GetById 12ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llsdutil.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 675 lines | 465 code | 60 blank | 150 comment | 80 complexity | 2e14142a9b6e9fbd5b57a04fc75b5164 MD5 | raw file
  1/** 
  2 * @file llsdutil.cpp
  3 * @author Phoenix
  4 * @date 2006-05-24
  5 * @brief Implementation of classes, functions, etc, for using structured data.
  6 *
  7 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29#include "linden_common.h"
 30
 31#include "llsdutil.h"
 32
 33#if LL_WINDOWS
 34#	define WIN32_LEAN_AND_MEAN
 35#	include <winsock2.h>	// for htonl
 36#elif LL_LINUX || LL_SOLARIS
 37#	include <netinet/in.h>
 38#elif LL_DARWIN
 39#	include <arpa/inet.h>
 40#endif
 41
 42#include "llsdserialize.h"
 43#include "stringize.h"
 44#include "is_approx_equal_fraction.h"
 45
 46#include <map>
 47#include <set>
 48#include <boost/range.hpp>
 49
 50// U32
 51LLSD ll_sd_from_U32(const U32 val)
 52{
 53	std::vector<U8> v;
 54	U32 net_order = htonl(val);
 55
 56	v.resize(4);
 57	memcpy(&(v[0]), &net_order, 4);		/* Flawfinder: ignore */
 58
 59	return LLSD(v);
 60}
 61
 62U32 ll_U32_from_sd(const LLSD& sd)
 63{
 64	U32 ret;
 65	std::vector<U8> v = sd.asBinary();
 66	if (v.size() < 4)
 67	{
 68		return 0;
 69	}
 70	memcpy(&ret, &(v[0]), 4);		/* Flawfinder: ignore */
 71	ret = ntohl(ret);
 72	return ret;
 73}
 74
 75//U64
 76LLSD ll_sd_from_U64(const U64 val)
 77{
 78	std::vector<U8> v;
 79	U32 high, low;
 80
 81	high = (U32)(val >> 32);
 82	low = (U32)val;
 83	high = htonl(high);
 84	low = htonl(low);
 85
 86	v.resize(8);
 87	memcpy(&(v[0]), &high, 4);		/* Flawfinder: ignore */
 88	memcpy(&(v[4]), &low, 4);		/* Flawfinder: ignore */
 89
 90	return LLSD(v);
 91}
 92
 93U64 ll_U64_from_sd(const LLSD& sd)
 94{
 95	U32 high, low;
 96	std::vector<U8> v = sd.asBinary();
 97
 98	if (v.size() < 8)
 99	{
100		return 0;
101	}
102
103	memcpy(&high, &(v[0]), 4);		/* Flawfinder: ignore */
104	memcpy(&low, &(v[4]), 4);		/* Flawfinder: ignore */
105	high = ntohl(high);
106	low = ntohl(low);
107
108	return ((U64)high) << 32 | low;
109}
110
111// IP Address (stored in net order in a U32, so don't need swizzling)
112LLSD ll_sd_from_ipaddr(const U32 val)
113{
114	std::vector<U8> v;
115
116	v.resize(4);
117	memcpy(&(v[0]), &val, 4);		/* Flawfinder: ignore */
118
119	return LLSD(v);
120}
121
122U32 ll_ipaddr_from_sd(const LLSD& sd)
123{
124	U32 ret;
125	std::vector<U8> v = sd.asBinary();
126	if (v.size() < 4)
127	{
128		return 0;
129	}
130	memcpy(&ret, &(v[0]), 4);		/* Flawfinder: ignore */
131	return ret;
132}
133
134// Converts an LLSD binary to an LLSD string
135LLSD ll_string_from_binary(const LLSD& sd)
136{
137	std::vector<U8> value = sd.asBinary();
138	std::string str;
139	str.resize(value.size());
140	memcpy(&str[0], &value[0], value.size());
141	return str;
142}
143
144// Converts an LLSD string to an LLSD binary
145LLSD ll_binary_from_string(const LLSD& sd)
146{
147	std::vector<U8> binary_value;
148
149	std::string string_value = sd.asString();
150	for (std::string::iterator iter = string_value.begin();
151		 iter != string_value.end(); ++iter)
152	{
153		binary_value.push_back(*iter);
154	}
155
156	binary_value.push_back('\0');
157
158	return binary_value;
159}
160
161char* ll_print_sd(const LLSD& sd)
162{
163	const U32 bufferSize = 10 * 1024;
164	static char buffer[bufferSize];
165	std::ostringstream stream;
166	//stream.rdbuf()->pubsetbuf(buffer, bufferSize);
167	stream << LLSDOStreamer<LLSDXMLFormatter>(sd);
168	stream << std::ends;
169	strncpy(buffer, stream.str().c_str(), bufferSize);
170	buffer[bufferSize - 1] = '\0';
171	return buffer;
172}
173
174char* ll_pretty_print_sd_ptr(const LLSD* sd)
175{
176	if (sd)
177	{
178		return ll_pretty_print_sd(*sd);
179	}
180	return NULL;
181}
182
183char* ll_pretty_print_sd(const LLSD& sd)
184{
185	const U32 bufferSize = 10 * 1024;
186	static char buffer[bufferSize];
187	std::ostringstream stream;
188	//stream.rdbuf()->pubsetbuf(buffer, bufferSize);
189	stream << LLSDOStreamer<LLSDXMLFormatter>(sd, LLSDFormatter::OPTIONS_PRETTY);
190	stream << std::ends;
191	strncpy(buffer, stream.str().c_str(), bufferSize);
192	buffer[bufferSize - 1] = '\0';
193	return buffer;
194}
195
196//compares the structure of an LLSD to a template LLSD and stores the
197//"valid" values in a 3rd LLSD.  Default values pulled from the template
198//if the tested LLSD does not contain the key/value pair.
199//Excess values in the test LLSD are ignored in the resultant_llsd.
200//If the llsd to test has a specific key to a map and the values
201//are not of the same type, false is returned or if the LLSDs are not
202//of the same value.  Ordering of arrays matters
203//Otherwise, returns true
204BOOL compare_llsd_with_template(
205	const LLSD& llsd_to_test,
206	const LLSD& template_llsd,
207	LLSD& resultant_llsd)
208{
209	if (
210		llsd_to_test.isUndefined() &&
211		template_llsd.isDefined() )
212	{
213		resultant_llsd = template_llsd;
214		return TRUE;
215	}
216	else if ( llsd_to_test.type() != template_llsd.type() )
217	{
218		resultant_llsd = LLSD();
219		return FALSE;
220	}
221
222	if ( llsd_to_test.isArray() )
223	{
224		//they are both arrays
225		//we loop over all the items in the template
226		//verifying that the to_test has a subset (in the same order)
227		//any shortcoming in the testing_llsd are just taken
228		//to be the rest of the template
229		LLSD data;
230		LLSD::array_const_iterator test_iter;
231		LLSD::array_const_iterator template_iter;
232
233		resultant_llsd = LLSD::emptyArray();
234		test_iter = llsd_to_test.beginArray();
235
236		for (
237			template_iter = template_llsd.beginArray();
238			(template_iter != template_llsd.endArray() &&
239			 test_iter != llsd_to_test.endArray());
240			++template_iter)
241		{
242			if ( !compare_llsd_with_template(
243					 *test_iter,
244					 *template_iter,
245					 data) )
246			{
247				resultant_llsd = LLSD();
248				return FALSE;
249			}
250			else
251			{
252				resultant_llsd.append(data);
253			}
254
255			++test_iter;
256		}
257
258		//so either the test or the template ended
259		//we do another loop now to the end of the template
260		//grabbing the default values
261		for (;
262			 template_iter != template_llsd.endArray();
263			 ++template_iter)
264		{
265			resultant_llsd.append(*template_iter);
266		}
267	}
268	else if ( llsd_to_test.isMap() )
269	{
270		//now we loop over the keys of the two maps
271		//any excess is taken from the template
272		//excess is ignored in the test
273		LLSD value;
274		LLSD::map_const_iterator template_iter;
275
276		resultant_llsd = LLSD::emptyMap();
277		for (
278			template_iter = template_llsd.beginMap();
279			template_iter != template_llsd.endMap();
280			++template_iter)
281		{
282			if ( llsd_to_test.has(template_iter->first) )
283			{
284				//the test LLSD has the same key
285				if ( !compare_llsd_with_template(
286						 llsd_to_test[template_iter->first],
287						 template_iter->second,
288						 value) )
289				{
290					resultant_llsd = LLSD();
291					return FALSE;
292				}
293				else
294				{
295					resultant_llsd[template_iter->first] = value;
296				}
297			}
298			else
299			{
300				//test llsd doesn't have it...take the
301				//template as default value
302				resultant_llsd[template_iter->first] =
303					template_iter->second;
304			}
305		}
306	}
307	else
308	{
309		//of same type...take the test llsd's value
310		resultant_llsd = llsd_to_test;
311	}
312
313
314	return TRUE;
315}
316
317/*****************************************************************************
318*   Helpers for llsd_matches()
319*****************************************************************************/
320// raw data used for LLSD::Type lookup
321struct Data
322{
323    LLSD::Type type;
324    const char* name;
325} typedata[] =
326{
327#define def(type) { LLSD::type, #type + 4 }
328    def(TypeUndefined),
329    def(TypeBoolean),
330    def(TypeInteger),
331    def(TypeReal),
332    def(TypeString),
333    def(TypeUUID),
334    def(TypeDate),
335    def(TypeURI),
336    def(TypeBinary),
337    def(TypeMap),
338    def(TypeArray)
339#undef  def
340};
341
342// LLSD::Type lookup class into which we load the above static data
343class TypeLookup
344{
345    typedef std::map<LLSD::Type, std::string> MapType;
346
347public:
348    TypeLookup()
349    {
350        for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
351        {
352            mMap[di->type] = di->name;
353        }
354    }
355
356    std::string lookup(LLSD::Type type) const
357    {
358        MapType::const_iterator found = mMap.find(type);
359        if (found != mMap.end())
360        {
361            return found->second;
362        }
363        return STRINGIZE("<unknown LLSD type " << type << ">");
364    }
365
366private:
367    MapType mMap;
368};
369
370// static instance of the lookup class
371static const TypeLookup sTypes;
372
373// describe a mismatch; phrasing may want tweaking
374const std::string op(" required instead of ");
375
376// llsd_matches() wants to identify specifically where in a complex prototype
377// structure the mismatch occurred. This entails passing a prefix string,
378// empty for the top-level call. If the prototype contains an array of maps,
379// and the mismatch occurs in the second map in a key 'foo', we want to
380// decorate the returned string with: "[1]['foo']: etc." On the other hand, we
381// want to omit the entire prefix -- including colon -- if the mismatch is at
382// top level. This helper accepts the (possibly empty) recursively-accumulated
383// prefix string, returning either empty or the original string with colon
384// appended.
385static std::string colon(const std::string& pfx)
386{
387    if (pfx.empty())
388        return pfx;
389    return pfx + ": ";
390}
391
392// param type for match_types
393typedef std::vector<LLSD::Type> TypeVector;
394
395// The scalar cases in llsd_matches() use this helper. In most cases, we can
396// accept not only the exact type specified in the prototype, but also other
397// types convertible to the expected type. That implies looping over an array
398// of such types. If the actual type doesn't match any of them, we want to
399// provide a list of acceptable conversions as well as the exact type, e.g.:
400// "Integer (or Boolean, Real, String) required instead of UUID". Both the
401// implementation and the calling logic are simplified by separating out the
402// expected type from the convertible types.
403static std::string match_types(LLSD::Type expect, // prototype.type()
404                               const TypeVector& accept, // types convertible to that type
405                               LLSD::Type actual,        // type we're checking
406                               const std::string& pfx)   // as for llsd_matches
407{
408    // Trivial case: if the actual type is exactly what we expect, we're good.
409    if (actual == expect)
410        return "";
411
412    // For the rest of the logic, build up a suitable error string as we go so
413    // we only have to make a single pass over the list of acceptable types.
414    // If we detect success along the way, we'll simply discard the partial
415    // error string.
416    std::ostringstream out;
417    out << colon(pfx) << sTypes.lookup(expect);
418
419    // If there are any convertible types, append that list.
420    if (! accept.empty())
421    {
422        out << " (";
423        const char* sep = "or ";
424        for (TypeVector::const_iterator ai(accept.begin()), aend(accept.end());
425             ai != aend; ++ai, sep = ", ")
426        {
427            // Don't forget to return success if we match any of those types...
428            if (actual == *ai)
429                return "";
430            out << sep << sTypes.lookup(*ai);
431        }
432        out << ')';
433    }
434    // If we got this far, it's because 'actual' was not one of the acceptable
435    // types, so we must return an error. 'out' already contains colon(pfx)
436    // and the formatted list of acceptable types, so just append the mismatch
437    // phrase and the actual type.
438    out << op << sTypes.lookup(actual);
439    return out.str();
440}
441
442// see docstring in .h file
443std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
444{
445    // An undefined prototype means that any data is valid.
446    // An undefined slot in an array or map prototype means that any data
447    // may fill that slot.
448    if (prototype.isUndefined())
449        return "";
450    // A prototype array must match a data array with at least as many
451    // entries. Moreover, every prototype entry must match the
452    // corresponding data entry.
453    if (prototype.isArray())
454    {
455        if (! data.isArray())
456        {
457            return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type()));
458        }
459        if (data.size() < prototype.size())
460        {
461            return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op
462                             << "Array size " << data.size());
463        }
464        for (LLSD::Integer i = 0; i < prototype.size(); ++i)
465        {
466            std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']')));
467            if (! match.empty())
468            {
469                return match;
470            }
471        }
472        return "";
473    }
474    // A prototype map must match a data map. Every key in the prototype
475    // must have a corresponding key in the data map; every value in the
476    // prototype must match the corresponding key's value in the data.
477    if (prototype.isMap())
478    {
479        if (! data.isMap())
480        {
481            return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type()));
482        }
483        // If there are a number of keys missing from the data, it would be
484        // frustrating to a coder to discover them one at a time, with a big
485        // build each time. Enumerate all missing keys.
486        std::ostringstream out;
487        out << colon(pfx);
488        const char* init = "Map missing keys: ";
489        const char* sep = init;
490        for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi)
491        {
492            if (! data.has(mi->first))
493            {
494                out << sep << mi->first;
495                sep = ", ";
496            }
497        }
498        // So... are we missing any keys?
499        if (sep != init)
500        {
501            return out.str();
502        }
503        // Good, the data block contains all the keys required by the
504        // prototype. Now match the prototype entries.
505        for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2)
506        {
507            std::string match(llsd_matches(mi2->second, data[mi2->first],
508                                           STRINGIZE("['" << mi2->first << "']")));
509            if (! match.empty())
510            {
511                return match;
512            }
513        }
514        return "";
515    }
516    // A String prototype can match String, Boolean, Integer, Real, UUID,
517    // Date and URI, because any of these can be converted to String.
518    if (prototype.isString())
519    {
520        static LLSD::Type accept[] =
521        {
522            LLSD::TypeBoolean,
523            LLSD::TypeInteger,
524            LLSD::TypeReal,
525            LLSD::TypeUUID,
526            LLSD::TypeDate,
527            LLSD::TypeURI
528        };
529        return match_types(prototype.type(),
530                           TypeVector(boost::begin(accept), boost::end(accept)),
531                           data.type(),
532                           pfx);
533    }
534    // Boolean, Integer, Real match each other or String. TBD: ensure that
535    // a String value is numeric.
536    if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal())
537    {
538        static LLSD::Type all[] =
539        {
540            LLSD::TypeBoolean,
541            LLSD::TypeInteger,
542            LLSD::TypeReal,
543            LLSD::TypeString
544        };
545        // Funny business: shuffle the set of acceptable types to include all
546        // but the prototype's type. Get the acceptable types in a set.
547        std::set<LLSD::Type> rest(boost::begin(all), boost::end(all));
548        // Remove the prototype's type because we pass that separately.
549        rest.erase(prototype.type());
550        return match_types(prototype.type(),
551                           TypeVector(rest.begin(), rest.end()),
552                           data.type(),
553                           pfx);
554    }
555    // UUID, Date and URI match themselves or String.
556    if (prototype.isUUID() || prototype.isDate() || prototype.isURI())
557    {
558        static LLSD::Type accept[] =
559        {
560            LLSD::TypeString
561        };
562        return match_types(prototype.type(),
563                           TypeVector(boost::begin(accept), boost::end(accept)),
564                           data.type(),
565                           pfx);
566    }
567    // We don't yet know the conversion semantics associated with any new LLSD
568    // data type that might be added, so until we've been extended to handle
569    // them, assume it's strict: the new type matches only itself. (This is
570    // true of Binary, which is why we don't handle that case separately.) Too
571    // bad LLSD doesn't define isConvertible(Type to, Type from).
572    return match_types(prototype.type(), TypeVector(), data.type(), pfx);
573}
574
575bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits)
576{
577    // We're comparing strict equality of LLSD representation rather than
578    // performing any conversions. So if the types aren't equal, the LLSD
579    // values aren't equal.
580    if (lhs.type() != rhs.type())
581    {
582        return false;
583    }
584
585    // Here we know both types are equal. Now compare values.
586    switch (lhs.type())
587    {
588    case LLSD::TypeUndefined:
589        // Both are TypeUndefined. There's nothing more to know.
590        return true;
591
592    case LLSD::TypeReal:
593        // This is where the 'bits' argument comes in handy. If passed
594        // explicitly, it means to use is_approx_equal_fraction() to compare.
595        if (bits >= 0)
596        {
597            return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits);
598        }
599        // Otherwise we compare bit representations, and the usual caveats
600        // about comparing floating-point numbers apply. Omitting 'bits' when
601        // comparing Real values is only useful when we expect identical bit
602        // representation for a given Real value, e.g. for integer-valued
603        // Reals.
604        return (lhs.asReal() == rhs.asReal());
605
606#define COMPARE_SCALAR(type)                                    \
607    case LLSD::Type##type:                                      \
608        /* LLSD::URI has operator!=() but not operator==() */   \
609        /* rely on the optimizer for all others */              \
610        return (! (lhs.as##type() != rhs.as##type()))
611
612    COMPARE_SCALAR(Boolean);
613    COMPARE_SCALAR(Integer);
614    COMPARE_SCALAR(String);
615    COMPARE_SCALAR(UUID);
616    COMPARE_SCALAR(Date);
617    COMPARE_SCALAR(URI);
618    COMPARE_SCALAR(Binary);
619
620#undef COMPARE_SCALAR
621
622    case LLSD::TypeArray:
623    {
624        LLSD::array_const_iterator
625            lai(lhs.beginArray()), laend(lhs.endArray()),
626            rai(rhs.beginArray()), raend(rhs.endArray());
627        // Compare array elements, walking the two arrays in parallel.
628        for ( ; lai != laend && rai != raend; ++lai, ++rai)
629        {
630            // If any one array element is unequal, the arrays are unequal.
631            if (! llsd_equals(*lai, *rai, bits))
632                return false;
633        }
634        // Here we've reached the end of one or the other array. They're equal
635        // only if they're BOTH at end: that is, if they have equal length too.
636        return (lai == laend && rai == raend);
637    }
638
639    case LLSD::TypeMap:
640    {
641        // Build a set of all rhs keys.
642        std::set<LLSD::String> rhskeys;
643        for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
644             rmi != rmend; ++rmi)
645        {
646            rhskeys.insert(rmi->first);
647        }
648        // Now walk all the lhs keys.
649        for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
650             lmi != lmend; ++lmi)
651        {
652            // Try to erase this lhs key from the set of rhs keys. If rhs has
653            // no such key, the maps are unequal. erase(key) returns count of
654            // items erased.
655            if (rhskeys.erase(lmi->first) != 1)
656                return false;
657            // Both maps have the current key. Compare values.
658            if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
659                return false;
660        }
661        // We've now established that all the lhs keys have equal values in
662        // both maps. The maps are equal unless rhs contains a superset of
663        // those keys.
664        return rhskeys.empty();
665    }
666
667    default:
668        // We expect that every possible type() value is specifically handled
669        // above. Failing to extend this switch to support a new LLSD type is
670        // an error that must be brought to the coder's attention.
671        LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
672            "unknown type " << lhs.type() << LL_ENDL;
673        return false;               // pacify the compiler
674    }
675}