core/systems/HandleSys.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Mar 30 07:00:22 2008 +0000 (2008-03-30)
changeset 1952 b7aa2b626807
child 2175 54a8411faaac
permissions -rw-r--r--
Spring Cleaning, Part Ichi (1)
Various minor things done to project files
Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way)
Updated regex project file and makefile
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
ds@1952
     4
 * SourceMod
ds@1952
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
ds@1952
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1952
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952
    10
 * Free Software Foundation.
ds@1952
    11
 * 
ds@1952
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1952
    15
 * details.
ds@1952
    16
 *
ds@1952
    17
 * You should have received a copy of the GNU General Public License along with
ds@1952
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
ds@1952
    19
 *
ds@1952
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1952
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1952
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1952
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#include "HandleSys.h"
ds@1952
    33
#include "ShareSys.h"
ds@1952
    34
#include "PluginSys.h"
ds@1952
    35
#include "ExtensionSys.h"
ds@1952
    36
#include "Logger.h"
ds@1952
    37
#include <assert.h>
ds@1952
    38
#include <string.h>
ds@1952
    39
#include "sm_stringutil.h"
ds@1952
    40
ds@1952
    41
HandleSystem g_HandleSys;
ds@1952
    42
ds@1952
    43
QHandle *ignore_handle;
ds@1952
    44
ds@1952
    45
inline HandleType_t TypeParent(HandleType_t type)
ds@1952
    46
{
ds@1952
    47
	return (type & ~HANDLESYS_SUBTYPE_MASK);
ds@1952
    48
}
ds@1952
    49
ds@1952
    50
inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
ds@1952
    51
{
ds@1952
    52
	return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
ds@1952
    53
}
ds@1952
    54
ds@1952
    55
HandleSystem::HandleSystem()
ds@1952
    56
{
ds@1952
    57
	m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
ds@1952
    58
	memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
ds@1952
    59
ds@1952
    60
	m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
ds@1952
    61
	memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
ds@1952
    62
ds@1952
    63
	m_TypeLookup = sm_trie_create();
ds@1952
    64
	m_strtab = new BaseStringTable(512);
ds@1952
    65
ds@1952
    66
	m_TypeTail = 0;
ds@1952
    67
}
ds@1952
    68
ds@1952
    69
HandleSystem::~HandleSystem()
ds@1952
    70
{
ds@1952
    71
	delete [] m_Handles;
ds@1952
    72
	delete [] m_Types;
ds@1952
    73
	sm_trie_destroy(m_TypeLookup);
ds@1952
    74
	delete m_strtab;
ds@1952
    75
}
ds@1952
    76
ds@1952
    77
ds@1952
    78
HandleType_t HandleSystem::CreateType(const char *name, 
ds@1952
    79
									  IHandleTypeDispatch *dispatch, 
ds@1952
    80
									  HandleType_t parent, 
ds@1952
    81
									  const TypeAccess *typeAccess, 
ds@1952
    82
									  const HandleAccess *hndlAccess, 
ds@1952
    83
									  IdentityToken_t *ident,
ds@1952
    84
									  HandleError *err)
ds@1952
    85
{
ds@1952
    86
	if (!dispatch)
ds@1952
    87
	{
ds@1952
    88
		if (err)
ds@1952
    89
		{
ds@1952
    90
			*err = HandleError_Parameter;
ds@1952
    91
		}
ds@1952
    92
		return 0;
ds@1952
    93
	}
ds@1952
    94
ds@1952
    95
	if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
ds@1952
    96
	{
ds@1952
    97
		if (err)
ds@1952
    98
		{
ds@1952
    99
			*err = HandleError_Version;
ds@1952
   100
		}
ds@1952
   101
		return 0;
ds@1952
   102
	}
ds@1952
   103
ds@1952
   104
	if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
ds@1952
   105
	{
ds@1952
   106
		if (err)
ds@1952
   107
		{
ds@1952
   108
			*err = HandleError_Version;
ds@1952
   109
		}
ds@1952
   110
		return 0;
ds@1952
   111
	}
ds@1952
   112
ds@1952
   113
	bool isChild = false;
ds@1952
   114
ds@1952
   115
	if (parent != 0)
ds@1952
   116
	{
ds@1952
   117
		isChild = true;
ds@1952
   118
		if (parent & HANDLESYS_SUBTYPE_MASK)
ds@1952
   119
		{
ds@1952
   120
			if (err)
ds@1952
   121
			{
ds@1952
   122
				*err = HandleError_NoInherit;
ds@1952
   123
			}
ds@1952
   124
			return 0;
ds@1952
   125
		}
ds@1952
   126
		if (parent >= HANDLESYS_TYPEARRAY_SIZE
ds@1952
   127
			|| m_Types[parent].dispatch == NULL)
ds@1952
   128
		{
ds@1952
   129
			if (err)
ds@1952
   130
			{
ds@1952
   131
				*err = HandleError_Parameter;
ds@1952
   132
			}
ds@1952
   133
			return 0;
ds@1952
   134
		}
ds@1952
   135
		if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
ds@1952
   136
			&& (m_Types[parent].typeSec.ident != ident))
ds@1952
   137
		{
ds@1952
   138
			if (err)
ds@1952
   139
			{
ds@1952
   140
				*err = HandleError_Access;
ds@1952
   141
			}
ds@1952
   142
			return 0;
ds@1952
   143
		}
ds@1952
   144
	}
ds@1952
   145
ds@1952
   146
	if (name && name[0] != '\0')
ds@1952
   147
	{
ds@1952
   148
		if (sm_trie_retrieve(m_TypeLookup, name, NULL))
ds@1952
   149
		{
ds@1952
   150
			if (err)
ds@1952
   151
			{
ds@1952
   152
				*err = HandleError_Parameter;
ds@1952
   153
			}
ds@1952
   154
			return 0;
ds@1952
   155
		}
ds@1952
   156
	}
