//private
bool LLFloaterMediaSettings::haveValuesChanged() const
{
	bool values_changed = false;
	// *NOTE: The code below is very inefficient.  Better to do this
	// only when data change.
	// Every frame, check to see what the values are.  If they are not
	// the same as the initial media data, enable the OK/Apply buttons
	LLSD settings;
	sInstance->mPanelMediaSettingsGeneral->getValues( settings );
	sInstance->mPanelMediaSettingsSecurity->getValues( settings );
	sInstance->mPanelMediaSettingsPermissions->getValues( settings );	
	LLSD::map_const_iterator iter = settings.beginMap();
	LLSD::map_const_iterator end = settings.endMap();
	for ( ; iter != end; ++iter )
	{
		const std::string &current_key = iter->first;
		const LLSD &current_value = iter->second;
		if ( ! llsd_equals(current_value, mInitialValues[current_key]))
		{
			values_changed = true;
			break;
		}
	}
	return values_changed;
}
void LLPostProcess::resetSelectedEffect()
{
	if(!llsd_equals(mAllEffectInfo[mSelectedEffectName], mSelectedEffectInfo))
	{
		mSelectedEffectInfo = mAllEffectInfo[mSelectedEffectName];
		for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
		{
			(*it)->loadSettings(mSelectedEffectInfo);
		}
	}
}
 void ensure_llsd_equals(const std::string& msg, const LLSD& expected, const LLSD& actual)
 {
     if (!llsd_equals(expected, actual))
     {
         std::string message = msg;
         message += ": actual: ";
         message += ll_pretty_print_sd(actual);
         message += "\n  expected: ";
         message += ll_pretty_print_sd(expected);
         message += "\n";
         ensure(message, false);
     }
 }
