PageRenderTime 844ms CodeModel.GetById 161ms app.highlight 527ms RepoModel.GetById 147ms app.codeStats 1ms

/indra/lscript/lscript_library/lscript_alloc.cpp

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