ds@1952
   157
ds@1952
   158
	unsigned int index;
ds@1952
   159
ds@1952
   160
	if (isChild)
ds@1952
   161
	{
ds@1952
   162
		QHandleType *pParent = &m_Types[parent];
ds@1952
   163
		if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
ds@1952
   164
		{
ds@1952
   165
			if (err)
ds@1952
   166
			{
ds@1952
   167
				*err = HandleError_Limit;
ds@1952
   168
			}
ds@1952
   169
			return 0;
ds@1952
   170
		}
ds@1952
   171
		index = 0;
ds@1952
   172
		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
ds@1952
   173
		{
ds@1952
   174
			if (m_Types[parent + i].dispatch == NULL)
ds@1952
   175
			{
ds@1952
   176
				index = parent + i;
ds@1952
   177
				break;
ds@1952
   178
			}
ds@1952
   179
		}
ds@1952
   180
		if (!index)
ds@1952
   181
		{
ds@1952
   182
			if (err)
ds@1952
   183
			{
ds@1952
   184
				*err = HandleError_Limit;
ds@1952
   185
			}
ds@1952
   186
			return 0;
ds@1952
   187
		}
ds@1952
   188
		pParent->children++;
ds@1952
   189
	} else {
ds@1952
   190
		if (m_FreeTypes == 0)
ds@1952
   191
		{
ds@1952
   192
			/* Reserve another index */
ds@1952
   193
			if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
ds@1952
   194
			{
ds@1952
   195
				if (err)
ds@1952
   196
				{
ds@1952
   197
					*err = HandleError_Limit;
ds@1952
   198
				}
ds@1952
   199
				return 0;
ds@1952
   200
			} else {
ds@1952
   201
				m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
ds@1952
   202
				index = m_TypeTail;
ds@1952
   203
			}
ds@1952
   204
		} else {
ds@1952
   205
			/* The "free array" is compacted into the normal array for easiness */
ds@1952
   206
			index = m_Types[m_FreeTypes--].freeID;
ds@1952
   207
		}
ds@1952
   208
	}
ds@1952
   209
ds@1952
   210
	QHandleType *pType = &m_Types[index];
ds@1952
   211
	
ds@1952
   212
	pType->dispatch = dispatch;
ds@1952
   213
	if (name && name[0] != '\0')
ds@1952
   214
	{
ds@1952
   215
		pType->nameIdx = m_strtab->AddString(name);
ds@1952
   216
		sm_trie_insert(m_TypeLookup, name, (void *)pType);
ds@1952
   217
	} else {
ds@1952
   218
		pType->nameIdx = -1;
ds@1952
   219
	}
ds@1952
   220
ds@1952
   221
	pType->opened = 0;
ds@1952
   222
ds@1952
   223
	if (typeAccess)
ds@1952
   224
	{
ds@1952
   225
		pType->typeSec = *typeAccess;
ds@1952
   226
	} else {
ds@1952
   227
		InitAccessDefaults(&pType->typeSec, NULL);
ds@1952
   228
		pType->typeSec.ident = ident;
ds@1952
   229
	}
ds@1952
   230
ds@1952
   231
	if (hndlAccess)
ds@1952
   232
	{
ds@1952
   233
		pType->hndlSec = *hndlAccess;
ds@1952
   234
	} else {
ds@1952
   235
		InitAccessDefaults(NULL, &pType->hndlSec);
ds@1952
   236
	}
ds@1952
   237
ds@1952
   238
	if (!isChild)
ds@1952
   239
	{
ds@1952
   240
		pType->children = 0;
ds@1952
   241
	}
ds@1952
   242
ds@1952
   243
	return index;
ds@1952
   244
}
ds@1952
   245
ds@1952
   246
bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
ds@1952
   247
{
ds@1952
   248
	QHandleType *_type;
ds@1952
   249
ds@1952
   250
	if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
ds@1952
   251
	{
ds@1952
   252
		return false;
ds@1952
   253
	}
ds@1952
   254
ds@1952
   255
	unsigned int offset = _type - m_Types;
ds@1952
   256
ds@1952
   257
	if (type)
ds@1952
   258
	{
ds@1952
   259
		*type = offset;
ds@1952
   260
	}
ds@1952
   261
ds@1952
   262
	return true;
ds@1952
   263
}
ds@1952
   264
ds@1952
   265
HandleError HandleSystem::TryAllocHandle(unsigned int *handle)
ds@1952
   266
{
ds@1952
   267
	if (m_FreeHandles == 0)
ds@1952
   268
	{
ds@1952
   269
		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
ds@1952
   270
		{
ds@1952
   271
			return HandleError_Limit;;
ds@1952
   272
		}
ds@1952
   273
		*handle = ++m_HandleTail;
ds@1952
   274
	}
ds@1952
   275
	else
ds@1952
   276
	{
ds@1952
   277
		*handle = m_Handles[m_FreeHandles--].freeID;
ds@1952
   278
	}
ds@1952
   279
ds@1952
   280
	return HandleError_None;
ds@1952
   281
}
ds@1952
   282
ds@1952
   283
HandleError HandleSystem::MakePrimHandle(HandleType_t type, 
ds@1952
   284
						   QHandle **in_pHandle, 
ds@1952
   285
						   unsigned int *in_index, 
ds@1952
   286
						   Handle_t *in_handle,
ds@1952
   287
						   IdentityToken_t *owner,
ds@1952
   288
						   bool identity)
