summaryrefslogtreecommitdiff
path: root/indra/llprimitive/llmediaentry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llprimitive/llmediaentry.cpp')
-rw-r--r--indra/llprimitive/llmediaentry.cpp597
1 files changed, 597 insertions, 0 deletions
diff --git a/indra/llprimitive/llmediaentry.cpp b/indra/llprimitive/llmediaentry.cpp
new file mode 100644
index 0000000000..fa04bf80e7
--- /dev/null
+++ b/indra/llprimitive/llmediaentry.cpp
@@ -0,0 +1,597 @@
+/**
+ * @file llmediaentry.cpp
+ * @brief This is a single instance of media data related to the face of a prim
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-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 "llmediaentry.h"
+#include "lllslconstants.h"
+
+#include <boost/regex.hpp>
+
+// LLSD key defines
+// DO NOT REORDER OR REMOVE THESE!
+
+// Some LLSD keys. Do not change!
+#define MEDIA_ALT_IMAGE_ENABLE_KEY_STR "alt_image_enable"
+#define MEDIA_CONTROLS_KEY_STR "controls"
+#define MEDIA_CURRENT_URL_KEY_STR "current_url"
+#define MEDIA_HOME_URL_KEY_STR "home_url"
+#define MEDIA_AUTO_LOOP_KEY_STR "auto_loop"
+#define MEDIA_AUTO_PLAY_KEY_STR "auto_play"
+#define MEDIA_AUTO_SCALE_KEY_STR "auto_scale"
+#define MEDIA_AUTO_ZOOM_KEY_STR "auto_zoom"
+#define MEDIA_FIRST_CLICK_INTERACT_KEY_STR "first_click_interact"
+#define MEDIA_WIDTH_PIXELS_KEY_STR "width_pixels"
+#define MEDIA_HEIGHT_PIXELS_KEY_STR "height_pixels"
+
+// "security" fields
+#define MEDIA_WHITELIST_ENABLE_KEY_STR "whitelist_enable"
+#define MEDIA_WHITELIST_KEY_STR "whitelist"
+
+// "permissions" fields
+#define MEDIA_PERMS_INTERACT_KEY_STR "perms_interact"
+#define MEDIA_PERMS_CONTROL_KEY_STR "perms_control"
+
+// "general" fields
+const char* LLMediaEntry::ALT_IMAGE_ENABLE_KEY = MEDIA_ALT_IMAGE_ENABLE_KEY_STR;
+const char* LLMediaEntry::CONTROLS_KEY = MEDIA_CONTROLS_KEY_STR;
+const char* LLMediaEntry::CURRENT_URL_KEY = MEDIA_CURRENT_URL_KEY_STR;
+const char* LLMediaEntry::HOME_URL_KEY = MEDIA_HOME_URL_KEY_STR;
+const char* LLMediaEntry::AUTO_LOOP_KEY = MEDIA_AUTO_LOOP_KEY_STR;
+const char* LLMediaEntry::AUTO_PLAY_KEY = MEDIA_AUTO_PLAY_KEY_STR;
+const char* LLMediaEntry::AUTO_SCALE_KEY = MEDIA_AUTO_SCALE_KEY_STR;
+const char* LLMediaEntry::AUTO_ZOOM_KEY = MEDIA_AUTO_ZOOM_KEY_STR;
+const char* LLMediaEntry::FIRST_CLICK_INTERACT_KEY = MEDIA_FIRST_CLICK_INTERACT_KEY_STR;
+const char* LLMediaEntry::WIDTH_PIXELS_KEY = MEDIA_WIDTH_PIXELS_KEY_STR;
+const char* LLMediaEntry::HEIGHT_PIXELS_KEY = MEDIA_HEIGHT_PIXELS_KEY_STR;
+
+// "security" fields
+const char* LLMediaEntry::WHITELIST_ENABLE_KEY = MEDIA_WHITELIST_ENABLE_KEY_STR;
+const char* LLMediaEntry::WHITELIST_KEY = MEDIA_WHITELIST_KEY_STR;
+
+// "permissions" fields
+const char* LLMediaEntry::PERMS_INTERACT_KEY = MEDIA_PERMS_INTERACT_KEY_STR;
+const char* LLMediaEntry::PERMS_CONTROL_KEY = MEDIA_PERMS_CONTROL_KEY_STR;
+
+#define DEFAULT_URL_PREFIX "http://"
+
+// Constructor(s)
+LLMediaEntry::LLMediaEntry() :
+ mAltImageEnable(false),
+ mControls(STANDARD),
+ mCurrentURL(""),
+ mHomeURL(""),
+ mAutoLoop(false),
+ mAutoPlay(false),
+ mAutoScale(false),
+ mAutoZoom(false),
+ mFirstClickInteract(false),
+ mWidthPixels(0),
+ mHeightPixels(0),
+ mWhiteListEnable(false),
+ // mWhiteList
+ mPermsInteract(PERM_ALL),
+ mPermsControl(PERM_ALL),
+ mMediaIDp(NULL)
+{
+}
+
+LLMediaEntry::LLMediaEntry(const LLMediaEntry &rhs) :
+ mMediaIDp(NULL)
+{
+ // "general" fields
+ mAltImageEnable = rhs.mAltImageEnable;
+ mControls = rhs.mControls;
+ mCurrentURL = rhs.mCurrentURL;
+ mHomeURL = rhs.mHomeURL;
+ mAutoLoop = rhs.mAutoLoop;
+ mAutoPlay = rhs.mAutoPlay;
+ mAutoScale = rhs.mAutoScale;
+ mAutoZoom = rhs.mAutoZoom;
+ mFirstClickInteract = rhs.mFirstClickInteract;
+ mWidthPixels = rhs.mWidthPixels;
+ mHeightPixels = rhs.mHeightPixels;
+
+ // "security" fields
+ mWhiteListEnable = rhs.mWhiteListEnable;
+ mWhiteList = rhs.mWhiteList;
+
+ // "permissions" fields
+ mPermsInteract = rhs.mPermsInteract;
+ mPermsControl = rhs.mPermsControl;
+}
+
+LLMediaEntry::~LLMediaEntry()
+{
+ if (NULL != mMediaIDp)
+ {
+ delete mMediaIDp;
+ }
+}
+
+LLSD LLMediaEntry::asLLSD() const
+{
+ LLSD sd;
+ asLLSD(sd);
+ return sd;
+}
+
+//
+// LLSD functions
+//
+void LLMediaEntry::asLLSD(LLSD& sd) const
+{
+ // "general" fields
+ sd[ALT_IMAGE_ENABLE_KEY] = mAltImageEnable;
+ sd[CONTROLS_KEY] = (LLSD::Integer)mControls;
+ sd[CURRENT_URL_KEY] = mCurrentURL;
+ sd[HOME_URL_KEY] = mHomeURL;
+ sd[AUTO_LOOP_KEY] = mAutoLoop;
+ sd[AUTO_PLAY_KEY] = mAutoPlay;
+ sd[AUTO_SCALE_KEY] = mAutoScale;
+ sd[AUTO_ZOOM_KEY] = mAutoZoom;
+ sd[FIRST_CLICK_INTERACT_KEY] = mFirstClickInteract;
+ sd[WIDTH_PIXELS_KEY] = mWidthPixels;
+ sd[HEIGHT_PIXELS_KEY] = mHeightPixels;
+
+ // "security" fields
+ sd[WHITELIST_ENABLE_KEY] = mWhiteListEnable;
+ for (U32 i=0; i<mWhiteList.size(); i++)
+ {
+ sd[WHITELIST_KEY].append(mWhiteList[i]);
+ }
+
+ // "permissions" fields
+ sd[PERMS_INTERACT_KEY] = mPermsInteract;
+ sd[PERMS_CONTROL_KEY] = mPermsControl;
+}
+
+// static
+bool LLMediaEntry::checkLLSD(const LLSD& sd)
+{
+ if (sd.isUndefined()) return true;
+ LLMediaEntry temp;
+ return temp.fromLLSDInternal(sd, true);
+}
+
+void LLMediaEntry::fromLLSD(const LLSD& sd)
+{
+ (void)fromLLSDInternal(sd, true);
+}
+
+void LLMediaEntry::mergeFromLLSD(const LLSD& sd)
+{
+ (void)fromLLSDInternal(sd, false);
+}
+
+// *NOTE: returns true if NO failures to set occurred, false otherwise.
+// However, be aware that if a failure to set does occur, it does
+// not stop setting fields from the LLSD!
+bool LLMediaEntry::fromLLSDInternal(const LLSD& sd, bool overwrite)
+{
+ // *HACK: we sort of cheat here and assume that status is a
+ // bit field. We "or" into status and instead of returning
+ // it, we return whether it finishes off as LSL_STATUS_OK or not.
+ U32 status = LSL_STATUS_OK;
+
+ // "general" fields
+ if ( overwrite || sd.has(ALT_IMAGE_ENABLE_KEY) )
+ {
+ status |= setAltImageEnable( sd[ALT_IMAGE_ENABLE_KEY] );
+ }
+ if ( overwrite || sd.has(CONTROLS_KEY) )
+ {
+ status |= setControls( (MediaControls)(LLSD::Integer)sd[CONTROLS_KEY] );
+ }
+ if ( overwrite || sd.has(CURRENT_URL_KEY) )
+ {
+ // Don't check whitelist
+ status |= setCurrentURLInternal( sd[CURRENT_URL_KEY], false );
+ }
+ if ( overwrite || sd.has(HOME_URL_KEY) )
+ {
+ status |= setHomeURL( sd[HOME_URL_KEY] );
+ }
+ if ( overwrite || sd.has(AUTO_LOOP_KEY) )
+ {
+ status |= setAutoLoop( sd[AUTO_LOOP_KEY] );
+ }
+ if ( overwrite || sd.has(AUTO_PLAY_KEY) )
+ {
+ status |= setAutoPlay( sd[AUTO_PLAY_KEY] );
+ }
+ if ( overwrite || sd.has(AUTO_SCALE_KEY) )
+ {
+ status |= setAutoScale( sd[AUTO_SCALE_KEY] );
+ }
+ if ( overwrite || sd.has(AUTO_ZOOM_KEY) )
+ {
+ status |= setAutoZoom( sd[AUTO_ZOOM_KEY] );
+ }
+ if ( overwrite || sd.has(FIRST_CLICK_INTERACT_KEY) )
+ {
+ status |= setFirstClickInteract( sd[FIRST_CLICK_INTERACT_KEY] );
+ }
+ if ( overwrite || sd.has(WIDTH_PIXELS_KEY) )
+ {
+ status |= setWidthPixels( (LLSD::Integer)sd[WIDTH_PIXELS_KEY] );
+ }
+ if ( overwrite || sd.has(HEIGHT_PIXELS_KEY) )
+ {
+ status |= setHeightPixels( (LLSD::Integer)sd[HEIGHT_PIXELS_KEY] );
+ }
+
+ // "security" fields
+ if ( overwrite || sd.has(WHITELIST_ENABLE_KEY) )
+ {
+ status |= setWhiteListEnable( sd[WHITELIST_ENABLE_KEY] );
+ }
+ if ( overwrite || sd.has(WHITELIST_KEY) )
+ {
+ status |= setWhiteList( sd[WHITELIST_KEY] );
+ }
+
+ // "permissions" fields
+ if ( overwrite || sd.has(PERMS_INTERACT_KEY) )
+ {
+ status |= setPermsInteract( 0xff & (LLSD::Integer)sd[PERMS_INTERACT_KEY] );
+ }
+ if ( overwrite || sd.has(PERMS_CONTROL_KEY) )
+ {
+ status |= setPermsControl( 0xff & (LLSD::Integer)sd[PERMS_CONTROL_KEY] );
+ }
+
+ return LSL_STATUS_OK == status;
+}
+
+LLMediaEntry& LLMediaEntry::operator=(const LLMediaEntry &rhs)
+{
+ if (this != &rhs)
+ {
+ // "general" fields
+ mAltImageEnable = rhs.mAltImageEnable;
+ mControls = rhs.mControls;
+ mCurrentURL = rhs.mCurrentURL;
+ mHomeURL = rhs.mHomeURL;
+ mAutoLoop = rhs.mAutoLoop;
+ mAutoPlay = rhs.mAutoPlay;
+ mAutoScale = rhs.mAutoScale;
+ mAutoZoom = rhs.mAutoZoom;
+ mFirstClickInteract = rhs.mFirstClickInteract;
+ mWidthPixels = rhs.mWidthPixels;
+ mHeightPixels = rhs.mHeightPixels;
+
+ // "security" fields
+ mWhiteListEnable = rhs.mWhiteListEnable;
+ mWhiteList = rhs.mWhiteList;
+
+ // "permissions" fields
+ mPermsInteract = rhs.mPermsInteract;
+ mPermsControl = rhs.mPermsControl;
+ }
+
+ return *this;
+}
+
+bool LLMediaEntry::operator==(const LLMediaEntry &rhs) const
+{
+ return (
+ // "general" fields
+ mAltImageEnable == rhs.mAltImageEnable &&
+ mControls == rhs.mControls &&
+ mCurrentURL == rhs.mCurrentURL &&
+ mHomeURL == rhs.mHomeURL &&
+ mAutoLoop == rhs.mAutoLoop &&
+ mAutoPlay == rhs.mAutoPlay &&
+ mAutoScale == rhs.mAutoScale &&
+ mAutoZoom == rhs.mAutoZoom &&
+ mFirstClickInteract == rhs.mFirstClickInteract &&
+ mWidthPixels == rhs.mWidthPixels &&
+ mHeightPixels == rhs.mHeightPixels &&
+
+ // "security" fields
+ mWhiteListEnable == rhs.mWhiteListEnable &&
+ mWhiteList == rhs.mWhiteList &&
+
+ // "permissions" fields
+ mPermsInteract == rhs.mPermsInteract &&
+ mPermsControl == rhs.mPermsControl
+
+ );
+}
+
+bool LLMediaEntry::operator!=(const LLMediaEntry &rhs) const
+{
+ return (
+ // "general" fields
+ mAltImageEnable != rhs.mAltImageEnable ||
+ mControls != rhs.mControls ||
+ mCurrentURL != rhs.mCurrentURL ||
+ mHomeURL != rhs.mHomeURL ||
+ mAutoLoop != rhs.mAutoLoop ||
+ mAutoPlay != rhs.mAutoPlay ||
+ mAutoScale != rhs.mAutoScale ||
+ mAutoZoom != rhs.mAutoZoom ||
+ mFirstClickInteract != rhs.mFirstClickInteract ||
+ mWidthPixels != rhs.mWidthPixels ||
+ mHeightPixels != rhs.mHeightPixels ||
+
+ // "security" fields
+ mWhiteListEnable != rhs.mWhiteListEnable ||
+ mWhiteList != rhs.mWhiteList ||
+
+ // "permissions" fields
+ mPermsInteract != rhs.mPermsInteract ||
+ mPermsControl != rhs.mPermsControl
+
+ );
+}
+
+U32 LLMediaEntry::setWhiteList( const std::vector<std::string> &whitelist )
+{
+ // *NOTE: This code is VERY similar to the setWhitelist below.
+ // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER!
+ U32 size = 0;
+ U32 count = 0;
+ // First count to make sure the size constraint is not violated
+ std::vector<std::string>::const_iterator iter = whitelist.begin();
+ std::vector<std::string>::const_iterator end = whitelist.end();
+ for ( ; iter < end; ++iter)
+ {
+ const std::string &entry = (*iter);
+ size += entry.length() + 1; // Include one for \0
+ count ++;
+ if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT)
+ {
+ return LSL_STATUS_BOUNDS_ERROR;
+ }
+ }
+ // Next clear the vector
+ mWhiteList.clear();
+ // Then re-iterate and copy entries
+ iter = whitelist.begin();
+ for ( ; iter < end; ++iter)
+ {
+ const std::string &entry = (*iter);
+ mWhiteList.push_back(entry);
+ }
+ return LSL_STATUS_OK;
+}
+
+U32 LLMediaEntry::setWhiteList( const LLSD &whitelist )
+{
+ // If whitelist is undef, this is a no-op.
+ if (whitelist.isUndefined()) return LSL_STATUS_OK;
+
+ // However, if the whitelist is an empty array, erase it.
+ if (whitelist.isArray())
+ {
+ // *NOTE: This code is VERY similar to the setWhitelist above.
+ // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER!
+ U32 size = 0;
+ U32 count = 0;
+ // First check to make sure the size and count constraints are not violated
+ LLSD::array_const_iterator iter = whitelist.beginArray();
+ LLSD::array_const_iterator end = whitelist.endArray();
+ for ( ; iter < end; ++iter)
+ {
+ const std::string &entry = (*iter).asString();
+ size += entry.length() + 1; // Include one for \0
+ count ++;
+ if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT)
+ {
+ return LSL_STATUS_BOUNDS_ERROR;
+ }
+ }
+ // Next clear the vector
+ mWhiteList.clear();
+ // Then re-iterate and copy entries
+ iter = whitelist.beginArray();
+ for ( ; iter < end; ++iter)
+ {
+ const std::string &entry = (*iter).asString();
+ mWhiteList.push_back(entry);
+ }
+ return LSL_STATUS_OK;
+ }
+ else
+ {
+ return LSL_STATUS_MALFORMED_PARAMS;
+ }
+}
+
+
+static void prefix_with(std::string &str, const char *chars, const char *prefix)
+{
+ // Given string 'str', prefix all instances of any character in 'chars'
+ // with 'prefix'
+ size_t found = str.find_first_of(chars);
+ size_t prefix_len = strlen(prefix);
+ while (found != std::string::npos)
+ {
+ str.insert(found, prefix, prefix_len);
+ found = str.find_first_of(chars, found+prefix_len+1);
+ }
+}
+
+static bool pattern_match(const std::string &candidate_str, const std::string &pattern)
+{
+ // If the pattern is empty, it matches
+ if (pattern.empty()) return true;
+
+ // 'pattern' is a glob pattern, we only accept '*' chars
+ // copy it
+ std::string expression = pattern;
+
+ // Escape perl's regexp chars with a backslash, except all "*" chars
+ prefix_with(expression, ".[{()\\+?|^$", "\\");
+ prefix_with(expression, "*", ".");
+
+ // case-insensitive matching:
+ boost::regex regexp(expression, boost::regex::perl|boost::regex::icase);
+ return boost::regex_match(candidate_str, regexp);
+}
+
+bool LLMediaEntry::checkCandidateUrl(const std::string& url) const
+{
+ if (getWhiteListEnable())
+ {
+ return checkUrlAgainstWhitelist(url, getWhiteList());
+ }
+ else
+ {
+ return true;
+ }
+}
+
+// static
+bool LLMediaEntry::checkUrlAgainstWhitelist(const std::string& url,
+ const std::vector<std::string> &whitelist)
+{
+ bool passes = true;
+ // *NOTE: no entries? Don't check
+ if (whitelist.size() > 0)
+ {
+ passes = false;
+
+ // Case insensitive: the reason why we toUpper both this and the
+ // filter
+ std::string candidate_url = url;
+ // Use lluri to see if there is a path part in the candidate URL. No path? Assume "/"
+ LLURI candidate_uri(candidate_url);
+ std::vector<std::string>::const_iterator iter = whitelist.begin();
+ std::vector<std::string>::const_iterator end = whitelist.end();
+ for ( ; iter < end; ++iter )
+ {
+ std::string filter = *iter;
+
+ LLURI filter_uri(filter);
+ bool scheme_passes = pattern_match( candidate_uri.scheme(), filter_uri.scheme() );
+ if (filter_uri.scheme().empty())
+ {
+ filter_uri = LLURI(DEFAULT_URL_PREFIX + filter);
+ }
+ bool authority_passes = pattern_match( candidate_uri.authority(), filter_uri.authority() );
+ bool path_passes = pattern_match( candidate_uri.escapedPath(), filter_uri.escapedPath() );
+
+ if (scheme_passes && authority_passes && path_passes)
+ {
+ passes = true;
+ break;
+ }
+ }
+ }
+ return passes;
+}
+
+U32 LLMediaEntry::setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit )
+{
+ if ( value.length() > limit )
+ {
+ return LSL_STATUS_BOUNDS_ERROR;
+ }
+ else
+ {
+ field = value;
+ return LSL_STATUS_OK;
+ }
+}
+
+U32 LLMediaEntry::setControls(LLMediaEntry::MediaControls controls)
+{
+ if (controls == STANDARD ||
+ controls == MINI)
+ {
+ mControls = controls;
+ return LSL_STATUS_OK;
+ }
+ return LSL_STATUS_BOUNDS_ERROR;
+}
+
+U32 LLMediaEntry::setPermsInteract( U8 val )
+{
+ mPermsInteract = val & PERM_MASK;
+ return LSL_STATUS_OK;
+}
+
+U32 LLMediaEntry::setPermsControl( U8 val )
+{
+ mPermsControl = val & PERM_MASK;
+ return LSL_STATUS_OK;
+}
+
+U32 LLMediaEntry::setCurrentURL(const std::string& current_url)
+{
+ return setCurrentURLInternal( current_url, true );
+}
+
+U32 LLMediaEntry::setCurrentURLInternal(const std::string& current_url, bool check_whitelist)
+{
+ if ( ! check_whitelist || checkCandidateUrl(current_url))
+ {
+ return setStringFieldWithLimit( mCurrentURL, current_url, MAX_URL_LENGTH );
+ }
+ else
+ {
+ return LSL_STATUS_WHITELIST_FAILED;
+ }
+}
+
+U32 LLMediaEntry::setHomeURL(const std::string& home_url)
+{
+ return setStringFieldWithLimit( mHomeURL, home_url, MAX_URL_LENGTH );
+}
+
+U32 LLMediaEntry::setWidthPixels(U16 width)
+{
+ if (width > MAX_WIDTH_PIXELS) return LSL_STATUS_BOUNDS_ERROR;
+ mWidthPixels = width;
+ return LSL_STATUS_OK;
+}
+
+U32 LLMediaEntry::setHeightPixels(U16 height)
+{
+ if (height > MAX_HEIGHT_PIXELS) return LSL_STATUS_BOUNDS_ERROR;
+ mHeightPixels = height;
+ return LSL_STATUS_OK;
+}
+
+const LLUUID &LLMediaEntry::getMediaID() const
+{
+ // Lazily generate media ID
+ if (NULL == mMediaIDp)
+ {
+ mMediaIDp = new LLUUID();
+ mMediaIDp->generate();
+ }
+ return *mMediaIDp;
+}
+