llgesture.cpp

Go to the documentation of this file.
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 // for allocating serialization buffers - these need to be updated when members change
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 // NOT endian-neutral
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);                /* Flawfinder: ignore */
00123         buffer += mTrigger.length() + 1;
00124         memcpy(buffer, mAnimation.c_str(), mAnimation.length() + 1);            /* Flawfinder: ignore */
00125         buffer += mAnimation.length() + 1;
00126         memcpy(buffer, mOutputString.c_str(), mOutputString.length() + 1);              /* Flawfinder: ignore */
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         //RN: force animation names to lower case
00155         // must do this for backwards compatibility
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 // LLGestureList
00177 //---------------------------------------------------------------------
00178 
00179 LLGestureList::LLGestureList()
00180 :       mList(0)
00181 {
00182         // add some gestures for debugging
00183 //      LLGesture *gesture = NULL;
00184 /*
00185         gesture = new LLGesture(KEY_F2, MASK_NONE, ":-)", 
00186                 SND_CHIRP, "dance2", ":-)" );
00187         mList.put(gesture);
00188 
00189         gesture = new LLGesture(KEY_F3, MASK_NONE, "/dance", 
00190                 SND_OBJECT_CREATE, "dance3", "(dances)" );
00191         mList.put(gesture);
00192 
00193         gesture = new LLGesture(KEY_F4, MASK_NONE, "/boogie", 
00194                 LLUUID::null, "dance4", LLString::null );
00195         mList.put(gesture);
00196 
00197         gesture = new LLGesture(KEY_F5, MASK_SHIFT, "/tongue", 
00198                 LLUUID::null, "Express_Tongue_Out", LLString::null );
00199         mList.put(gesture);
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 // Iterates through space delimited tokens in string, triggering any gestures found.
00220 // Generates a revised string that has the found tokens replaced by their replacement strings
00221 // and (as a minor side effect) has multiple spaces in a row replaced by single spaces.
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 ) // Only pay attention to the first gesture in the string.
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                                                 // Don't muck with the user's capitalization if we don't have to.
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 // NOT endian-neutral
00313 U8 *LLGestureList::serialize(U8 *buffer) const
00314 {
00315         // a single S32 serves as the header that tells us how many to read
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 // this is a helper for deserialize
00369 // it gets overridden by LLViewerGestureList to create LLViewerGestures
00370 // overridden by child class to use local LLGesture implementation
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 }

Generated on Thu Jul 1 06:08:39 2010 for Second Life Viewer by  doxygen 1.4.7