ds@1952
   289
{
ds@1952
   290
	HandleError err;
ds@1952
   291
	unsigned int owner_index = 0;
ds@1952
   292
ds@1952
   293
	if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
ds@1952
   294
	{
ds@1952
   295
		return HandleError_Identity;
ds@1952
   296
	}
ds@1952
   297
ds@1952
   298
	unsigned int handle;
ds@1952
   299
	if ((err = TryAllocHandle(&handle)) != HandleError_None)
ds@1952
   300
	{
ds@1952
   301
		if (!TryAndFreeSomeHandles()
ds@1952
   302
			|| (err = TryAllocHandle(&handle)) != HandleError_None)
ds@1952
   303
		{
ds@1952
   304
			return err;
ds@1952
   305
		}
ds@1952
   306
	}
ds@1952
   307
ds@1952
   308
	QHandle *pHandle = &m_Handles[handle];
ds@1952
   309
	
ds@1952
   310
	assert(pHandle->set == false);
ds@1952
   311
ds@1952
   312
	if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
ds@1952
   313
	{
ds@1952
   314
		m_HSerial = 1;
ds@1952
   315
	}
ds@1952
   316
ds@1952
   317
	/* Set essential information */
ds@1952
   318
	pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
ds@1952
   319
	pHandle->refcount = 1;
ds@1952
   320
	pHandle->type = type;
ds@1952
   321
	pHandle->serial = m_HSerial;
ds@1952
   322
	pHandle->owner = owner;
ds@1952
   323
	pHandle->ch_next = 0;
ds@1952
   324
	pHandle->access_special = false;
ds@1952
   325
	pHandle->is_destroying = false;
ds@1952
   326
ds@1952
   327
	/* Create the hash value */
ds@1952
   328
	Handle_t hash = pHandle->serial;
ds@1952
   329
	hash <<= 16;
ds@1952
   330
	hash |= handle;
ds@1952
   331
ds@1952
   332
	/* Add a reference count to the type */
ds@1952
   333
	m_Types[type].opened++;
ds@1952
   334
ds@1952
   335
	/* Output */
ds@1952
   336
	*in_pHandle = pHandle;
ds@1952
   337
	*in_index = handle;
ds@1952
   338
	*in_handle = hash;
ds@1952
   339
ds@1952
   340
	/* Decode the identity token 
ds@1952
   341
	 * For now, we don't allow nested ownership
ds@1952
   342
	 */
ds@1952
   343
	if (owner && !identity)
ds@1952
   344
	{
ds@1952
   345
		QHandle *pIdentity = &m_Handles[owner_index];
ds@1952
   346
		if (pIdentity->ch_prev == 0)
ds@1952
   347
		{
ds@1952
   348
			pIdentity->ch_prev = handle;
ds@1952
   349
			pIdentity->ch_next = handle;
ds@1952
   350
			pHandle->ch_prev = 0;
ds@1952
   351
		}
ds@1952
   352
		else
ds@1952
   353
		{
ds@1952
   354
			/* Link previous node to us (forward) */
ds@1952
   355
			m_Handles[pIdentity->ch_next].ch_next = handle;
ds@1952
   356
			/* Link us to previous node (backwards) */
ds@1952
   357
			pHandle->ch_prev = pIdentity->ch_next;
ds@1952
   358
			/* Set new tail */
ds@1952
   359
			pIdentity->ch_next = handle;
ds@1952
   360
		}
ds@1952
   361
		pIdentity->refcount++;
ds@1952
   362
	}
ds@1952
   363
	else
ds@1952
   364
	{
ds@1952
   365
		pHandle->ch_prev = 0;
ds@1952
   366
	}
ds@1952
   367
ds@1952
   368
	return HandleError_None;
ds@1952
   369
}
ds@1952
   370
ds@1952
   371
void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
ds@1952
   372
{
ds@1952
   373
	if (!type
ds@1952
   374
		|| type >= HANDLESYS_TYPEARRAY_SIZE
ds@1952
   375
		|| m_Types[type].dispatch == NULL)
ds@1952
   376
	{
ds@1952
   377
		return;
ds@1952
   378
	}
ds@1952
   379
ds@1952
   380
	m_Types[type].typeSec.ident = pToken;
ds@1952
   381
}
ds@1952
   382
ds@1952
   383
Handle_t HandleSystem::CreateHandleInt(HandleType_t type, 
ds@1952
   384
									   void *object, 
ds@1952
   385
									   const HandleSecurity *pSec,
ds@1952
   386
									   HandleError *err, 
ds@1952
   387
									   const HandleAccess *pAccess,
ds@1952
   388
									   bool identity)
ds@1952
   389
{
ds@1952
   390
	IdentityToken_t *ident;
ds@1952
   391
	IdentityToken_t *owner;
ds@1952
   392
ds@1952
   393
	if (pSec)
ds@1952
   394
	{
ds@1952
   395
		ident = pSec->pIdentity;
ds@1952
   396
		owner = pSec->pOwner;
ds@1952
   397
	} else {
ds@1952
   398
		ident = NULL;
ds@1952
   399
		owner = NULL;
ds@1952
   400
	}
ds@1952
   401
ds@1952
   402
	if (!type 
ds@1952
   403
		|| type >= HANDLESYS_TYPEARRAY_SIZE
ds@1952
   404
		|| m_Types[type].dispatch == NULL)
ds@1952
   405
	{
ds@1952
   406
		if (err)
ds@1952
   407
		{
ds@1952
   408
			*err = HandleError_Parameter;
ds@1952
   409
		}
ds@1952
   410
		return 0;
ds@1952
   411
	}
ds@1952
   412
ds@1952
   413
	/* Check to see if we're allowed to create this handle type */
ds@1952
   414
	QHandleType *pType = &m_Types[type];
ds@1952
   415
	if (!pType->typeSec.access[HTypeAccess_Create]
ds@1952
   416
	&& (!pType->typeSec.ident
ds@1952
   417
		|| pType->typeSec.ident != ident))
ds@1952
   418
	{
ds@1952
   419
		if (err)
ds@1952
   420
		{
ds@1952
   421
			*err = HandleError_Access;
ds@1952
   422
		}
ds@1952
   423
		return 0;
ds@1952
   424
	}
ds@1952
   425
ds@1952
   426
	unsigned int index;
ds@1952
   427
	Handle_t handle;
ds@1952
   428
	QHandle *pHandle;
ds@1952
   429
	HandleError _err;
ds@1952
   430
ds@1952
   431
	if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
ds@1952
   432
	{
ds@1952
   433
		if (err)
ds@1952
   434
		{
ds@1952
   435
			*err = _err;
ds@1952
   436
		}
ds@1952
   437
		return 0;
ds@1952
   438
	}
ds@1952
   439
ds@1952
   440
	if (pAccess)
ds@1952
   441
	{
ds@1952
   442
		pHandle->access_special = true;
ds@1952
   443
		pHandle->sec = *pAccess;
ds@1952
   444
	}
ds@1952
   445
ds@1952
   446
	pHandle->object = object;
ds@1952
   447
	pHandle->clone = 0;
ds@1952
   448
ds@1952
   449
	return handle;
ds@1952
   450
}
ds@1952
   451
