00001
00031 #include "linden_common.h"
00032
00033 #include "indra_constants.h"
00034
00035 #include "llgesture.h"
00036 #include "llendianswizzle.h"
00037 #include "message.h"
00038 #include <boost/tokenizer.hpp>
00039
00040
00041 const S32 LLGestureList::SERIAL_HEADER_SIZE = sizeof(S32);
00042 const S32 LLGesture::MAX_SERIAL_SIZE = sizeof(KEY) + sizeof(MASK) + 16 + 26 + 41 + 41;
00043
00044 LLGesture::LLGesture()
00045 : mKey(KEY_NONE),
00046 mMask(MASK_NONE),
00047 mTrigger(),
00048 mTriggerLower(),
00049 mSoundItemID(),
00050 mAnimation(),
00051 mOutputString()
00052 { }
00053
00054 LLGesture::LLGesture(KEY key, MASK mask, const std::string &trigger,
00055 const LLUUID &sound_item_id,
00056 const std::string &animation,
00057 const std::string &output_string)
00058 :
00059 mKey(key),
00060 mMask(mask),
00061 mTrigger(trigger),
00062 mTriggerLower(trigger),
00063 mSoundItemID(sound_item_id),
00064 mAnimation(animation),
00065 mOutputString(output_string)
00066 {
00067 mTriggerLower = utf8str_tolower(mTriggerLower);
00068 }
00069
00070 LLGesture::LLGesture(U8 **buffer, S32 max_size)
00071 {
00072 *buffer = deserialize(*buffer, max_size);
00073 }
00074
00075 LLGesture::LLGesture(const LLGesture &rhs)
00076 {
00077 mKey = rhs.mKey;
00078 mMask = rhs.mMask;
00079 mTrigger = rhs.mTrigger;
00080 mTriggerLower = rhs.mTriggerLower;
00081 mSoundItemID = rhs.mSoundItemID;
00082 mAnimation = rhs.mAnimation;
00083 mOutputString = rhs.mOutputString;
00084 }
00085
00086 const LLGesture &LLGesture::operator =(const LLGesture &rhs)
00087 {
00088 mKey = rhs.mKey;
00089 mMask = rhs.mMask;
00090 mTrigger = rhs.mTrigger;
00091 mTriggerLower = rhs.mTriggerLower;
00092 mSoundItemID = rhs.mSoundItemID;
00093 mAnimation = rhs.mAnimation;
00094 mOutputString = rhs.mOutputString;
00095 return (*this);
00096 }
00097
00098
00099 BOOL LLGesture::trigger(KEY key, MASK mask)
00100 {
00101 llwarns << "Parent class trigger called: you probably didn't mean this." << llendl;
00102 return FALSE;
00103 }
00104
00105
00106 BOOL LLGesture::trigger(const LLString &trigger_string)
00107 {
00108 llwarns << "Parent class trigger called: you probably didn't mean this." << llendl;
00109 return FALSE;
00110 }
00111
00112
00113 U8 *LLGesture::serialize(U8 *buffer) const
00114 {
00115 htonmemcpy(buffer, &mKey, MVT_S8, 1);
00116 buffer += sizeof(mKey);
00117 htonmemcpy(buffer, &mMask, MVT_U32, 4);
00118 buffer += sizeof(mMask);
00119 htonmemcpy(buffer, mSoundItemID.mData, MVT_LLUUID, 16);
00120 buffer += 16;
00121
00122 memcpy(buffer, mTrigger.c_str(), mTrigger.length() + 1);
00123 buffer += mTrigger.length() + 1;
00124 memcpy(buffer, mAnimation.c_str(), mAnimation.length() + 1);
00125 buffer += mAnimation.length() + 1;
00126 memcpy(buffer, mOutputString.c_str(), mOutputString.length() + 1);
00127 buffer += mOutputString.length() + 1;
00128
00129 return buffer;
00130 }
00131
00132 U8 *LLGesture::deserialize(U8 *buffer, S32 max_size)
00133 {
00134 U8 *tmp = buffer;
00135
00136 if (tmp + sizeof(mKey) + sizeof(mMask) + 16 > buffer + max_size)
00137 {
00138 llwarns << "Attempt to read past end of buffer, bad data!!!!" << llendl;
00139 return buffer;
00140 }
00141
00142 htonmemcpy(&mKey, tmp, MVT_S8, 1);
00143 tmp += sizeof(mKey);
00144 htonmemcpy(&mMask, tmp, MVT_U32, 4);
00145 tmp += sizeof(mMask);
00146 htonmemcpy(mSoundItemID.mData, tmp, MVT_LLUUID, 16);
00147 tmp += 16;
00148
00149 mTrigger.assign((char *)tmp);
00150 mTriggerLower = mTrigger;
00151 mTriggerLower = utf8str_tolower(mTriggerLower);
00152 tmp += mTrigger.length() + 1;
00153 mAnimation.assign((char *)tmp);
00154
00155
00156 mAnimation = utf8str_tolower(mAnimation);
00157 tmp += mAnimation.length() + 1;
00158 mOutputString.assign((char *)tmp);
00159 tmp += mOutputString.length() + 1;
00160
00161 if (tmp > buffer + max_size)
00162 {
00163 llwarns << "Read past end of buffer, bad data!!!!" << llendl;
00164 return tmp;
00165 }
00166
00167 return tmp;
00168 }
00169
00170 S32 LLGesture::getMaxSerialSize()
00171 {
00172 return MAX_SERIAL_SIZE;
00173 }
00174
00175
00176
00177
00178
00179 LLGestureList::LLGestureList()
00180 : mList(0)
00181 {
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 }
00202
00203 LLGestureList::~LLGestureList()
00204 {
00205 deleteAll();
00206 }
00207
00208
00209 void LLGestureList::deleteAll()
00210 {
00211 S32 count = mList.count();
00212 for (S32 i = 0; i < count; i++)
00213 {
00214 delete mList.get(i);
00215 }
00216 mList.reset();
00217 }
00218
00219
00220
00221
00222 BOOL LLGestureList::triggerAndReviseString(const LLString &string, LLString* revised_string)
00223 {
00224 LLString tokenized = string;
00225
00226 BOOL found_gestures = FALSE;
00227 BOOL first_token = TRUE;
00228
00229 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00230 boost::char_separator<char> sep(" ");
00231 tokenizer tokens(string, sep);
00232 tokenizer::iterator token_iter;
00233
00234 for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
00235 {
00236 LLGesture* gesture = NULL;
00237
00238 if( !found_gestures )
00239 {
00240 LLString cur_token_lower = *token_iter;
00241 LLString::toLower(cur_token_lower);
00242
00243 for (S32 i = 0; i < mList.count(); i++)
00244 {
00245 gesture = mList.get(i);
00246 if (gesture->trigger(cur_token_lower))
00247 {
00248 if( !gesture->getOutputString().empty() )
00249 {
00250 if( !first_token )
00251 {
00252 revised_string->append( " " );
00253 }
00254
00255
00256 const std::string& output = gesture->getOutputString();
00257 LLString output_lower = LLString(output.c_str());
00258 LLString::toLower(output_lower);
00259 if( cur_token_lower == output_lower )
00260 {
00261 revised_string->append(*token_iter);
00262 }
00263 else
00264 {
00265 revised_string->append(output.c_str());
00266 }
00267
00268 }
00269 found_gestures = TRUE;
00270 break;
00271 }
00272 gesture = NULL;
00273 }
00274 }
00275
00276 if( !gesture )
00277 {
00278 if( !first_token )
00279 {
00280 revised_string->append( " " );
00281 }
00282 revised_string->append( *token_iter );
00283 }
00284
00285 first_token = FALSE;
00286 }
00287 return found_gestures;
00288 }
00289
00290
00291
00292 BOOL LLGestureList::trigger(KEY key, MASK mask)
00293 {
00294 for (S32 i = 0; i < mList.count(); i++)
00295 {
00296 LLGesture* gesture = mList.get(i);
00297 if( gesture )
00298 {
00299 if (gesture->trigger(key, mask))
00300 {
00301 return TRUE;
00302 }
00303 }
00304 else
00305 {
00306 llwarns << "NULL gesture in gesture list (" << i << ")" << llendl
00307 }
00308 }
00309 return FALSE;
00310 }
00311
00312
00313 U8 *LLGestureList::serialize(U8 *buffer) const
00314 {
00315
00316 S32 count = mList.count();
00317 htonmemcpy(buffer, &count, MVT_S32, 4);
00318 buffer += sizeof(count);
00319
00320 for (S32 i = 0; i < count; i++)
00321 {
00322 buffer = mList[i]->serialize(buffer);
00323 }
00324
00325 return buffer;
00326 }
00327
00328 const S32 MAX_GESTURES = 4096;
00329
00330 U8 *LLGestureList::deserialize(U8 *buffer, S32 max_size)
00331 {
00332 deleteAll();
00333
00334 S32 count;
00335 U8 *tmp = buffer;
00336
00337 if (tmp + sizeof(count) > buffer + max_size)
00338 {
00339 llwarns << "Invalid max_size" << llendl;
00340 return buffer;
00341 }
00342
00343 htonmemcpy(&count, tmp, MVT_S32, 4);
00344
00345 if (count > MAX_GESTURES)
00346 {
00347 llwarns << "Unreasonably large gesture list count in deserialize: " << count << llendl;
00348 return tmp;
00349 }
00350
00351 tmp += sizeof(count);
00352
00353 mList.reserve_block(count);
00354
00355 for (S32 i = 0; i < count; i++)
00356 {
00357 mList[i] = create_gesture(&tmp, max_size - (S32)(tmp - buffer));
00358 if (tmp - buffer > max_size)
00359 {
00360 llwarns << "Deserialization read past end of buffer, bad data!!!!" << llendl;
00361 return tmp;
00362 }
00363 }
00364
00365 return tmp;
00366 }
00367
00368
00369
00370
00371 LLGesture *LLGestureList::create_gesture(U8 **buffer, S32 max_size)
00372 {
00373 return new LLGesture(buffer, max_size);
00374 }
00375
00376 S32 LLGestureList::getMaxSerialSize()
00377 {
00378 return SERIAL_HEADER_SIZE + (count() * LLGesture::getMaxSerialSize());
00379 }