llgesture.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:9k
源码类别:

游戏引擎

开发平台:

C++ Builder

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