ds@1952
   452
Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err)
ds@1952
   453
{
ds@1952
   454
	return CreateHandleInt(type, object, pSec, err, pAccess, false);
ds@1952
   455
}
ds@1952
   456
ds@1952
   457
Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
ds@1952
   458
{
ds@1952
   459
	HandleSecurity sec;
ds@1952
   460
ds@1952
   461
	sec.pIdentity = ident;
ds@1952
   462
	sec.pOwner = owner;
ds@1952
   463
ds@1952
   464
	return CreateHandleEx(type, object, &sec, NULL, err);
ds@1952
   465
}
ds@1952
   466
ds@1952
   467
bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
ds@1952
   468
{
ds@1952
   469
	/* Check the type inheritance */
ds@1952
   470
	if (intype & HANDLESYS_SUBTYPE_MASK)
ds@1952
   471
	{
ds@1952
   472
		if (intype != outtype
ds@1952
   473
			&& (TypeParent(intype) != TypeParent(outtype)))
ds@1952
   474
		{
ds@1952
   475
			return false;
ds@1952
   476
		}
ds@1952
   477
	} else {
ds@1952
   478
		if (intype != outtype)
ds@1952
   479
		{
ds@1952
   480
			return false;
ds@1952
   481
		}
ds@1952
   482
	}
ds@1952
   483
ds@1952
   484
	return true;
ds@1952
   485
}
ds@1952
   486
ds@1952
   487
HandleError HandleSystem::GetHandle(Handle_t handle,
ds@1952
   488
									IdentityToken_t *ident, 
ds@1952
   489
									QHandle **in_pHandle, 
ds@1952
   490
									unsigned int *in_index,
ds@1952
   491
									bool ignoreFree)
ds@1952
   492
{
ds@1952
   493
	unsigned int serial = (handle >> 16);
ds@1952
   494
	unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
ds@1952
   495
ds@1952
   496
	if (index == 0 || index == 0xFFFF)
ds@1952
   497
	{
ds@1952
   498
		return HandleError_Index;
ds@1952
   499
	}
ds@1952
   500
ds@1952
   501
	QHandle *pHandle = &m_Handles[index];
ds@1952
   502
ds@1952
   503
	if (!pHandle->set
ds@1952
   504
		|| (pHandle->set == HandleSet_Freed && !ignoreFree))
ds@1952
   505
	{
ds@1952
   506
		return HandleError_Freed;
ds@1952
   507
	} else if (pHandle->set == HandleSet_Identity
ds@1952
   508
			   && ident != g_ShareSys.GetIdentRoot())
ds@1952
   509
	{
ds@1952
   510
		/* Only IdentityHandle() can read this! */
ds@1952
   511
		return HandleError_Identity;
ds@1952
   512
	}
ds@1952
   513
	if (pHandle->serial != serial)
ds@1952
   514
	{
ds@1952
   515
		return HandleError_Changed;
ds@1952
   516
	}
ds@1952
   517
ds@1952
   518
	*in_pHandle = pHandle;
ds@1952
   519
	*in_index = index;
ds@1952
   520
ds@1952
   521
	return HandleError_None;
ds@1952
   522
}
ds@1952
   523
ds@1952
   524
bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity)
ds@1952
   525
{
ds@1952
   526
	QHandleType *pType = &m_Types[pHandle->type];
ds@1952
   527
	unsigned int access;
ds@1952
   528
ds@1952
   529
	if (pHandle->access_special)
ds@1952
   530
	{
ds@1952
   531
		access = pHandle->sec.access[right];
ds@1952
   532
	} else {
ds@1952
   533
		access = pType->hndlSec.access[right];
ds@1952
   534
	}
ds@1952
   535
ds@1952
   536
	/* Check if the type's identity matches */
ds@1952
   537
	if (access & HANDLE_RESTRICT_IDENTITY)
ds@1952
   538
	{
ds@1952
   539
		IdentityToken_t *owner = pType->typeSec.ident;
ds@1952
   540
		if (!owner
ds@1952
   541
			|| (!pSecurity || pSecurity->pIdentity != owner))
ds@1952
   542
		{
ds@1952
   543
			return false;
ds@1952
   544
		}
ds@1952
   545
	}
ds@1952
   546
ds@1952
   547
	/* Check if the owner is allowed */
ds@1952
   548
	if (access & HANDLE_RESTRICT_OWNER)
ds@1952
   549
	{
ds@1952
   550
		IdentityToken_t *owner = pHandle->owner;
ds@1952
   551
		if (owner
ds@1952
   552
			&& (!pSecurity || pSecurity->pOwner != owner))
ds@1952
   553
		{
ds@1952
   554
			return false;
ds@1952
   555
		}
ds@1952
   556
	}
ds@1952
   557
ds@1952
   558
	return true;
ds@1952
   559
}
ds@1952
   560
