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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file lscript_alloc.cpp
  3.  * @brief general heap management for scripting system
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-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. // #define at top of file accelerates gcc compiles
  33. // Under gcc 2.9, the manual is unclear if comments can appear above #ifndef
  34. // Under gcc 3, the manual explicitly states comments can appear above the #ifndef
  35. #include "linden_common.h"
  36. #include "lscript_alloc.h"
  37. #include "llrand.h"
  38. // supported data types
  39. // basic types
  40. // integer 4 bytes of integer data
  41. // float 4 bytes of float data
  42. // string data null terminated 1 byte string
  43. // key data null terminated 1 byte string
  44. // vector data 12 bytes of 3 floats
  45. // quaternion data 16 bytes of 4 floats
  46. // list type
  47. // list data 4 bytes of number of entries followed by pointer
  48. // string pointer 4 bytes of address of string data on the heap (only used in list data)
  49. //  key pointer 4 bytes of address of key data on the heap (only used in list data)
  50. // heap format
  51. // 
  52. // 4 byte offset to next block (in bytes)
  53. // 1 byte of type of variable or empty
  54. // 2 bytes of reference count
  55. // nn bytes of data
  56. void reset_hp_to_safe_spot(const U8 *buffer)
  57. {
  58. set_register((U8 *)buffer, LREG_HP, TOP_OF_MEMORY);
  59. }
  60. // create a heap from the HR to TM
  61. BOOL lsa_create_heap(U8 *heap_start, S32 size)
  62. {
  63. LLScriptAllocEntry entry(size, LST_NULL);
  64. S32 position = 0;
  65. alloc_entry2bytestream(heap_start, position, entry);
  66. return TRUE;
  67. }
  68. S32 lsa_heap_top(U8 *heap_start, S32 maxtop)
  69. {
  70. S32 offset = 0;
  71. LLScriptAllocEntry entry;
  72. bytestream2alloc_entry(entry, heap_start, offset);
  73. while (offset + entry.mSize < maxtop)
  74. {
  75. offset += entry.mSize;
  76. bytestream2alloc_entry(entry, heap_start, offset);
  77. }
  78. return offset + entry.mSize;
  79. }
  80. // adding to heap
  81. // if block is empty
  82. // if block is at least block size + 4 larger than data
  83. // split block
  84. // insert data into first part
  85. // return address
  86. // else
  87. // insert data into block
  88. // return address
  89. // else
  90. // if next block is >= SP 
  91. // set Stack-Heap collision
  92. // return NULL
  93. // if next block is empty
  94. // merge next block with current block
  95. // go to start of algorithm
  96. // else
  97. // move to next block
  98. // go to start of algorithm
  99. S32 lsa_heap_add_data(U8 *buffer, LLScriptLibData *data, S32 heapsize, BOOL b_delete)
  100. {
  101. if (get_register(buffer, LREG_FR))
  102. return 1;
  103. LLScriptAllocEntry entry, nextentry;
  104. S32 hr = get_register(buffer, LREG_HR);
  105. S32 hp = get_register(buffer, LREG_HP);
  106. S32 current_offset, next_offset, offset = hr;
  107. S32 size = 0;
  108. switch(data->mType)
  109. {
  110. case LST_INTEGER:
  111. size = 4;
  112. break;
  113. case LST_FLOATINGPOINT:
  114. size = 4;
  115. break;
  116. case LST_KEY:
  117.         // NOTE: babbage: defensive as some library calls set data to NULL
  118.         size = data->mKey ? (S32)strlen(data->mKey) + 1 : 1; /*Flawfinder: ignore*/
  119. break;
  120. case LST_STRING:
  121.                 // NOTE: babbage: defensive as some library calls set data to NULL
  122.              size = data->mString ? (S32)strlen(data->mString) + 1 : 1; /*Flawfinder: ignore*/
  123. break;
  124. case LST_LIST:
  125. // list data 4 bytes of number of entries followed by number of pointer
  126. size = 4 + 4*data->getListLength();
  127. if (data->checkForMultipleLists())
  128. {
  129. set_fault(buffer, LSRF_NESTING_LISTS);
  130. }
  131. break;
  132. case LST_VECTOR:
  133. size = 12;
  134. break;
  135. case LST_QUATERNION:
  136. size = 16;
  137. break;
  138. default:
  139. break;
  140. }
  141. current_offset = offset;
  142. bytestream2alloc_entry(entry, buffer, offset);
  143. do
  144. {
  145. hp = get_register(buffer, LREG_HP);
  146. if (!entry.mType)
  147. {
  148. if (entry.mSize >= size + SIZEOF_SCRIPT_ALLOC_ENTRY + 4)
  149. {
  150. offset = current_offset;
  151. lsa_split_block(buffer, offset, size, entry);
  152. entry.mType = data->mType;
  153. entry.mSize = size;
  154. entry.mReferenceCount = 1;
  155. offset = current_offset;
  156. alloc_entry2bytestream(buffer, offset, entry);
  157. lsa_insert_data(buffer, offset, data, entry, heapsize);
  158. hp = get_register(buffer, LREG_HP);
  159. S32 new_hp = current_offset + size + 2*SIZEOF_SCRIPT_ALLOC_ENTRY;
  160. if (new_hp >= hr + heapsize)
  161. {
  162. break;
  163. }
  164. if (new_hp > hp)
  165. {
  166. set_register(buffer, LREG_HP, new_hp);
  167. hp = get_register(buffer, LREG_HP);
  168. }
  169. if (b_delete)
  170. delete data;
  171. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  172. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  173. if (current_offset <= hp)
  174. return current_offset - hr + 1;
  175. else
  176. return hp - hr + 1;
  177. }
  178. else if (entry.mSize >= size)
  179. {
  180. entry.mType = data->mType;
  181. entry.mReferenceCount = 1;
  182. offset = current_offset;
  183. alloc_entry2bytestream(buffer, offset, entry);
  184. lsa_insert_data(buffer, offset, data, entry, heapsize);
  185. hp = get_register(buffer, LREG_HP);
  186. if (b_delete)
  187. delete data;
  188. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  189. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  190. return current_offset - hr + 1;
  191. }
  192. }
  193. offset += entry.mSize;
  194. if (offset < hr + heapsize)
  195. {
  196. next_offset = offset;
  197. bytestream2alloc_entry(nextentry, buffer, offset);
  198. if (!nextentry.mType && !entry.mType)
  199. {
  200. entry.mSize += nextentry.mSize + SIZEOF_SCRIPT_ALLOC_ENTRY;
  201. offset = current_offset;
  202. alloc_entry2bytestream(buffer, offset, entry);
  203. }
  204. else
  205. {
  206. current_offset = next_offset;
  207. entry = nextentry;
  208. }
  209. // this works whether we are bumping out or coming in
  210. S32 new_hp = current_offset + size + 2*SIZEOF_SCRIPT_ALLOC_ENTRY;
  211. // make sure we aren't about to be stupid
  212. if (new_hp >= hr + heapsize)
  213. {
  214. break;
  215. }
  216. if (new_hp > hp)
  217. {
  218. set_register(buffer, LREG_HP, new_hp);
  219. hp = get_register(buffer, LREG_HP);
  220. }
  221. }
  222. else
  223. {
  224. break;
  225. }
  226. } while (1);
  227. set_fault(buffer, LSRF_STACK_HEAP_COLLISION);
  228. reset_hp_to_safe_spot(buffer);
  229. if (b_delete)
  230. delete data;
  231. return 0;
  232. }
  233. // split block
  234. // set offset to point to new block
  235. // set offset of new block to point to original offset - block size - data size
  236. // set new block to empty
  237. // set new block reference count to 0
  238. void lsa_split_block(U8 *buffer, S32 &offset, S32 size, LLScriptAllocEntry &entry)
  239. {
  240. if (get_register(buffer, LREG_FR))
  241. return;
  242. LLScriptAllocEntry newentry;
  243. newentry.mSize = entry.mSize - SIZEOF_SCRIPT_ALLOC_ENTRY - size;
  244. entry.mSize -= newentry.mSize + SIZEOF_SCRIPT_ALLOC_ENTRY;
  245. alloc_entry2bytestream(buffer, offset, entry);
  246. S32 orig_offset = offset + size;
  247. alloc_entry2bytestream(buffer, orig_offset, newentry);
  248. }
  249. // insert data
  250. // if data is non-list type
  251. // set type to basic type, set reference count to 1, copy data, return address
  252. // else
  253. // set type to list data type, set reference count to 1
  254. // save length of list
  255. // for each list entry
  256. // insert data
  257. // return address
  258. void lsa_insert_data(U8 *buffer, S32 &offset, LLScriptLibData *data, LLScriptAllocEntry &entry, S32 heapsize)
  259. {
  260. if (get_register(buffer, LREG_FR))
  261. return;
  262. if (data->mType != LST_LIST)
  263. {
  264. switch(data->mType)
  265. {
  266. case LST_INTEGER:
  267. integer2bytestream(buffer, offset, data->mInteger);
  268. break;
  269. case LST_FLOATINGPOINT:
  270. float2bytestream(buffer, offset, data->mFP);
  271. break;
  272. case LST_KEY:
  273.         char2bytestream(buffer, offset, data->mKey ? data->mKey : "");
  274. break;
  275. case LST_STRING:
  276.         char2bytestream(buffer, offset, data->mString ? data->mString : "");
  277. break;
  278. case LST_VECTOR:
  279. vector2bytestream(buffer, offset, data->mVec);
  280. break;
  281. case LST_QUATERNION:
  282. quaternion2bytestream(buffer, offset, data->mQuat);
  283. break;
  284. default:
  285. break;
  286. }
  287. }
  288. else
  289. {
  290. // store length of list
  291. integer2bytestream(buffer, offset, data->getListLength());
  292. data = data->mListp;
  293. while(data)
  294. {
  295. // store entry and then store address if valid
  296. S32 address = lsa_heap_add_data(buffer, data, heapsize, FALSE);
  297. integer2bytestream(buffer, offset, address);
  298. data = data->mListp;
  299. }
  300. }
  301. }
  302. S32 lsa_create_data_block(U8 **buffer, LLScriptLibData *data, S32 base_offset)
  303. {
  304. S32 offset = 0;
  305. S32 size = 0;
  306. LLScriptAllocEntry entry;
  307. if (!data)
  308. {
  309. entry.mType = LST_NULL;
  310. entry.mReferenceCount = 0;
  311. entry.mSize = MAX_HEAP_SIZE;
  312. size = SIZEOF_SCRIPT_ALLOC_ENTRY;
  313. *buffer = new U8[size];
  314. alloc_entry2bytestream(*buffer, offset, entry);
  315. return size;
  316. }
  317. entry.mType = data->mType;
  318. entry.mReferenceCount = 1;
  319. if (data->mType != LST_LIST)
  320. {
  321. if (  (data->mType != LST_STRING)
  322. &&(data->mType != LST_KEY))
  323. {
  324. size = LSCRIPTDataSize[data->mType];
  325. }
  326. else
  327. {
  328. if (data->mType == LST_STRING)
  329. {
  330. if (data->mString)
  331. {
  332. size = (S32)strlen(data->mString) + 1; /*Flawfinder: ignore*/
  333. }
  334. else
  335. {
  336. size = 1;
  337. }
  338. }
  339. if (data->mType == LST_KEY)
  340. {
  341. if (data->mKey)
  342. {
  343. size = (S32)strlen(data->mKey) + 1; /*Flawfinder: ignore*/
  344. }
  345. else
  346. {
  347. size = 1;
  348. }
  349. }
  350. }
  351. entry.mSize = size;
  352. size += SIZEOF_SCRIPT_ALLOC_ENTRY;
  353. *buffer = new U8[size];
  354. alloc_entry2bytestream(*buffer, offset, entry);
  355. switch(data->mType)
  356. {
  357. case LST_INTEGER:
  358. integer2bytestream(*buffer, offset, data->mInteger);
  359. break;
  360. case LST_FLOATINGPOINT:
  361. float2bytestream(*buffer, offset, data->mFP);
  362. break;
  363. case LST_KEY:
  364. if (data->mKey)
  365. char2bytestream(*buffer, offset, data->mKey);
  366. else
  367. byte2bytestream(*buffer, offset, 0);
  368. break;
  369. case LST_STRING:
  370. if (data->mString)
  371. char2bytestream(*buffer, offset, data->mString);
  372. else
  373. byte2bytestream(*buffer, offset, 0);
  374. break;
  375. case LST_VECTOR:
  376. vector2bytestream(*buffer, offset, data->mVec);
  377. break;
  378. case LST_QUATERNION:
  379. quaternion2bytestream(*buffer, offset, data->mQuat);
  380. break;
  381. default:
  382. break;
  383. }
  384. }
  385. else
  386. {
  387. U8 *listbuf;
  388. S32 length = data->getListLength();
  389. size = 4 * length + 4;
  390. entry.mSize = size;
  391. size += SIZEOF_SCRIPT_ALLOC_ENTRY;
  392. *buffer = new U8[size];
  393. alloc_entry2bytestream(*buffer, offset, entry);
  394. // store length of list
  395. integer2bytestream(*buffer, offset, length);
  396. data = data->mListp;
  397. while(data)
  398. {
  399. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  400. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  401. integer2bytestream(*buffer, offset, size + base_offset + 1);
  402. S32 listsize = lsa_create_data_block(&listbuf, data, base_offset + size);
  403. if (listsize)
  404. {
  405. U8 *tbuff = new U8[size + listsize];
  406. if (tbuff == NULL)
  407. {
  408. llerrs << "Memory Allocation Failed" << llendl;
  409. }
  410. memcpy(tbuff, *buffer, size); /*Flawfinder: ignore*/
  411. memcpy(tbuff + size, listbuf, listsize); /*Flawfinder: ignore*/
  412. size += listsize;
  413. delete [] *buffer;
  414. delete [] listbuf;
  415. *buffer = tbuff;
  416. }
  417. data = data->mListp;
  418. }
  419. }
  420. return size;
  421. }
  422. // increase reference count
  423. // increase reference count by 1
  424. void lsa_increase_ref_count(U8 *buffer, S32 offset)
  425. {
  426. if (get_register(buffer, LREG_FR))
  427. return;
  428. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  429. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  430. offset += get_register(buffer, LREG_HR) - 1;
  431. if (  (offset < get_register(buffer, LREG_HR))
  432. ||(offset >= get_register(buffer, LREG_HP)))
  433. {
  434. set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
  435. return;
  436. }
  437. S32 orig_offset = offset;
  438. LLScriptAllocEntry entry;
  439. bytestream2alloc_entry(entry, buffer, offset);
  440. entry.mReferenceCount++;
  441. alloc_entry2bytestream(buffer, orig_offset, entry);
  442. }
  443. // decrease reference count
  444. // decrease reference count by 1
  445. // if reference count == 0
  446. // set type to empty
  447. void lsa_decrease_ref_count(U8 *buffer, S32 offset)
  448. {
  449. if (get_register(buffer, LREG_FR))
  450. return;
  451. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  452. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  453. offset += get_register(buffer, LREG_HR) - 1;
  454. if (  (offset < get_register(buffer, LREG_HR))
  455. ||(offset >= get_register(buffer, LREG_HP)))
  456. {
  457. set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
  458. return;
  459. }
  460. S32 orig_offset = offset;
  461. LLScriptAllocEntry entry;
  462. bytestream2alloc_entry(entry, buffer, offset);
  463. entry.mReferenceCount--;
  464. if (entry.mReferenceCount < 0)
  465. {
  466. entry.mReferenceCount = 0;
  467. set_fault(buffer, LSRF_HEAP_ERROR);
  468. }
  469. else if (!entry.mReferenceCount)
  470. {
  471. if (entry.mType == LST_LIST)
  472. {
  473. S32 i, num = bytestream2integer(buffer, offset);
  474. for (i = 0; i < num; i++)
  475. {
  476. S32 list_offset = bytestream2integer(buffer, offset);
  477. lsa_decrease_ref_count(buffer, list_offset);
  478. }
  479. }
  480. entry.mType = LST_NULL;
  481. }
  482. alloc_entry2bytestream(buffer, orig_offset, entry);
  483. }
  484. char gLSAStringRead[TOP_OF_MEMORY]; /*Flawfinder: ignore*/
  485. LLScriptLibData *lsa_get_data(U8 *buffer, S32 &offset, BOOL b_dec_ref)
  486. {
  487. if (get_register(buffer, LREG_FR))
  488. return (new LLScriptLibData);
  489. S32 orig_offset = offset;
  490. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  491. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  492. offset += get_register(buffer, LREG_HR) - 1;
  493. if (  (offset < get_register(buffer, LREG_HR))
  494. ||(offset >= get_register(buffer, LREG_HP)))
  495. {
  496. set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
  497. return (new LLScriptLibData);
  498. }
  499. LLScriptAllocEntry entry;
  500. bytestream2alloc_entry(entry, buffer, offset);
  501. LLScriptLibData *retval = new LLScriptLibData;
  502. if (!entry.mType)
  503. {
  504. set_fault(buffer, LSRF_HEAP_ERROR);
  505. return retval;
  506. }
  507. retval->mType = (LSCRIPTType)entry.mType;
  508. if (entry.mType != LST_LIST)
  509. {
  510. switch(entry.mType)
  511. {
  512. case LST_INTEGER:
  513. retval->mInteger = bytestream2integer(buffer, offset);
  514. break;
  515. case LST_FLOATINGPOINT:
  516. retval->mFP = bytestream2float(buffer, offset);
  517. break;
  518. case LST_KEY:
  519. bytestream2char(gLSAStringRead, buffer, offset, sizeof(gLSAStringRead)); // global sring buffer? for real? :(
  520. retval->mKey = new char[strlen(gLSAStringRead) + 1]; /*Flawfinder: ignore*/
  521. strcpy(retval->mKey, gLSAStringRead); /*Flawfinder: ignore*/
  522. break;
  523. case LST_STRING:
  524. bytestream2char(gLSAStringRead, buffer, offset, sizeof(gLSAStringRead));
  525. retval->mString = new char[strlen(gLSAStringRead) + 1]; /*Flawfinder: ignore*/
  526. strcpy(retval->mString, gLSAStringRead); /*Flawfinder: ignore*/
  527. break;
  528. case LST_VECTOR:
  529. bytestream2vector(retval->mVec, buffer, offset);
  530. break;
  531. case LST_QUATERNION:
  532. bytestream2quaternion(retval->mQuat, buffer, offset);
  533. break;
  534. default:
  535. break;
  536. }
  537. }
  538. else
  539. {
  540. // get length of list
  541. S32 i, length = bytestream2integer(buffer, offset);
  542. LLScriptLibData *tip = retval;
  543. for (i = 0; i < length; i++)
  544. {
  545. S32 address = bytestream2integer(buffer, offset);
  546. tip->mListp = lsa_get_data(buffer, address, FALSE);
  547. tip = tip->mListp;
  548. }
  549. }
  550. if (retval->checkForMultipleLists())
  551. {
  552. set_fault(buffer, LSRF_NESTING_LISTS);
  553. }
  554. if (b_dec_ref)
  555. {
  556. lsa_decrease_ref_count(buffer, orig_offset);
  557. }
  558. return retval;
  559. }
  560. LLScriptLibData *lsa_get_list_ptr(U8 *buffer, S32 &offset, BOOL b_dec_ref)
  561. {
  562. if (get_register(buffer, LREG_FR))
  563. return (new LLScriptLibData);
  564. S32 orig_offset = offset;
  565. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  566. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  567. offset += get_register(buffer, LREG_HR) - 1;
  568. if (  (offset < get_register(buffer, LREG_HR))
  569. ||(offset >= get_register(buffer, LREG_HP)))
  570. {
  571. set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
  572. return (new LLScriptLibData);
  573. }
  574. LLScriptAllocEntry entry;
  575. bytestream2alloc_entry(entry, buffer, offset);
  576. if (!entry.mType)
  577. {
  578. set_fault(buffer, LSRF_HEAP_ERROR);
  579. return NULL;
  580. }
  581. LLScriptLibData base, *tip = &base;
  582. if (entry.mType != LST_LIST)
  583. {
  584. return NULL;
  585. }
  586. else
  587. {
  588. // get length of list
  589. S32 i, length = bytestream2integer(buffer, offset);
  590. for (i = 0; i < length; i++)
  591. {
  592. S32 address = bytestream2integer(buffer, offset);
  593. tip->mListp = lsa_get_data(buffer, address, FALSE);
  594. tip = tip->mListp;
  595. }
  596. }
  597. if (b_dec_ref)
  598. {
  599. lsa_decrease_ref_count(buffer, orig_offset);
  600. }
  601. tip = base.mListp;
  602. base.mListp = NULL;
  603. return tip;
  604. }
  605. S32 lsa_cat_strings(U8 *buffer, S32 offset1, S32 offset2, S32 heapsize)
  606. {
  607. if (get_register(buffer, LREG_FR))
  608. return 0;
  609. LLScriptLibData *string1;
  610. LLScriptLibData *string2;
  611. if (offset1 != offset2)
  612. {
  613. string1 = lsa_get_data(buffer, offset1, TRUE);
  614. string2 = lsa_get_data(buffer, offset2, TRUE);
  615. }
  616. else
  617. {
  618. string1 = lsa_get_data(buffer, offset1, TRUE);
  619. string2 = lsa_get_data(buffer, offset2, TRUE);
  620. }
  621. if (  (!string1)
  622. ||(!string2))
  623. {
  624. set_fault(buffer, LSRF_HEAP_ERROR);
  625. delete string1;
  626. delete string2;
  627. return 0;
  628. }
  629. char *test1 = NULL, *test2 = NULL;
  630. if (string1->mType == LST_STRING)
  631. {
  632. test1 = string1->mString;
  633. }
  634. else if (string1->mType == LST_KEY)
  635. {
  636. test1 = string1->mKey;
  637. }
  638. if (string2->mType == LST_STRING)
  639. {
  640. test2 = string2->mString;
  641. }
  642. else if (string2->mType == LST_KEY)
  643. {
  644. test2 = string2->mKey;
  645. }
  646. if (  (!test1)
  647. ||(!test2))
  648. {
  649. set_fault(buffer, LSRF_HEAP_ERROR);
  650. delete string1;
  651. delete string2;
  652. return 0;
  653. }
  654. S32 size = (S32)strlen(test1) + (S32)strlen(test2) + 1; /*Flawfinder: ignore*/
  655. LLScriptLibData *string3 = new LLScriptLibData;
  656. string3->mType = LST_STRING;
  657. string3->mString = new char[size];
  658. strcpy(string3->mString, test1); /*Flawfinder: ignore*/
  659. strcat(string3->mString, test2); /*Flawfinder: ignore*/
  660. delete string1;
  661. delete string2;
  662. return lsa_heap_add_data(buffer, string3, heapsize, TRUE);
  663. }
  664. S32 lsa_cmp_strings(U8 *buffer, S32 offset1, S32 offset2)
  665. {
  666. if (get_register(buffer, LREG_FR))
  667. return 0;
  668. LLScriptLibData *string1;
  669. LLScriptLibData *string2;
  670. string1 = lsa_get_data(buffer, offset1, TRUE);
  671. string2 = lsa_get_data(buffer, offset2, TRUE);
  672. if (  (!string1)
  673. ||(!string2))
  674. {
  675. set_fault(buffer, LSRF_HEAP_ERROR);
  676. delete string1;
  677. delete string2;
  678. return 0;
  679. }
  680. char *test1 = NULL, *test2 = NULL;
  681. if (string1->mType == LST_STRING)
  682. {
  683. test1 = string1->mString;
  684. }
  685. else if (string1->mType == LST_KEY)
  686. {
  687. test1 = string1->mKey;
  688. }
  689. if (string2->mType == LST_STRING)
  690. {
  691. test2 = string2->mString;
  692. }
  693. else if (string2->mType == LST_KEY)
  694. {
  695. test2 = string2->mKey;
  696. }
  697. if (  (!test1)
  698. ||(!test2))
  699. {
  700. set_fault(buffer, LSRF_HEAP_ERROR);
  701. delete string1;
  702. delete string2;
  703. return 0;
  704. }
  705. S32 retval = strcmp(test1, test2);
  706. delete string1;
  707. delete string2;
  708. return retval;
  709. }
  710. void lsa_print_heap(U8 *buffer)
  711. {
  712. S32 offset = get_register(buffer, LREG_HR);
  713. S32 readoffset;
  714. S32 ivalue;
  715. F32 fpvalue;
  716. LLVector3 vvalue;
  717. LLQuaternion qvalue;
  718. char string[4096]; /*Flawfinder: ignore*/
  719. LLScriptAllocEntry entry;
  720. bytestream2alloc_entry(entry, buffer, offset);
  721. printf("HP: [0x%X]n", get_register(buffer, LREG_HP));
  722. printf("==========n");
  723. while (offset + entry.mSize < MAX_HEAP_SIZE)
  724. {
  725. printf("[0x%X] ", offset);
  726. printf("%s ", LSCRIPTTypeNames[entry.mType]);
  727. printf("Ref Count: %d ", entry.mReferenceCount);
  728. printf("Size: %d = ", entry.mSize);
  729. readoffset = offset;
  730. switch(entry.mType)
  731. {
  732. case LST_INTEGER:
  733. ivalue = bytestream2integer(buffer, readoffset);
  734. printf("%dn", ivalue);
  735. break;
  736. case LST_FLOATINGPOINT:
  737. fpvalue = bytestream2float(buffer, readoffset);
  738. printf("%fn", fpvalue);
  739. break;
  740. case LST_STRING:
  741. bytestream2char(string, buffer, readoffset, sizeof(string));
  742. printf("%sn", string);
  743. break;
  744. case LST_KEY:
  745. bytestream2char(string, buffer, readoffset, sizeof(string));
  746. printf("%sn", string);
  747. break;
  748. case LST_VECTOR:
  749. bytestream2vector(vvalue, buffer, readoffset);
  750. printf("< %f, %f, %f >n", vvalue.mV[VX], vvalue.mV[VY], vvalue.mV[VZ]);
  751. break;
  752. case LST_QUATERNION:
  753. bytestream2quaternion(qvalue, buffer, readoffset);
  754. printf("< %f, %f, %f, %f >n", qvalue.mQ[VX], qvalue.mQ[VY], qvalue.mQ[VZ], qvalue.mQ[VS]);
  755. break;
  756. case LST_LIST:
  757. ivalue = bytestream2integer(buffer, readoffset);
  758. printf("%dn", ivalue);
  759. break;
  760. default:
  761. printf("n");
  762. break;
  763. }
  764. offset += entry.mSize;
  765. bytestream2alloc_entry(entry, buffer, offset);
  766. }
  767. printf("[0x%X] ", offset);
  768. printf("%s ", LSCRIPTTypeNames[entry.mType]);
  769. printf("Ref Count: %d ", entry.mReferenceCount);
  770. printf("Size: %dn", entry.mSize);
  771. printf("==========n");
  772. }
  773. void lsa_fprint_heap(U8 *buffer, LLFILE *fp)
  774. {
  775. S32 offset = get_register(buffer, LREG_HR);
  776. S32 readoffset;
  777. S32 ivalue;
  778. F32 fpvalue;
  779. LLVector3 vvalue;
  780. LLQuaternion qvalue;
  781. char string[4096]; /*Flawfinder: ignore*/
  782. LLScriptAllocEntry entry;
  783. bytestream2alloc_entry(entry, buffer, offset);
  784. while (offset + entry.mSize < MAX_HEAP_SIZE)
  785. {
  786. fprintf(fp, "[0x%X] ", offset);
  787. fprintf(fp, "%s ", LSCRIPTTypeNames[entry.mType]);
  788. fprintf(fp, "Ref Count: %d ", entry.mReferenceCount);
  789. fprintf(fp, "Size: %d = ", entry.mSize);
  790. readoffset = offset;
  791. switch(entry.mType)
  792. {
  793. case LST_INTEGER:
  794. ivalue = bytestream2integer(buffer, readoffset);
  795. fprintf(fp, "%dn", ivalue);
  796. break;
  797. case LST_FLOATINGPOINT:
  798. fpvalue = bytestream2float(buffer, readoffset);
  799. fprintf(fp, "%fn", fpvalue);
  800. break;
  801. case LST_STRING:
  802. bytestream2char(string, buffer, readoffset, sizeof(string));
  803. fprintf(fp, "%sn", string);
  804. break;
  805. case LST_KEY:
  806. bytestream2char(string, buffer, readoffset, sizeof(string));
  807. fprintf(fp, "%sn", string);
  808. break;
  809. case LST_VECTOR:
  810. bytestream2vector(vvalue, buffer, readoffset);
  811. fprintf(fp, "< %f, %f, %f >n", vvalue.mV[VX], vvalue.mV[VY], vvalue.mV[VZ]);
  812. break;
  813. case LST_QUATERNION:
  814. bytestream2quaternion(qvalue, buffer, readoffset);
  815. fprintf(fp, "< %f, %f, %f, %f >n", qvalue.mQ[VX], qvalue.mQ[VY], qvalue.mQ[VZ], qvalue.mQ[VS]);
  816. break;
  817. case LST_LIST:
  818. ivalue = bytestream2integer(buffer, readoffset);
  819. fprintf(fp, "%dn", ivalue);
  820. break;
  821. default:
  822. fprintf(fp, "n");
  823. break;
  824. }
  825. offset += entry.mSize;
  826. bytestream2alloc_entry(entry, buffer, offset);
  827. }
  828. fprintf(fp, "[0x%X] ", offset);
  829. fprintf(fp, "%s ", LSCRIPTTypeNames[entry.mType]);
  830. fprintf(fp, "Ref Count: %d ", entry.mReferenceCount);
  831. fprintf(fp, "Size: %d", entry.mSize);
  832. fprintf(fp, "n");
  833. }
  834. S32 lsa_cat_lists(U8 *buffer, S32 offset1, S32 offset2, S32 heapsize)
  835. {
  836. if (get_register(buffer, LREG_FR))
  837. return 0;
  838. LLScriptLibData *list1;
  839. LLScriptLibData *list2;
  840. if (offset1 != offset2)
  841. {
  842. list1 = lsa_get_data(buffer, offset1, TRUE);
  843. list2 = lsa_get_data(buffer, offset2, TRUE);
  844. }
  845. else
  846. {
  847. list1 = lsa_get_data(buffer, offset1, TRUE);
  848. list2 = lsa_get_data(buffer, offset2, TRUE);
  849. }
  850. if (  (!list1)
  851. ||(!list2))
  852. {
  853. set_fault(buffer, LSRF_HEAP_ERROR);
  854. delete list1;
  855. delete list2;
  856. return 0;
  857. }
  858. if (  (list1->mType != LST_LIST)
  859. ||(list2->mType != LST_LIST))
  860. {
  861. set_fault(buffer, LSRF_HEAP_ERROR);
  862. delete list1;
  863. delete list2;
  864. return 0;
  865. }
  866. LLScriptLibData *runner = list1;
  867. while (runner->mListp)
  868. {
  869. runner = runner->mListp;
  870. }
  871. runner->mListp = list2->mListp;
  872. list2->mListp = NULL;
  873. delete list2;
  874. return lsa_heap_add_data(buffer, list1, heapsize, TRUE);
  875. }
  876. S32 lsa_cmp_lists(U8 *buffer, S32 offset1, S32 offset2)
  877. {
  878. if (get_register(buffer, LREG_FR))
  879. return 0;
  880. LLScriptLibData *list1;
  881. LLScriptLibData *list2;
  882. if (offset1 != offset2)
  883. {
  884. list1 = lsa_get_data(buffer, offset1, TRUE);
  885. list2 = lsa_get_data(buffer, offset2, TRUE);
  886. }
  887. else
  888. {
  889. list1 = lsa_get_data(buffer, offset1, FALSE);
  890. list2 = lsa_get_data(buffer, offset2, TRUE);
  891. }
  892. if (  (!list1)
  893. ||(!list2))
  894. {
  895. set_fault(buffer, LSRF_HEAP_ERROR);
  896. delete list1;
  897. delete list2;
  898. return 0;
  899. }
  900. if (  (list1->mType != LST_LIST)
  901. ||(list2->mType != LST_LIST))
  902. {
  903. set_fault(buffer, LSRF_HEAP_ERROR);
  904. delete list1;
  905. delete list2;
  906. return 0;
  907. }
  908. S32 length1 = list1->getListLength();
  909. S32 length2 = list2->getListLength();
  910. delete list1;
  911. delete list2;
  912. return length1 - length2;
  913. }
  914. S32 lsa_preadd_lists(U8 *buffer, LLScriptLibData *data, S32 offset2, S32 heapsize)
  915. {
  916. if (get_register(buffer, LREG_FR))
  917. return 0;
  918. LLScriptLibData *list2 = lsa_get_data(buffer, offset2, TRUE);
  919. if (!list2)
  920. {
  921. set_fault(buffer, LSRF_HEAP_ERROR);
  922. delete list2;
  923. return 0;
  924. }
  925. if (list2->mType != LST_LIST)
  926. {
  927. set_fault(buffer, LSRF_HEAP_ERROR);
  928. delete list2;
  929. return 0;
  930. }
  931. LLScriptLibData *runner = data->mListp;
  932. while (runner->mListp)
  933. {
  934. runner = runner->mListp;
  935. }
  936. runner->mListp = list2->mListp;
  937. list2->mListp = data->mListp;
  938. return lsa_heap_add_data(buffer, list2, heapsize, TRUE);
  939. }
  940. S32 lsa_postadd_lists(U8 *buffer, S32 offset1, LLScriptLibData *data, S32 heapsize)
  941. {
  942. if (get_register(buffer, LREG_FR))
  943. return 0;
  944. LLScriptLibData *list1 = lsa_get_data(buffer, offset1, TRUE);
  945. if (!list1)
  946. {
  947. set_fault(buffer, LSRF_HEAP_ERROR);
  948. delete list1;
  949. return 0;
  950. }
  951. if (list1->mType != LST_LIST)
  952. {
  953. set_fault(buffer, LSRF_HEAP_ERROR);
  954. delete list1;
  955. return 0;
  956. }
  957. LLScriptLibData *runner = list1;
  958. while (runner->mListp)
  959. {
  960. runner = runner->mListp;
  961. }
  962. runner->mListp = data->mListp;
  963. return lsa_heap_add_data(buffer, list1, heapsize, TRUE);
  964. }
  965. LLScriptLibData* lsa_randomize(LLScriptLibData* src, S32 stride)
  966. {
  967. S32 number = src->getListLength();
  968. if (number <= 0)
  969. {
  970. return NULL;
  971. }
  972. if (stride <= 0)
  973. {
  974. stride = 1;
  975. }
  976. if(number % stride)
  977. {
  978. LLScriptLibData* retval = src->mListp;
  979. src->mListp = NULL;
  980. return retval;
  981. }
  982. S32 buckets = number / stride;
  983. // Copy everything into a special vector for sorting;
  984. std::vector<LLScriptLibData*> sort_array;
  985. sort_array.reserve(number);
  986. LLScriptLibData* temp = src->mListp;
  987. while(temp)
  988. {
  989. sort_array.push_back(temp);
  990. temp = temp->mListp;
  991. }
  992. // We cannot simply call random_shuffle or similar algorithm since
  993. // we need to obey the stride. So, we iterate over what we have
  994. // and swap each with a random other segment.
  995. S32 index = 0;
  996. S32 ii = 0;
  997. for(; ii < number; ii += stride)
  998. {
  999. index = ll_rand(buckets) * stride;
  1000. for(S32 jj = 0; jj < stride; ++jj)
  1001. {
  1002. std::swap(sort_array[ii + jj], sort_array[index + jj]);
  1003. }
  1004. }
  1005. // copy the pointers back out
  1006. ii = 1;
  1007. temp = sort_array[0];
  1008. while (ii < number)
  1009. {
  1010. temp->mListp = sort_array[ii++];
  1011. temp = temp->mListp;
  1012. }
  1013. temp->mListp = NULL;
  1014. src->mListp = NULL;
  1015. LLScriptLibData* ret_value = sort_array[0];
  1016. return ret_value;
  1017. }