void LLReqID::stamp(LLSD& response) const
{
    if (! (response.isUndefined() || response.isMap()))
    {
        // If 'response' was previously completely empty, it's okay to
        // turn it into a map. If it was already a map, then it should be
        // okay to add a key. But if it was anything else (e.g. a scalar),
        // assigning a ["reqid"] key will DISCARD the previous value,
        // replacing it with a map. That would be Bad.
        LL_INFOS("LLReqID") << "stamp(" << mReqid << ") leaving non-map response unmodified: "
                            << response << LL_ENDL;
        return;
    }
    LLSD oldReqid(response["reqid"]);
    if (! (oldReqid.isUndefined() || llsd_equals(oldReqid, mReqid)))
    {
        LL_INFOS("LLReqID") << "stamp(" << mReqid << ") preserving existing [\"reqid\"] value "
                            << oldReqid << " in response: " << response << LL_ENDL;
        return;
    }
    response["reqid"] = mReqid;
}
    void llsdutil_object::test<9>()
    {
        set_test_name("llsd_matches");

        // for this test, construct a map of all possible LLSD types
        LLSD map;
        map.insert("empty",     LLSD());
        map.insert("Boolean",   LLSD::Boolean());
        map.insert("Integer",   LLSD::Integer(0));
        map.insert("Real",      LLSD::Real(0.0));
        map.insert("String",    LLSD::String("bah"));
        map.insert("NumString", LLSD::String("1"));
        map.insert("UUID",      LLSD::UUID());
        map.insert("Date",      LLSD::Date());
        map.insert("URI",       LLSD::URI());
        map.insert("Binary",    LLSD::Binary());
        map.insert("Map",       LLSD().with("foo", LLSD()));
        // Only an empty array can be constructed on the fly
        LLSD array;
        array.append(LLSD());
        map.insert("Array",     array);

        // These iterators are declared outside our various for loops to avoid
        // fatal MSVC warning: "I used to be broken, but I'm all better now!"
        LLSD::map_const_iterator mi, mend(map.endMap());

        /*-------------------------- llsd_matches --------------------------*/

        // empty prototype matches anything
        for (mi = map.beginMap(); mi != mend; ++mi)
        {
            ensure_equals(std::string("empty matches ") + mi->first, llsd_matches(LLSD(), mi->second), "");
        }

        LLSD proto_array, data_array;
        for (int i = 0; i < 3; ++i)
        {
            proto_array.append(LLSD());
            data_array.append(LLSD());
        }

        // prototype array matches only array
        for (mi = map.beginMap(); mi != mend; ++mi)
        {
            ensure(std::string("array doesn't match ") + mi->first,
                   ! llsd_matches(proto_array, mi->second).empty());
        }

        // data array must be at least as long as prototype array
        proto_array.append(LLSD());
        ensure_equals("data array too short", llsd_matches(proto_array, data_array),
                      "Array size 4 required instead of Array size 3");
        data_array.append(LLSD());
        ensure_equals("data array just right", llsd_matches(proto_array, data_array), "");
        data_array.append(LLSD());
        ensure_equals("data array longer", llsd_matches(proto_array, data_array), "");

        // array element matching
        data_array[0] = LLSD::String();
        ensure_equals("undefined prototype array entry", llsd_matches(proto_array, data_array), "");
        proto_array[0] = LLSD::Binary();
        ensure_equals("scalar prototype array entry", llsd_matches(proto_array, data_array),
                      "[0]: Binary required instead of String");
        data_array[0] = LLSD::Binary();
        ensure_equals("matching prototype array entry", llsd_matches(proto_array, data_array), "");

        // build a coupla maps
        LLSD proto_map, data_map;
        data_map["got"] = LLSD();
        data_map["found"] = LLSD();
        for (LLSD::map_const_iterator dmi(data_map.beginMap()), dmend(data_map.endMap());
             dmi != dmend; ++dmi)
        {
            proto_map[dmi->first] = dmi->second;
        }
        proto_map["foo"] = LLSD();
        proto_map["bar"] = LLSD();

        // prototype map matches only map
        for (mi = map.beginMap(); mi != mend; ++mi)
        {
            ensure(std::string("map doesn't match ") + mi->first,
                   ! llsd_matches(proto_map, mi->second).empty());
        }

        // data map must contain all keys in prototype map
        std::string error(llsd_matches(proto_map, data_map));
        ensure_contains("missing keys", error, "missing keys");
        ensure_contains("missing foo", error, "foo");
        ensure_contains("missing bar", error, "bar");
        ensure_does_not_contain("found found", error, "found");
        ensure_does_not_contain("got got", error, "got");
        data_map["bar"] = LLSD();
        error = llsd_matches(proto_map, data_map);
        ensure_contains("missing foo", error, "foo");
        ensure_does_not_contain("got bar", error, "bar");
        data_map["foo"] = LLSD();
        ensure_equals("data map just right", llsd_matches(proto_map, data_map), "");
        data_map["extra"] = LLSD();
        ensure_equals("data map with extra", llsd_matches(proto_map, data_map), "");

        // map element matching
        data_map["foo"] = LLSD::String();
        ensure_equals("undefined prototype map entry", llsd_matches(proto_map, data_map), "");
        proto_map["foo"] = LLSD::Binary();
        ensure_equals("scalar prototype map entry", llsd_matches(proto_map, data_map),
                      "['foo']: Binary required instead of String");
        data_map["foo"] = LLSD::Binary();
        ensure_equals("matching prototype map entry", llsd_matches(proto_map, data_map), "");

        // String
        {
            static const char* matches[] = { "String", "NumString", "Boolean", "Integer",
                                             "Real", "UUID", "Date", "URI" };
            test_matches("String", map, boost::begin(matches), boost::end(matches));
        }

        // Boolean, Integer, Real
        static const char* numerics[] = { "Boolean", "Integer", "Real" };
        for (const char **ni = boost::begin(numerics), **nend = boost::end(numerics);
             ni != nend; ++ni)
        {
            static const char* matches[] = { "Boolean", "Integer", "Real", "String", "NumString" };
            test_matches(*ni, map, boost::begin(matches), boost::end(matches));
        }

        // UUID
        {
            static const char* matches[] = { "UUID", "String", "NumString" };
            test_matches("UUID", map, boost::begin(matches), boost::end(matches));
        }

        // Date
        {
            static const char* matches[] = { "Date", "String", "NumString" };
            test_matches("Date", map, boost::begin(matches), boost::end(matches));
        }

        // URI
        {
            static const char* matches[] = { "URI", "String", "NumString" };
            test_matches("URI", map, boost::begin(matches), boost::end(matches));
        }

        // Binary
        {
            static const char* matches[] = { "Binary" };
            test_matches("Binary", map, boost::begin(matches), boost::end(matches));
        }

        /*-------------------------- llsd_equals ---------------------------*/

        // Cross-product of each LLSD type with every other
        for (LLSD::map_const_iterator lmi(map.beginMap()), lmend(map.endMap());
             lmi != lmend; ++lmi)
        {
            for (LLSD::map_const_iterator rmi(map.beginMap()), rmend(map.endMap());
                 rmi != rmend; ++rmi)
            {
                // Name this test based on the map keys naming the types of
                // interest, e.g "String::Integer".
                // We expect the values (xmi->second) to be equal if and only
                // if the type names (xmi->first) are equal.
                ensure(STRINGIZE(lmi->first << "::" << rmi->first),
                       bool(lmi->first == rmi->first) ==
                       bool(llsd_equals(lmi->second, rmi->second)));
            }
        }

        // Array cases
        LLSD rarray;
        rarray.append(1.0);
        rarray.append(2);
        rarray.append("3");
        LLSD larray(rarray);
        ensure("llsd_equals(equal arrays)", llsd_equals(larray, rarray));
        rarray[2] = "4";
        ensure("llsd_equals(different [2])", ! llsd_equals(larray, rarray));
        rarray = larray;
        rarray.append(LLSD::Date());
        ensure("llsd_equals(longer right array)", ! llsd_equals(larray, rarray));
        rarray = larray;
        rarray.erase(2);
        ensure("llsd_equals(shorter right array)", ! llsd_equals(larray, rarray));

        // Map cases
        LLSD rmap;
        rmap["San Francisco"] = 65;
        rmap["Phoenix"] = 92;
        rmap["Boston"] = 77;
        LLSD lmap(rmap);
        ensure("llsd_equals(equal maps)", llsd_equals(lmap, rmap));
        rmap["Boston"] = 80;
        ensure("llsd_equals(different [\"Boston\"])", ! llsd_equals(lmap, rmap));
        rmap = lmap;
        rmap["Atlanta"] = 95;
        ensure("llsd_equals(superset right map)", ! llsd_equals(lmap, rmap));
        rmap = lmap;
        lmap["Seattle"] = 72;
        ensure("llsd_equals(superset left map)", ! llsd_equals(lmap, rmap));
    }
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits)
{
    // We're comparing strict equality of LLSD representation rather than
    // performing any conversions. So if the types aren't equal, the LLSD
    // values aren't equal.
    if (lhs.type() != rhs.type())
    {
        return false;
    }

    // Here we know both types are equal. Now compare values.
    switch (lhs.type())
    {
    case LLSD::TypeUndefined:
        // Both are TypeUndefined. There's nothing more to know.
        return true;

    case LLSD::TypeReal:
        // This is where the 'bits' argument comes in handy. If passed
        // explicitly, it means to use is_approx_equal_fraction() to compare.
        if (bits >= 0)
        {
            return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits);
        }
        // Otherwise we compare bit representations, and the usual caveats
        // about comparing floating-point numbers apply. Omitting 'bits' when
        // comparing Real values is only useful when we expect identical bit
        // representation for a given Real value, e.g. for integer-valued
        // Reals.
        return (lhs.asReal() == rhs.asReal());

#define COMPARE_SCALAR(type)                                    \
    case LLSD::Type##type:                                      \
        /* LLSD::URI has operator!=() but not operator==() */   \
        /* rely on the optimizer for all others */              \
        return (! (lhs.as##type() != rhs.as##type()))

    COMPARE_SCALAR(Boolean);
    COMPARE_SCALAR(Integer);
    COMPARE_SCALAR(String);
    COMPARE_SCALAR(UUID);
    COMPARE_SCALAR(Date);
    COMPARE_SCALAR(URI);
    COMPARE_SCALAR(Binary);

#undef COMPARE_SCALAR

    case LLSD::TypeArray:
    {
        LLSD::array_const_iterator
            lai(lhs.beginArray()), laend(lhs.endArray()),
            rai(rhs.beginArray()), raend(rhs.endArray());
        // Compare array elements, walking the two arrays in parallel.
        for ( ; lai != laend && rai != raend; ++lai, ++rai)
        {
            // If any one array element is unequal, the arrays are unequal.
            if (! llsd_equals(*lai, *rai, bits))
                return false;
        }
        // Here we've reached the end of one or the other array. They're equal
        // only if they're BOTH at end: that is, if they have equal length too.
        return (lai == laend && rai == raend);
    }

    case LLSD::TypeMap:
    {
        // Build a set of all rhs keys.
        std::set<LLSD::String> rhskeys;
        for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
             rmi != rmend; ++rmi)
        {
            rhskeys.insert(rmi->first);
        }
        // Now walk all the lhs keys.
        for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
             lmi != lmend; ++lmi)
        {
            // Try to erase this lhs key from the set of rhs keys. If rhs has
            // no such key, the maps are unequal. erase(key) returns count of
            // items erased.
            if (rhskeys.erase(lmi->first) != 1)
                return false;
            // Both maps have the current key. Compare values.
            if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
                return false;
        }
        // We've now established that all the lhs keys have equal values in
        // both maps. The maps are equal unless rhs contains a superset of
        // those keys.
        return rhskeys.empty();
    }

    default:
        // We expect that every possible type() value is specifically handled
        // above. Failing to extend this switch to support a new LLSD type is
        // an error that must be brought to the coder's attention.
        LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
            "unknown type " << lhs.type() << LL_ENDL;
        return false;               // pacify the compiler
    }
}