ds@1952
   561
HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
ds@1952
   562
{
ds@1952
   563
	/* Get a new Handle ID */
ds@1952
   564
	unsigned int new_index;
ds@1952
   565
	QHandle *pNewHandle;
ds@1952
   566
	Handle_t new_handle;
ds@1952
   567
	HandleError err;
ds@1952
   568
ds@1952
   569
	if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
ds@1952
   570
	{
ds@1952
   571
		return err;
ds@1952
   572
	}
ds@1952
   573
ds@1952
   574
	/* Assign permissions from parent */
ds@1952
   575
	if (pHandle->access_special)
ds@1952
   576
	{
ds@1952
   577
		pNewHandle->access_special = true;
ds@1952
   578
		pNewHandle->sec = pHandle->sec;
ds@1952
   579
	}
ds@1952
   580
ds@1952
   581
	pNewHandle->clone = index;
ds@1952
   582
	pHandle->refcount++;
ds@1952
   583
ds@1952
   584
	*newhandle = new_handle;
ds@1952
   585
ds@1952
   586
	return HandleError_None;
ds@1952
   587
}
ds@1952
   588
ds@1952
   589
HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
ds@1952
   590
{
ds@1952
   591
	HandleError err;
ds@1952
   592
	QHandle *pHandle;
ds@1952
   593
	unsigned int index;
ds@1952
   594
	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
ds@1952
   595
ds@1952
   596
	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
ds@1952
   597
	{
ds@1952
   598
		return err;
ds@1952
   599
	}
ds@1952
   600
ds@1952
   601
	/* Identities cannot be cloned */
ds@1952
   602
	if (pHandle->set == HandleSet_Identity)
ds@1952
   603
	{
ds@1952
   604
		return HandleError_Identity;
ds@1952
   605
	}
ds@1952
   606
ds@1952
   607
	/* Check if the handle can be cloned */
ds@1952
   608
	if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity))
ds@1952
   609
	{
ds@1952
   610
		return HandleError_Access;
ds@1952
   611
	}
ds@1952
   612
ds@1952
   613
	/* Make sure we're not cloning a clone */
ds@1952
   614
	if (pHandle->clone)
ds@1952
   615
	{
ds@1952
   616
		QHandle *pParent = &m_Handles[pHandle->clone];
ds@1952
   617
		return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
ds@1952
   618
	}
ds@1952
   619
ds@1952
   620
	return CloneHandle(pHandle, index, newhandle, newOwner);
ds@1952
   621
}
ds@1952
   622
ds@1952
   623
HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
ds@1952
   624
{
ds@1952
   625
	QHandleType *pType = &m_Types[pHandle->type];
ds@1952
   626
ds@1952
   627
	if (pHandle->clone)
ds@1952
   628
	{
ds@1952
   629
		/* If we're a clone, decrease the parent reference count */
ds@1952
   630
		QHandle *pMaster;
ds@1952
   631
		unsigned int master;
ds@1952
   632
ds@1952
   633
		/* Note that if we ever have per-handle security, we would need to re-check
ds@1952
   634
		* the access on this Handle. */
ds@1952
   635
		master = pHandle->clone;
ds@1952
   636
		pMaster = &m_Handles[master];
ds@1952
   637
ds@1952
   638
		/* Release the clone now */
ds@1952
   639
		ReleasePrimHandle(index);
ds@1952
   640
ds@1952
   641
		/* Decrement the master's reference count */
ds@1952
   642
		if (--pMaster->refcount == 0)
ds@1952
   643
		{
ds@1952
   644
			/* Type should be the same but do this anyway... */
ds@1952
   645
			pType = &m_Types[pMaster->type];
ds@1952
   646
			pMaster->is_destroying = true;
ds@1952
   647
			pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
ds@1952
   648
			ReleasePrimHandle(master);
ds@1952
   649
		}
ds@1952
   650
	} else if (pHandle->set == HandleSet_Identity) {
ds@1952
   651
		/* If we're an identity, skip all this stuff!
ds@1952
   652
		 * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
ds@1952
   653
		 */
ds@1952
   654
		ReleasePrimHandle(index);
ds@1952
   655
	} else {
ds@1952
   656
		/* Decrement, free if necessary */
ds@1952
   657
		if (--pHandle->refcount == 0)
ds@1952
   658
		{
ds@1952
   659
			pHandle->is_destroying = true;
ds@1952
   660
			pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
ds@1952
   661
			ReleasePrimHandle(index);
ds@1952
   662
		} else {
ds@1952
   663
			/* We must be cloned, so mark ourselves as freed */
ds@1952
   664
			pHandle->set = HandleSet_Freed;
ds@1952
   665
			/* Now, unlink us, so we're not being tracked by the owner */
ds@1952
   666
			if (pHandle->owner)
ds@1952
   667
			{
ds@1952
   668
				UnlinkHandleFromOwner(pHandle, index);
ds@1952
   669
			}
ds@1952
   670
		}
ds@1952
   671
	}
ds@1952
   672
ds@1952
   673
	return HandleError_None;
ds@1952
   674
}
ds@1952
   675
ds@1952
   676
HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity)
ds@1952
   677
{
ds@1952
   678
	unsigned int index;
ds@1952
   679
	QHandle *pHandle;
ds@1952
   680
	HandleError err;
ds@1952
   681
	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
ds@1952
   682
ds@1952
   683
	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
ds@1952
   684
	{
ds@1952
   685
		return err;
ds@1952
   686
	}
ds@1952
   687
ds@1952
   688
	if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity))
