aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llprimitive/llmediaentry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llprimitive/llmediaentry.cpp')
-rwxr-xr-xlinden/indra/llprimitive/llmediaentry.cpp602
1 files changed, 602 insertions, 0 deletions
diff --git a/linden/indra/llprimitive/llmediaentry.cpp b/linden/indra/llprimitive/llmediaentry.cpp
new file mode 100755
index 0000000..e4b31e2
--- /dev/null
+++ b/linden/indra/llprimitive/llmediaentry.cpp
@@ -0,0 +1,602 @@
1/**
2 * @file llmediaentry.cpp
3 * @brief This is a single instance of media data related to the face of a prim
4 *
5 * $LicenseInfo:firstyear=2001&license=viewergpl$
6 *
7 * Copyright (c) 2001-2010, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "linden_common.h"
34#include "llmediaentry.h"
35#include "lllslconstants.h"
36
37#include <boost/regex.hpp>
38
39// LLSD key defines
40// DO NOT REORDER OR REMOVE THESE!
41
42// Some LLSD keys. Do not change!
43#define MEDIA_ALT_IMAGE_ENABLE_KEY_STR "alt_image_enable"
44#define MEDIA_CONTROLS_KEY_STR "controls"
45#define MEDIA_CURRENT_URL_KEY_STR "current_url"
46#define MEDIA_HOME_URL_KEY_STR "home_url"
47#define MEDIA_AUTO_LOOP_KEY_STR "auto_loop"
48#define MEDIA_AUTO_PLAY_KEY_STR "auto_play"
49#define MEDIA_AUTO_SCALE_KEY_STR "auto_scale"
50#define MEDIA_AUTO_ZOOM_KEY_STR "auto_zoom"
51#define MEDIA_FIRST_CLICK_INTERACT_KEY_STR "first_click_interact"
52#define MEDIA_WIDTH_PIXELS_KEY_STR "width_pixels"
53#define MEDIA_HEIGHT_PIXELS_KEY_STR "height_pixels"
54
55// "security" fields
56#define MEDIA_WHITELIST_ENABLE_KEY_STR "whitelist_enable"
57#define MEDIA_WHITELIST_KEY_STR "whitelist"
58
59// "permissions" fields
60#define MEDIA_PERMS_INTERACT_KEY_STR "perms_interact"
61#define MEDIA_PERMS_CONTROL_KEY_STR "perms_control"
62
63// "general" fields
64const char* LLMediaEntry::ALT_IMAGE_ENABLE_KEY = MEDIA_ALT_IMAGE_ENABLE_KEY_STR;
65const char* LLMediaEntry::CONTROLS_KEY = MEDIA_CONTROLS_KEY_STR;
66const char* LLMediaEntry::CURRENT_URL_KEY = MEDIA_CURRENT_URL_KEY_STR;
67const char* LLMediaEntry::HOME_URL_KEY = MEDIA_HOME_URL_KEY_STR;
68const char* LLMediaEntry::AUTO_LOOP_KEY = MEDIA_AUTO_LOOP_KEY_STR;
69const char* LLMediaEntry::AUTO_PLAY_KEY = MEDIA_AUTO_PLAY_KEY_STR;
70const char* LLMediaEntry::AUTO_SCALE_KEY = MEDIA_AUTO_SCALE_KEY_STR;
71const char* LLMediaEntry::AUTO_ZOOM_KEY = MEDIA_AUTO_ZOOM_KEY_STR;
72const char* LLMediaEntry::FIRST_CLICK_INTERACT_KEY = MEDIA_FIRST_CLICK_INTERACT_KEY_STR;
73const char* LLMediaEntry::WIDTH_PIXELS_KEY = MEDIA_WIDTH_PIXELS_KEY_STR;
74const char* LLMediaEntry::HEIGHT_PIXELS_KEY = MEDIA_HEIGHT_PIXELS_KEY_STR;
75
76// "security" fields
77const char* LLMediaEntry::WHITELIST_ENABLE_KEY = MEDIA_WHITELIST_ENABLE_KEY_STR;
78const char* LLMediaEntry::WHITELIST_KEY = MEDIA_WHITELIST_KEY_STR;
79
80// "permissions" fields
81const char* LLMediaEntry::PERMS_INTERACT_KEY = MEDIA_PERMS_INTERACT_KEY_STR;
82const char* LLMediaEntry::PERMS_CONTROL_KEY = MEDIA_PERMS_CONTROL_KEY_STR;
83
84#define DEFAULT_URL_PREFIX "http://"
85
86// Constructor(s)
87LLMediaEntry::LLMediaEntry() :
88 mAltImageEnable(false),
89 mControls(STANDARD),
90 mCurrentURL(""),
91 mHomeURL(""),
92 mAutoLoop(false),
93 mAutoPlay(false),
94 mAutoScale(false),
95 mAutoZoom(false),
96 mFirstClickInteract(false),
97 mWidthPixels(0),
98 mHeightPixels(0),
99 mWhiteListEnable(false),
100 // mWhiteList
101 mPermsInteract(PERM_ALL),
102 mPermsControl(PERM_ALL),
103 mMediaIDp(NULL)
104{
105}
106
107LLMediaEntry::LLMediaEntry(const LLMediaEntry &rhs) :
108 mMediaIDp(NULL)
109{
110 // "general" fields
111 mAltImageEnable = rhs.mAltImageEnable;
112 mControls = rhs.mControls;
113 mCurrentURL = rhs.mCurrentURL;
114 mHomeURL = rhs.mHomeURL;
115 mAutoLoop = rhs.mAutoLoop;
116 mAutoPlay = rhs.mAutoPlay;
117 mAutoScale = rhs.mAutoScale;
118 mAutoZoom = rhs.mAutoZoom;
119 mFirstClickInteract = rhs.mFirstClickInteract;
120 mWidthPixels = rhs.mWidthPixels;
121 mHeightPixels = rhs.mHeightPixels;
122
123 // "security" fields
124 mWhiteListEnable = rhs.mWhiteListEnable;
125 mWhiteList = rhs.mWhiteList;
126
127 // "permissions" fields
128 mPermsInteract = rhs.mPermsInteract;
129 mPermsControl = rhs.mPermsControl;
130}
131
132LLMediaEntry::~LLMediaEntry()
133{
134 if (NULL != mMediaIDp)
135 {
136 delete mMediaIDp;
137 }
138}
139
140LLSD LLMediaEntry::asLLSD() const
141{
142 LLSD sd;
143 asLLSD(sd);
144 return sd;
145}
146
147//
148// LLSD functions
149//
150void LLMediaEntry::asLLSD(LLSD& sd) const
151{
152 // "general" fields
153 sd[ALT_IMAGE_ENABLE_KEY] = mAltImageEnable;
154 sd[CONTROLS_KEY] = (LLSD::Integer)mControls;
155 sd[CURRENT_URL_KEY] = mCurrentURL;
156 sd[HOME_URL_KEY] = mHomeURL;
157 sd[AUTO_LOOP_KEY] = mAutoLoop;
158 sd[AUTO_PLAY_KEY] = mAutoPlay;
159 sd[AUTO_SCALE_KEY] = mAutoScale;
160 sd[AUTO_ZOOM_KEY] = mAutoZoom;
161 sd[FIRST_CLICK_INTERACT_KEY] = mFirstClickInteract;
162 sd[WIDTH_PIXELS_KEY] = mWidthPixels;
163 sd[HEIGHT_PIXELS_KEY] = mHeightPixels;
164
165 // "security" fields
166 sd[WHITELIST_ENABLE_KEY] = mWhiteListEnable;
167 sd.erase(WHITELIST_KEY);
168 for (U32 i=0; i<mWhiteList.size(); i++)
169 {
170 sd[WHITELIST_KEY].append(mWhiteList[i]);
171 }
172
173 // "permissions" fields
174 sd[PERMS_INTERACT_KEY] = mPermsInteract;
175 sd[PERMS_CONTROL_KEY] = mPermsControl;
176}
177
178// static
179bool LLMediaEntry::checkLLSD(const LLSD& sd)
180{
181 if (sd.isUndefined()) return true;
182 LLMediaEntry temp;
183 return temp.fromLLSDInternal(sd, true);
184}
185
186void LLMediaEntry::fromLLSD(const LLSD& sd)
187{
188 (void)fromLLSDInternal(sd, true);
189}
190
191void LLMediaEntry::mergeFromLLSD(const LLSD& sd)
192{
193 (void)fromLLSDInternal(sd, false);
194}
195
196// *NOTE: returns true if NO failures to set occurred, false otherwise.
197// However, be aware that if a failure to set does occur, it does
198// not stop setting fields from the LLSD!
199bool LLMediaEntry::fromLLSDInternal(const LLSD& sd, bool overwrite)
200{
201 // *HACK: we sort of cheat here and assume that status is a
202 // bit field. We "or" into status and instead of returning
203 // it, we return whether it finishes off as LSL_STATUS_OK or not.
204 U32 status = LSL_STATUS_OK;
205
206 // "general" fields
207 if ( overwrite || sd.has(ALT_IMAGE_ENABLE_KEY) )
208 {
209 status |= setAltImageEnable( sd[ALT_IMAGE_ENABLE_KEY] );
210 }
211 if ( overwrite || sd.has(CONTROLS_KEY) )
212 {
213 status |= setControls( (MediaControls)(LLSD::Integer)sd[CONTROLS_KEY] );
214 }
215 if ( overwrite || sd.has(CURRENT_URL_KEY) )
216 {
217 // Don't check whitelist
218 status |= setCurrentURLInternal( sd[CURRENT_URL_KEY], false );
219 }
220 if ( overwrite || sd.has(HOME_URL_KEY) )
221 {
222 status |= setHomeURL( sd[HOME_URL_KEY] );
223 }
224 if ( overwrite || sd.has(AUTO_LOOP_KEY) )
225 {
226 status |= setAutoLoop( sd[AUTO_LOOP_KEY] );
227 }
228 if ( overwrite || sd.has(AUTO_PLAY_KEY) )
229 {
230 status |= setAutoPlay( sd[AUTO_PLAY_KEY] );
231 }
232 if ( overwrite || sd.has(AUTO_SCALE_KEY) )
233 {
234 status |= setAutoScale( sd[AUTO_SCALE_KEY] );
235 }
236 if ( overwrite || sd.has(AUTO_ZOOM_KEY) )
237 {
238 status |= setAutoZoom( sd[AUTO_ZOOM_KEY] );
239 }
240 if ( overwrite || sd.has(FIRST_CLICK_INTERACT_KEY) )
241 {
242 status |= setFirstClickInteract( sd[FIRST_CLICK_INTERACT_KEY] );
243 }
244 if ( overwrite || sd.has(WIDTH_PIXELS_KEY) )
245 {
246 status |= setWidthPixels( (LLSD::Integer)sd[WIDTH_PIXELS_KEY] );
247 }
248 if ( overwrite || sd.has(HEIGHT_PIXELS_KEY) )
249 {
250 status |= setHeightPixels( (LLSD::Integer)sd[HEIGHT_PIXELS_KEY] );
251 }
252
253 // "security" fields
254 if ( overwrite || sd.has(WHITELIST_ENABLE_KEY) )
255 {
256 status |= setWhiteListEnable( sd[WHITELIST_ENABLE_KEY] );
257 }
258 if ( overwrite || sd.has(WHITELIST_KEY) )
259 {
260 status |= setWhiteList( sd[WHITELIST_KEY] );
261 }
262
263 // "permissions" fields
264 if ( overwrite || sd.has(PERMS_INTERACT_KEY) )
265 {
266 status |= setPermsInteract( 0xff & (LLSD::Integer)sd[PERMS_INTERACT_KEY] );
267 }
268 if ( overwrite || sd.has(PERMS_CONTROL_KEY) )
269 {
270 status |= setPermsControl( 0xff & (LLSD::Integer)sd[PERMS_CONTROL_KEY] );
271 }
272
273 return LSL_STATUS_OK == status;
274}
275
276LLMediaEntry& LLMediaEntry::operator=(const LLMediaEntry &rhs)
277{
278 if (this != &rhs)
279 {
280 // "general" fields
281 mAltImageEnable = rhs.mAltImageEnable;
282 mControls = rhs.mControls;
283 mCurrentURL = rhs.mCurrentURL;
284 mHomeURL = rhs.mHomeURL;
285 mAutoLoop = rhs.mAutoLoop;
286 mAutoPlay = rhs.mAutoPlay;
287 mAutoScale = rhs.mAutoScale;
288 mAutoZoom = rhs.mAutoZoom;
289 mFirstClickInteract = rhs.mFirstClickInteract;
290 mWidthPixels = rhs.mWidthPixels;
291 mHeightPixels = rhs.mHeightPixels;
292
293 // "security" fields
294 mWhiteListEnable = rhs.mWhiteListEnable;
295 mWhiteList = rhs.mWhiteList;
296
297 // "permissions" fields
298 mPermsInteract = rhs.mPermsInteract;
299 mPermsControl = rhs.mPermsControl;
300 }
301
302 return *this;
303}
304
305bool LLMediaEntry::operator==(const LLMediaEntry &rhs) const
306{
307 return (
308 // "general" fields
309 mAltImageEnable == rhs.mAltImageEnable &&
310 mControls == rhs.mControls &&
311 mCurrentURL == rhs.mCurrentURL &&
312 mHomeURL == rhs.mHomeURL &&
313 mAutoLoop == rhs.mAutoLoop &&
314 mAutoPlay == rhs.mAutoPlay &&
315 mAutoScale == rhs.mAutoScale &&
316 mAutoZoom == rhs.mAutoZoom &&
317 mFirstClickInteract == rhs.mFirstClickInteract &&
318 mWidthPixels == rhs.mWidthPixels &&
319 mHeightPixels == rhs.mHeightPixels &&
320
321 // "security" fields
322 mWhiteListEnable == rhs.mWhiteListEnable &&
323 mWhiteList == rhs.mWhiteList &&
324
325 // "permissions" fields
326 mPermsInteract == rhs.mPermsInteract &&
327 mPermsControl == rhs.mPermsControl
328
329 );
330}
331
332bool LLMediaEntry::operator!=(const LLMediaEntry &rhs) const
333{
334 return (
335 // "general" fields
336 mAltImageEnable != rhs.mAltImageEnable ||
337 mControls != rhs.mControls ||
338 mCurrentURL != rhs.mCurrentURL ||
339 mHomeURL != rhs.mHomeURL ||
340 mAutoLoop != rhs.mAutoLoop ||
341 mAutoPlay != rhs.mAutoPlay ||
342 mAutoScale != rhs.mAutoScale ||
343 mAutoZoom != rhs.mAutoZoom ||
344 mFirstClickInteract != rhs.mFirstClickInteract ||
345 mWidthPixels != rhs.mWidthPixels ||
346 mHeightPixels != rhs.mHeightPixels ||
347
348 // "security" fields
349 mWhiteListEnable != rhs.mWhiteListEnable ||
350 mWhiteList != rhs.mWhiteList ||
351
352 // "permissions" fields
353 mPermsInteract != rhs.mPermsInteract ||
354 mPermsControl != rhs.mPermsControl
355
356 );
357}
358
359U32 LLMediaEntry::setWhiteList( const std::vector<std::string> &whitelist )
360{
361 // *NOTE: This code is VERY similar to the setWhitelist below.
362 // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER!
363 U32 size = 0;
364 U32 count = 0;
365 // First count to make sure the size constraint is not violated
366 std::vector<std::string>::const_iterator iter = whitelist.begin();
367 std::vector<std::string>::const_iterator end = whitelist.end();
368 for ( ; iter < end; ++iter)
369 {
370 const std::string &entry = (*iter);
371 size += entry.length() + 1; // Include one for \0
372 count ++;
373 if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT)
374 {
375 return LSL_STATUS_BOUNDS_ERROR;
376 }
377 }
378 // Next clear the vector
379 mWhiteList.clear();
380 // Then re-iterate and copy entries
381 iter = whitelist.begin();
382 for ( ; iter < end; ++iter)
383 {
384 const std::string &entry = (*iter);
385 mWhiteList.push_back(entry);
386 }
387 return LSL_STATUS_OK;
388}
389
390U32 LLMediaEntry::setWhiteList( const LLSD &whitelist )
391{
392 // If whitelist is undef, the whitelist is cleared
393 if (whitelist.isUndefined())
394 {
395 mWhiteList.clear();
396 return LSL_STATUS_OK;
397 }
398
399 // However, if the whitelist is an empty array, erase it.
400 if (whitelist.isArray())
401 {
402 // *NOTE: This code is VERY similar to the setWhitelist above.
403 // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER!
404 U32 size = 0;
405 U32 count = 0;
406 // First check to make sure the size and count constraints are not violated
407 LLSD::array_const_iterator iter = whitelist.beginArray();
408 LLSD::array_const_iterator end = whitelist.endArray();
409 for ( ; iter < end; ++iter)
410 {
411 const std::string &entry = (*iter).asString();
412 size += entry.length() + 1; // Include one for \0
413 count ++;
414 if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT)
415 {
416 return LSL_STATUS_BOUNDS_ERROR;
417 }
418 }
419 // Next clear the vector
420 mWhiteList.clear();
421 // Then re-iterate and copy entries
422 iter = whitelist.beginArray();
423 for ( ; iter < end; ++iter)
424 {
425 const std::string &entry = (*iter).asString();
426 mWhiteList.push_back(entry);
427 }
428 return LSL_STATUS_OK;
429 }
430 else
431 {
432 return LSL_STATUS_MALFORMED_PARAMS;
433 }
434}
435
436
437static void prefix_with(std::string &str, const char *chars, const char *prefix)
438{
439 // Given string 'str', prefix all instances of any character in 'chars'
440 // with 'prefix'
441 size_t found = str.find_first_of(chars);
442 size_t prefix_len = strlen(prefix);
443 while (found != std::string::npos)
444 {
445 str.insert(found, prefix, prefix_len);
446 found = str.find_first_of(chars, found+prefix_len+1);
447 }
448}
449
450static bool pattern_match(const std::string &candidate_str, const std::string &pattern)
451{
452 // If the pattern is empty, it matches
453 if (pattern.empty()) return true;
454
455 // 'pattern' is a glob pattern, we only accept '*' chars
456 // copy it
457 std::string expression = pattern;
458
459 // Escape perl's regexp chars with a backslash, except all "*" chars
460 prefix_with(expression, ".[{()\\+?|^$", "\\");
461 prefix_with(expression, "*", ".");
462
463 // case-insensitive matching:
464 boost::regex regexp(expression, boost::regex::perl|boost::regex::icase);
465 return boost::regex_match(candidate_str, regexp);
466}
467
468bool LLMediaEntry::checkCandidateUrl(const std::string& url) const
469{
470 if (getWhiteListEnable())
471 {
472 return checkUrlAgainstWhitelist(url, getWhiteList());
473 }
474 else
475 {
476 return true;
477 }
478}
479
480// static
481bool LLMediaEntry::checkUrlAgainstWhitelist(const std::string& url,
482 const std::vector<std::string> &whitelist)
483{
484 bool passes = true;
485 // *NOTE: no entries? Don't check
486 if (whitelist.size() > 0)
487 {
488 passes = false;
489
490 // Case insensitive: the reason why we toUpper both this and the
491 // filter
492 std::string candidate_url = url;
493 // Use lluri to see if there is a path part in the candidate URL. No path? Assume "/"
494 LLURI candidate_uri(candidate_url);
495 std::vector<std::string>::const_iterator iter = whitelist.begin();
496 std::vector<std::string>::const_iterator end = whitelist.end();
497 for ( ; iter < end; ++iter )
498 {
499 std::string filter = *iter;
500
501 LLURI filter_uri(filter);
502 bool scheme_passes = pattern_match( candidate_uri.scheme(), filter_uri.scheme() );
503 if (filter_uri.scheme().empty())
504 {
505 filter_uri = LLURI(DEFAULT_URL_PREFIX + filter);
506 }
507 bool authority_passes = pattern_match( candidate_uri.authority(), filter_uri.authority() );
508 bool path_passes = pattern_match( candidate_uri.escapedPath(), filter_uri.escapedPath() );
509
510 if (scheme_passes && authority_passes && path_passes)
511 {
512 passes = true;
513 break;
514 }
515 }
516 }
517 return passes;
518}
519
520U32 LLMediaEntry::setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit )
521{
522 if ( value.length() > limit )
523 {
524 return LSL_STATUS_BOUNDS_ERROR;
525 }
526 else
527 {
528 field = value;
529 return LSL_STATUS_OK;
530 }
531}
532
533U32 LLMediaEntry::setControls(LLMediaEntry::MediaControls controls)
534{
535 if (controls == STANDARD ||
536 controls == MINI)
537 {
538 mControls = controls;
539 return LSL_STATUS_OK;
540 }
541 return LSL_STATUS_BOUNDS_ERROR;
542}
543
544U32 LLMediaEntry::setPermsInteract( U8 val )
545{
546 mPermsInteract = val & PERM_MASK;
547 return LSL_STATUS_OK;
548}
549
550U32 LLMediaEntry::setPermsControl( U8 val )
551{
552 mPermsControl = val & PERM_MASK;
553 return LSL_STATUS_OK;
554}
555
556U32 LLMediaEntry::setCurrentURL(const std::string& current_url)
557{
558 return setCurrentURLInternal( current_url, true );
559}
560
561U32 LLMediaEntry::setCurrentURLInternal(const std::string& current_url, bool check_whitelist)
562{
563 if ( ! check_whitelist || checkCandidateUrl(current_url))
564 {
565 return setStringFieldWithLimit( mCurrentURL, current_url, MAX_URL_LENGTH );
566 }
567 else
568 {
569 return LSL_STATUS_WHITELIST_FAILED;
570 }
571}
572
573U32 LLMediaEntry::setHomeURL(const std::string& home_url)
574{
575 return setStringFieldWithLimit( mHomeURL, home_url, MAX_URL_LENGTH );
576}
577
578U32 LLMediaEntry::setWidthPixels(U16 width)
579{
580 if (width > MAX_WIDTH_PIXELS) return LSL_STATUS_BOUNDS_ERROR;
581 mWidthPixels = width;
582 return LSL_STATUS_OK;
583}
584
585U32 LLMediaEntry::setHeightPixels(U16 height)
586{
587 if (height > MAX_HEIGHT_PIXELS) return LSL_STATUS_BOUNDS_ERROR;
588 mHeightPixels = height;
589 return LSL_STATUS_OK;
590}
591
592const LLUUID &LLMediaEntry::getMediaID() const
593{
594 // Lazily generate media ID
595 if (NULL == mMediaIDp)
596 {
597 mMediaIDp = new LLUUID();
598 mMediaIDp->generate();
599 }
600 return *mMediaIDp;
601}
602