aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcharacter/llgesture.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcharacter/llgesture.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llcharacter/llgesture.cpp')
-rw-r--r--linden/indra/llcharacter/llgesture.cpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/linden/indra/llcharacter/llgesture.cpp b/linden/indra/llcharacter/llgesture.cpp
new file mode 100644
index 0000000..944df78
--- /dev/null
+++ b/linden/indra/llcharacter/llgesture.cpp
@@ -0,0 +1,375 @@
1/**
2 * @file llgesture.cpp
3 *
4 * Copyright (c) 2002-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28
29#include "indra_constants.h"
30
31#include "llgesture.h"
32#include "llendianswizzle.h"
33#include "message.h"
34#include <boost/tokenizer.hpp>
35
36// for allocating serialization buffers - these need to be updated when members change
37const S32 LLGestureList::SERIAL_HEADER_SIZE = sizeof(S32);
38const S32 LLGesture::MAX_SERIAL_SIZE = sizeof(KEY) + sizeof(MASK) + 16 + 26 + 41 + 41;
39
40LLGesture::LLGesture()
41: mKey(KEY_NONE),
42 mMask(MASK_NONE),
43 mTrigger(),
44 mTriggerLower(),
45 mSoundItemID(),
46 mAnimation(),
47 mOutputString()
48{ }
49
50LLGesture::LLGesture(KEY key, MASK mask, const std::string &trigger,
51 const LLUUID &sound_item_id,
52 const std::string &animation,
53 const std::string &output_string)
54:
55 mKey(key),
56 mMask(mask),
57 mTrigger(trigger),
58 mTriggerLower(trigger),
59 mSoundItemID(sound_item_id),
60 mAnimation(animation),
61 mOutputString(output_string)
62{
63 mTriggerLower = utf8str_tolower(mTriggerLower);
64}
65
66LLGesture::LLGesture(U8 **buffer, S32 max_size)
67{
68 *buffer = deserialize(*buffer, max_size);
69}
70
71LLGesture::LLGesture(const LLGesture &rhs)
72{
73 mKey = rhs.mKey;
74 mMask = rhs.mMask;
75 mTrigger = rhs.mTrigger;
76 mTriggerLower = rhs.mTriggerLower;
77 mSoundItemID = rhs.mSoundItemID;
78 mAnimation = rhs.mAnimation;
79 mOutputString = rhs.mOutputString;
80}
81
82const LLGesture &LLGesture::operator =(const LLGesture &rhs)
83{
84 mKey = rhs.mKey;
85 mMask = rhs.mMask;
86 mTrigger = rhs.mTrigger;
87 mTriggerLower = rhs.mTriggerLower;
88 mSoundItemID = rhs.mSoundItemID;
89 mAnimation = rhs.mAnimation;
90 mOutputString = rhs.mOutputString;
91 return (*this);
92}
93
94
95BOOL LLGesture::trigger(KEY key, MASK mask)
96{
97 llwarns << "Parent class trigger called: you probably didn't mean this." << llendl;
98 return FALSE;
99}
100
101
102BOOL LLGesture::trigger(const LLString &trigger_string)
103{
104 llwarns << "Parent class trigger called: you probably didn't mean this." << llendl;
105 return FALSE;
106}
107
108// NOT endian-neutral
109U8 *LLGesture::serialize(U8 *buffer) const
110{
111 htonmemcpy(buffer, &mKey, MVT_S8, 1);
112 buffer += sizeof(mKey);
113 htonmemcpy(buffer, &mMask, MVT_U32, 4);
114 buffer += sizeof(mMask);
115 htonmemcpy(buffer, mSoundItemID.mData, MVT_LLUUID, 16);
116 buffer += 16;
117
118 memcpy(buffer, mTrigger.c_str(), mTrigger.length() + 1); /* Flawfinder: ignore */
119 buffer += mTrigger.length() + 1;
120 memcpy(buffer, mAnimation.c_str(), mAnimation.length() + 1); /* Flawfinder: ignore */
121 buffer += mAnimation.length() + 1;
122 memcpy(buffer, mOutputString.c_str(), mOutputString.length() + 1); /* Flawfinder: ignore */
123 buffer += mOutputString.length() + 1;
124
125 return buffer;
126}
127
128U8 *LLGesture::deserialize(U8 *buffer, S32 max_size)
129{
130 U8 *tmp = buffer;
131
132 if (tmp + sizeof(mKey) + sizeof(mMask) + 16 > buffer + max_size)
133 {
134 llwarns << "Attempt to read past end of buffer, bad data!!!!" << llendl;
135 return buffer;
136 }
137
138 htonmemcpy(&mKey, tmp, MVT_S8, 1);
139 tmp += sizeof(mKey);
140 htonmemcpy(&mMask, tmp, MVT_U32, 4);
141 tmp += sizeof(mMask);
142 htonmemcpy(mSoundItemID.mData, tmp, MVT_LLUUID, 16);
143 tmp += 16;
144
145 mTrigger.assign((char *)tmp);
146 mTriggerLower = mTrigger;
147 mTriggerLower = utf8str_tolower(mTriggerLower);
148 tmp += mTrigger.length() + 1;
149 mAnimation.assign((char *)tmp);
150 //RN: force animation names to lower case
151 // must do this for backwards compatibility
152 mAnimation = utf8str_tolower(mAnimation);
153 tmp += mAnimation.length() + 1;
154 mOutputString.assign((char *)tmp);
155 tmp += mOutputString.length() + 1;
156
157 if (tmp > buffer + max_size)
158 {
159 llwarns << "Read past end of buffer, bad data!!!!" << llendl;
160 return tmp;
161 }
162
163 return tmp;
164}
165
166S32 LLGesture::getMaxSerialSize()
167{
168 return MAX_SERIAL_SIZE;
169}
170
171//---------------------------------------------------------------------
172// LLGestureList
173//---------------------------------------------------------------------
174
175LLGestureList::LLGestureList()
176: mList(0)
177{
178 // add some gestures for debugging
179// LLGesture *gesture = NULL;
180/*
181 gesture = new LLGesture(KEY_F2, MASK_NONE, ":-)",
182 SND_CHIRP, "dance2", ":-)" );
183 mList.put(gesture);
184
185 gesture = new LLGesture(KEY_F3, MASK_NONE, "/dance",
186 SND_OBJECT_CREATE, "dance3", "(dances)" );
187 mList.put(gesture);
188
189 gesture = new LLGesture(KEY_F4, MASK_NONE, "/boogie",
190 LLUUID::null, "dance4", LLString::null );
191 mList.put(gesture);
192
193 gesture = new LLGesture(KEY_F5, MASK_SHIFT, "/tongue",
194 LLUUID::null, "Express_Tongue_Out", LLString::null );
195 mList.put(gesture);
196 */
197}
198
199LLGestureList::~LLGestureList()
200{
201 deleteAll();
202}
203
204
205void LLGestureList::deleteAll()
206{
207 S32 count = mList.count();
208 for (S32 i = 0; i < count; i++)
209 {
210 delete mList.get(i);
211 }
212 mList.reset();
213}
214
215// Iterates through space delimited tokens in string, triggering any gestures found.
216// Generates a revised string that has the found tokens replaced by their replacement strings
217// and (as a minor side effect) has multiple spaces in a row replaced by single spaces.
218BOOL LLGestureList::triggerAndReviseString(const LLString &string, LLString* revised_string)
219{
220 LLString tokenized = string;
221
222 BOOL found_gestures = FALSE;
223 BOOL first_token = TRUE;
224
225 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
226 boost::char_separator<char> sep(" ");
227 tokenizer tokens(string, sep);
228 tokenizer::iterator token_iter;
229
230 for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
231 {
232 LLGesture* gesture = NULL;
233
234 if( !found_gestures ) // Only pay attention to the first gesture in the string.
235 {
236 LLString cur_token_lower = *token_iter;
237 LLString::toLower(cur_token_lower);
238
239 for (S32 i = 0; i < mList.count(); i++)
240 {
241 gesture = mList.get(i);
242 if (gesture->trigger(cur_token_lower))
243 {
244 if( !gesture->getOutputString().empty() )
245 {
246 if( !first_token )
247 {
248 revised_string->append( " " );
249 }
250
251 // Don't muck with the user's capitalization if we don't have to.
252 const std::string& output = gesture->getOutputString();
253 LLString output_lower = LLString(output.c_str());
254 LLString::toLower(output_lower);
255 if( cur_token_lower == output_lower )
256 {
257 revised_string->append(*token_iter);
258 }
259 else
260 {
261 revised_string->append(output.c_str());
262 }
263
264 }
265 found_gestures = TRUE;
266 break;
267 }
268 gesture = NULL;
269 }
270 }
271
272 if( !gesture )
273 {
274 if( !first_token )
275 {
276 revised_string->append( " " );
277 }
278 revised_string->append( *token_iter );
279 }
280
281 first_token = FALSE;
282 }
283 return found_gestures;
284}
285
286
287
288BOOL LLGestureList::trigger(KEY key, MASK mask)
289{
290 for (S32 i = 0; i < mList.count(); i++)
291 {
292 LLGesture* gesture = mList.get(i);
293 if( gesture )
294 {
295 if (gesture->trigger(key, mask))
296 {
297 return TRUE;
298 }
299 }
300 else
301 {
302 llwarns << "NULL gesture in gesture list (" << i << ")" << llendl
303 }
304 }
305 return FALSE;
306}
307
308// NOT endian-neutral
309U8 *LLGestureList::serialize(U8 *buffer) const
310{
311 // a single S32 serves as the header that tells us how many to read
312 S32 count = mList.count();
313 htonmemcpy(buffer, &count, MVT_S32, 4);
314 buffer += sizeof(count);
315
316 for (S32 i = 0; i < count; i++)
317 {
318 buffer = mList[i]->serialize(buffer);
319 }
320
321 return buffer;
322}
323
324const S32 MAX_GESTURES = 4096;
325
326U8 *LLGestureList::deserialize(U8 *buffer, S32 max_size)
327{
328 deleteAll();
329
330 S32 count;
331 U8 *tmp = buffer;
332
333 if (tmp + sizeof(count) > buffer + max_size)
334 {
335 llwarns << "Invalid max_size" << llendl;
336 return buffer;
337 }
338
339 htonmemcpy(&count, tmp, MVT_S32, 4);
340
341 if (count > MAX_GESTURES)
342 {
343 llwarns << "Unreasonably large gesture list count in deserialize: " << count << llendl;
344 return tmp;
345 }
346
347 tmp += sizeof(count);
348
349 mList.reserve_block(count);
350
351 for (S32 i = 0; i < count; i++)
352 {
353 mList[i] = create_gesture(&tmp, max_size - (S32)(tmp - buffer));
354 if (tmp - buffer > max_size)
355 {
356 llwarns << "Deserialization read past end of buffer, bad data!!!!" << llendl;
357 return tmp;
358 }
359 }
360
361 return tmp;
362}
363
364// this is a helper for deserialize
365// it gets overridden by LLViewerGestureList to create LLViewerGestures
366// overridden by child class to use local LLGesture implementation
367LLGesture *LLGestureList::create_gesture(U8 **buffer, S32 max_size)
368{
369 return new LLGesture(buffer, max_size);
370}
371
372S32 LLGestureList::getMaxSerialSize()
373{
374 return SERIAL_HEADER_SIZE + (count() * LLGesture::getMaxSerialSize());
375}