ds@1952
   689
	{
ds@1952
   690
		return HandleError_Access;
ds@1952
   691
	}
ds@1952
   692
ds@1952
   693
	if (pHandle->is_destroying)
ds@1952
   694
	{
ds@1952
   695
		/* Someone tried to free this recursively.  
ds@1952
   696
		 * We'll just ignore this safely.
ds@1952
   697
		 */
ds@1952
   698
		return HandleError_None;
ds@1952
   699
	}
ds@1952
   700
ds@1952
   701
	return FreeHandle(pHandle, index);
ds@1952
   702
}
ds@1952
   703
ds@1952
   704
HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
ds@1952
   705
{
ds@1952
   706
	unsigned int index;
ds@1952
   707
	QHandle *pHandle;
ds@1952
   708
	HandleError err;
ds@1952
   709
	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
ds@1952
   710
ds@1952
   711
	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
ds@1952
   712
	{
ds@1952
   713
		return err;
ds@1952
   714
	}
ds@1952
   715
ds@1952
   716
	if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity))
ds@1952
   717
	{
ds@1952
   718
		return HandleError_Access;
ds@1952
   719
	}
ds@1952
   720
ds@1952
   721
	/* Check the type inheritance */
ds@1952
   722
	if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
ds@1952
   723
	{
ds@1952
   724
		if (pHandle->type != type
ds@1952
   725
			&& (TypeParent(pHandle->type) != TypeParent(type)))
ds@1952
   726
		{
ds@1952
   727
			return HandleError_Type;
ds@1952
   728
		}
ds@1952
   729
	} else if (type) {
ds@1952
   730
		if (pHandle->type != type)
ds@1952
   731
		{
ds@1952
   732
			return HandleError_Type;
ds@1952
   733
		}
ds@1952
   734
	}
ds@1952
   735
ds@1952
   736
	if (object)
ds@1952
   737
	{
ds@1952
   738
		/* if we're a clone, the rules change - object is ONLY in our reference */
ds@1952
   739
		if (pHandle->clone)
ds@1952
   740
		{
ds@1952
   741
			pHandle = &m_Handles[pHandle->clone];
ds@1952
   742
		}
ds@1952
   743
		*object = pHandle->object;
ds@1952
   744
	}
ds@1952
   745
ds@1952
   746
	return HandleError_None;
ds@1952
   747
}
ds@1952
   748
ds@1952
   749
void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
ds@1952
   750
{
ds@1952
   751
	/* Unlink us if necessary */
ds@1952
   752
	unsigned int ident_index;
ds@1952
   753
	if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
ds@1952
   754
	{
ds@1952
   755
		/* Uh-oh! */
ds@1952
   756
		assert(pHandle->owner == 0);
ds@1952
   757
		return;
ds@1952
   758
	}
ds@1952
   759
	/* Note that since 0 is an invalid handle, if any of these links are 0,
ds@1952
   760
	* the data can still be set.
ds@1952
   761
	*/
ds@1952
   762
	QHandle *pIdentity = &m_Handles[ident_index];
ds@1952
   763
ds@1952
   764
	/* Unlink case: We're the head AND tail node */
ds@1952
   765
	if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
ds@1952
   766
	{
ds@1952
   767
		pIdentity->ch_prev = 0;
ds@1952
   768
		pIdentity->ch_next = 0;
ds@1952
   769
	}
ds@1952
   770
	/* Unlink case: We're the head node */
ds@1952
   771
	else if (index == pIdentity->ch_prev) {
ds@1952
   772
		/* Link us to the next in the chain */
ds@1952
   773
		pIdentity->ch_prev = pHandle->ch_next;
ds@1952
   774
		/* Patch up the previous link */
ds@1952
   775
		m_Handles[pHandle->ch_next].ch_prev = 0;
ds@1952
   776
	}
ds@1952
   777
	/* Unlink case: We're the tail node */
ds@1952
   778
	else if (index == pIdentity->ch_next) {
ds@1952
   779
		/* Link us to the previous in the chain */
ds@1952
   780
		pIdentity->ch_next = pHandle->ch_prev;
ds@1952
   781
		/* Patch up the next link */
ds@1952
   782
		m_Handles[pHandle->ch_prev].ch_next = 0;
ds@1952
   783
	}
ds@1952
   784
	/* Unlink case: We're in the middle! */
ds@1952
   785
	else {
ds@1952
   786
		/* Patch the forward reference */
ds@1952
   787
		m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
ds@1952
   788
		/* Patch the backward reference */
ds@1952
   789
		m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
ds@1952
   790
	}
ds@1952
   791
ds@1952
   792
	/* Lastly, decrease the reference count */
ds@1952
   793
	pIdentity->refcount--;
ds@1952
   794
}
ds@1952
   795
ds@1952
   796
void HandleSystem::ReleasePrimHandle(unsigned int index)
ds@1952
   797
{
ds@1952
   798
	QHandle *pHandle = &m_Handles[index];
ds@1952
   799
	HandleSet set = pHandle->set;
ds@1952
   800
ds@1952
   801
	if (pHandle->owner && (set != HandleSet_Identity))
ds@1952
   802
	{
ds@1952
   803
		UnlinkHandleFromOwner(pHandle, index);
ds@1952
   804
	}
ds@1952
   805
ds@1952
   806
	/* Were we an identity ourself? */
ds@1952
   807
	QHandle *pLocal;
ds@1952
   808
	if (set == HandleSet_Identity)
ds@1952
   809
	{
ds@1952
   810
		/* Extra work to do.  We need to find everything connected to this identity and release it. */
ds@1952
   811
		unsigned int ch_index;
ds@1952
   812
#if defined _DEBUG
ds@1952
   813
		unsigned int old_index = 0;
ds@1952
   814
#endif
ds@1952
   815
		while ((ch_index = pHandle->ch_next) != 0)
ds@1952
   816
		{
ds@1952
   817
			pLocal = &m_Handles[ch_index];
ds@1952
   818
#if defined _DEBUG
ds@1952
   819
			assert(old_index != ch_index);
ds@1952
   820
			assert(pLocal->set == HandleSet_Used);
ds@1952
   821
			old_index = ch_index;
ds@1952
   822
#endif
ds@1952
   823
			FreeHandle(pLocal, ch_index);
ds@1952
   824
		}
ds@1952
   825
	}
ds@1952
   826
ds@1952
   827
	pHandle->set = HandleSet_None;
ds@1952
   828
	m_Types[pHandle->type].opened--;
ds@1952
   829
	m_Handles[++m_FreeHandles].freeID = index;
ds@1952
   830
}
ds@1952
   831
ds@1952
   832
bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
ds@1952
   833
{
ds@1952
   834
	if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
ds@1952
   835
	{
ds@1952
   836
		return false;
ds@1952
   837
	}
ds@1952
   838
ds@1952
   839
	QHandleType *pType = &m_Types[type];
ds@1952
   840
ds@1952
   841
	if (pType->typeSec.ident
ds@1952
   842
		&& pType->typeSec.ident != ident)
ds@1952
   843
	{
ds@1952
   844
		return false;
ds@1952
   845
	}
ds@1952
   846
ds@1952
   847
	if (pType->dispatch == NULL)
ds@1952
   848
	{
ds@1952
   849
		return false;
ds@1952
   850
	}
ds@1952
   851
ds@1952
   852
	/* Remove children if we have to */
ds@1952
   853
	if (!(type & HANDLESYS_SUBTYPE_MASK))
ds@1952
   854
	{
ds@1952
   855
		QHandleType *childType;
ds@1952
   856
		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
ds@1952
   857
		{
ds@1952
   858
			childType = &m_Types[type + i];
ds@1952
   859
			if (childType->dispatch)
ds@1952
   860
			{
ds@1952
   861
				RemoveType(type + i, childType->typeSec.ident);
ds@1952
   862
			}
ds@1952
   863
		}
ds@1952
   864
		/* Link us into the free chain */
ds@1952
   865
		m_Types[++m_FreeTypes].freeID = type;
ds@1952
   866
	}
ds@1952
   867
ds@1952
   868
	/* Invalidate the type now */
ds@1952
   869
	IHandleTypeDispatch *dispatch = pType->dispatch;
ds@1952
   870
	pType->dispatch = NULL;
ds@1952
   871
ds@1952
   872
	/* Make sure nothing is using this type. */
ds@1952
   873
	if (pType->opened)
ds@1952
   874
	{
ds@1952
   875
		QHandle *pHandle;
ds@1952
   876
		for (unsigned int i=1; i<=m_HandleTail; i++)
ds@1952
   877
		{
ds@1952
   878
			pHandle = &m_Handles[i];
ds@1952
   879
			if (!pHandle->set || pHandle->type != type)
ds@1952
   880
			{
ds@1952
   881
				continue;
ds@1952
   882
			}
ds@1952
   883
			if (pHandle->clone)
ds@1952
   884
			{
ds@1952
   885
				/* Get parent */
ds@1952
   886
				QHandle *pOther = &m_Handles[pHandle->clone];
ds@1952
   887
				if (--pOther->refcount == 0)
ds@1952
   888
				{
ds@1952
   889
					/* Free! */
ds@1952
   890
					dispatch->OnHandleDestroy(type, pOther->object);
ds@1952
   891
					ReleasePrimHandle(pHandle->clone);
ds@1952
   892
				}
ds@1952
   893
				/* Unlink ourselves since we don't have a reference count */
ds@1952
   894
				ReleasePrimHandle(i);
ds@1952
   895
			} else {
ds@1952
   896
				/* If it's not a clone, we still have to check the reference count.
ds@1952
   897
				 * Either way, we'll be destroyed eventually because the handle types do not change.
ds@1952
   898
				 */
ds@1952
   899
				if (--pHandle->refcount == 0)
ds@1952
   900
				{
ds@1952
   901
					/* Free! */
ds@1952
   902
					dispatch->OnHandleDestroy(type, pHandle->object);
ds@1952
   903
					ReleasePrimHandle(i);
ds@1952
   904
				}
ds@1952
   905
			}
ds@1952
   906
			if (pType->opened == 0)
ds@1952
   907
			{
ds@1952
   908
				break;
ds@1952
   909
			}
ds@1952
   910
		}
ds@1952
   911
	}
ds@1952
   912
ds@1952
   913
	return true;
ds@1952
   914
}
ds@1952
   915
ds@1952
   916
bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
ds@1952
   917
{
ds@1952
   918
	if (pTypeAccess)
ds@1952
   919
	{
ds@1952
   920
		if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
ds@1952
   921
		{
ds@1952
   922
			return false;
ds@1952
   923
		}
ds@1952
   924
		pTypeAccess->access[HTypeAccess_Create] = false;
ds@1952
   925
		pTypeAccess->access[HTypeAccess_Inherit] = false;
ds@1952
   926
		pTypeAccess->ident = NULL;
ds@1952
   927
	}
ds@1952
   928
ds@1952
   929
	if (pHandleAccess)
ds@1952
   930
	{
ds@1952
   931
		if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
ds@1952
   932
		{
ds@1952
   933
			return false;
ds@1952
   934
		}
ds@1952
   935
ds@1952
   936
		pHandleAccess->access[HandleAccess_Clone] = 0;
ds@1952
   937
		pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
ds@1952
   938
		pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;
ds@1952
   939
	}
ds@1952
   940
ds@1952
   941
	return true;
ds@1952
   942
}
ds@1952
   943
ds@1952
   944
bool HandleSystem::TryAndFreeSomeHandles()
ds@1952
   945
{
ds@1952
   946
	IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
ds@1952
   947
	IPlugin *highest_owner = NULL;
ds@1952
   948
	unsigned int highest_handle_count = 0;
ds@1952
   949
ds@1952
   950
	/* Search all plugins */
ds@1952
   951
	while (pl_iter->MorePlugins())
ds@1952
   952
	{
ds@1952
   953
		IPlugin *plugin = pl_iter->GetPlugin();
ds@1952
   954
		IdentityToken_t *identity = plugin->GetIdentity();
ds@1952
   955
		unsigned int handle_count = 0;
ds@1952
   956
ds@1952
   957
		if (identity == NULL)
ds@1952
   958
		{
ds@1952
   959
			continue;
ds@1952
   960
		}
ds@1952
   961
ds@1952
   962
		/* Search all handles */
ds@1952
   963
		for (unsigned int i = 1; i <= m_HandleTail; i++)
ds@1952
   964
		{
ds@1952
   965
			if (m_Handles[i].set != HandleSet_Used)
ds@1952
   966
			{
ds@1952
   967
				continue;
ds@1952
   968
			}
ds@1952
   969
			if (m_Handles[i].owner == identity)
ds@1952
   970
			{
ds@1952
   971
				handle_count++;
ds@1952
   972
			}
ds@1952
   973
		}
ds@1952
   974
ds@1952
   975
		if (handle_count > highest_handle_count)
ds@1952
   976
		{
ds@1952
   977
			highest_owner = plugin;
ds@1952
   978
			highest_handle_count = handle_count;
ds@1952
   979
		}
ds@1952
   980
ds@1952
   981
		pl_iter->NextPlugin();
ds@1952
   982
	}
ds@1952
   983
ds@1952
   984
	if (highest_owner == NULL || highest_handle_count == 0)
ds@1952
   985
	{
ds@1952
   986
		return false;
ds@1952
   987
	}
ds@1952
   988
ds@1952
   989
	g_Logger.LogFatal("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
ds@1952
   990
	g_Logger.LogFatal("[SM] Reloading plugin to free %d handles.", highest_handle_count);
ds@1952
   991
	g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
ds@1952
   992
ds@1952
   993
	highest_owner->GetContext()->n_err = SP_ERROR_MEMACCESS;
ds@1952
   994
ds@1952
   995
	return g_PluginSys.UnloadPlugin(highest_owner);
ds@1952
   996
}
ds@1952
   997
ds@1952
   998
void HandleSystem::Dump(HANDLE_REPORTER rep)
ds@1952
   999
{
ds@1952
  1000
	unsigned int total_size = 0;
ds@1952
  1001
	rep("%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory");
ds@1952
  1002
	rep("--------------------------------------------------------------------------");
ds@1952
  1003
	for (unsigned int i = 1; i <= m_HandleTail; i++)
ds@1952
  1004
	{
ds@1952
  1005
		if (m_Handles[i].set != HandleSet_Used)
ds@1952
  1006
		{
ds@1952
  1007
			continue;
ds@1952
  1008
		}
ds@1952
  1009
		/* Get the index */
ds@1952
  1010
		unsigned int index = (m_Handles[i].serial << 16) | i;
ds@1952
  1011
		/* Determine the owner */
ds@1952
  1012
		const char *owner = "UNKNOWN";
ds@1952
  1013
		if (m_Handles[i].owner)
ds@1952
  1014
		{
ds@1952
  1015
			IdentityToken_t *pOwner = m_Handles[i].owner;
ds@1952
  1016
			if (pOwner == g_pCoreIdent)
ds@1952
  1017
			{
ds@1952
  1018
				owner = "CORE";
ds@1952
  1019
			}
ds@1952
  1020
			else if (pOwner == g_PluginSys.GetIdentity())
ds@1952
  1021
			{
ds@1952
  1022
				owner = "PLUGINSYS";
ds@1952
  1023
			}
ds@1952
  1024
			else
ds@1952
  1025
			{
ds@1952
  1026
				CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
ds@1952
  1027
				if (ext)
ds@1952
  1028
				{
ds@1952
  1029
					owner = ext->GetFilename();
ds@1952
  1030
				}
ds@1952
  1031
				else
ds@1952
  1032
				{
ds@1952
  1033
					CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
ds@1952
  1034
					if (pPlugin)
ds@1952
  1035
					{
ds@1952
  1036
						owner = pPlugin->GetFilename();
ds@1952
  1037
					}
ds@1952
  1038
				}
ds@1952
  1039
			}
ds@1952
  1040
		}
ds@1952
  1041
		else
ds@1952
  1042
		{
ds@1952
  1043
			owner = "NONE";
ds@1952
  1044
		}
ds@1952
  1045
		const char *type = "ANON";
ds@1952
  1046
		QHandleType *pType = &m_Types[m_Handles[i].type];
ds@1952
  1047
		unsigned int size = 0;
ds@1952
  1048
		if (pType->nameIdx != -1)
ds@1952
  1049
		{
ds@1952
  1050
			type = m_strtab->GetString(pType->nameIdx);
ds@1952
  1051
		}
ds@1952
  1052
		if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
ds@1952
  1053
			|| !pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size))
ds@1952
  1054
		{
ds@1952
  1055
			rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
ds@1952
  1056
		}
ds@1952
  1057
		else
ds@1952
  1058
		{
ds@1952
  1059
			char buffer[32];
ds@1952
  1060
			UTIL_Format(buffer, sizeof(buffer), "%d", size);
ds@1952
  1061
			rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
ds@1952
  1062
			total_size += size;
ds@1952
  1063
		}
ds@1952
  1064
	}
ds@1952
  1065
	rep("-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
ds@1952
  1066
}
ds@1952
  1067