core/systems/HandleSys.cpp
author David Anderson <dvander@alliedmods.net>
Sat Dec 16 22:27:18 2006 +0000 (2006-12-16)
changeset 218 cbc16328b1bf
child 222 8d009d0087f1
permissions -rw-r--r--
implemented and finalized initial HandleSystem API
dvander@218
     1
#include "HandleSys.h"
dvander@218
     2
#include "PluginSys.h"
dvander@218
     3
dvander@218
     4
HandleSystem g_HandleSys;
dvander@218
     5
dvander@218
     6
HandleSystem::HandleSystem()
dvander@218
     7
{
dvander@218
     8
	m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
dvander@218
     9
	memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
dvander@218
    10
dvander@218
    11
	m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
dvander@218
    12
	memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
dvander@218
    13
dvander@218
    14
	m_TypeLookup = sm_trie_create();
dvander@218
    15
	m_strtab = new BaseStringTable(512);
dvander@218
    16
dvander@218
    17
	m_TypeTail = 0;
dvander@218
    18
}
dvander@218
    19
dvander@218
    20
HandleSystem::~HandleSystem()
dvander@218
    21
{
dvander@218
    22
	delete [] m_Handles;
dvander@218
    23
	delete [] m_Types;
dvander@218
    24
	sm_trie_destroy(m_TypeLookup);
dvander@218
    25
	delete m_strtab;
dvander@218
    26
}
dvander@218
    27
dvander@218
    28
HandleType_t HandleSystem::CreateType(const char *name, IHandleTypeDispatch *dispatch)
dvander@218
    29
{
dvander@218
    30
	return CreateTypeEx(name, dispatch, 0, NULL);
dvander@218
    31
}
dvander@218
    32
dvander@218
    33
HandleType_t HandleSystem::CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch)
dvander@218
    34
{
dvander@218
    35
	return CreateTypeEx(name, dispatch, parent, NULL);
dvander@218
    36
}
dvander@218
    37
dvander@218
    38
HandleType_t HandleSystem::CreateTypeEx(const char *name, 
dvander@218
    39
										IHandleTypeDispatch *dispatch, 
dvander@218
    40
										HandleType_t parent, 
dvander@218
    41
										const HandleSecurity *security)
dvander@218
    42
{
dvander@218
    43
	if (!dispatch)
dvander@218
    44
	{
dvander@218
    45
		return 0;
dvander@218
    46
	}
dvander@218
    47
dvander@218
    48
	bool isChild = false;
dvander@218
    49
dvander@218
    50
	if (parent != 0)
dvander@218
    51
	{
dvander@218
    52
		isChild = true;
dvander@218
    53
		if (parent & HANDLESYS_SUBTYPE_MASK)
dvander@218
    54
		{
dvander@218
    55
			return 0;
dvander@218
    56
		}
dvander@218
    57
		if (parent >= HANDLESYS_TYPEARRAY_SIZE
dvander@218
    58
			|| m_Types[parent].dispatch != NULL
dvander@218
    59
			|| m_Types[parent].sec.all.canInherit == false)
dvander@218
    60
		{
dvander@218
    61
			return 0;
dvander@218
    62
		}
dvander@218
    63
	}
dvander@218
    64
dvander@218
    65
	if (!security)
dvander@218
    66
	{
dvander@218
    67
		if (isChild)
dvander@218
    68
		{
dvander@218
    69
			security = &m_Types[parent].sec;
dvander@218
    70
		} else {
dvander@218
    71
			static HandleSecurity def_h = {0, HandleAccess() };
dvander@218
    72
			security = &def_h;
dvander@218
    73
		}
dvander@218
    74
	}
dvander@218
    75
dvander@218
    76
	if (security->all.canCreate && sm_trie_retrieve(m_TypeLookup, name, NULL))
dvander@218
    77
	{
dvander@218
    78
		return 0;
dvander@218
    79
	}
dvander@218
    80
dvander@218
    81
	unsigned int index;
dvander@218
    82
dvander@218
    83
	if (isChild)
dvander@218
    84
	{
dvander@218
    85
		QHandleType *pParent = &m_Types[parent];
dvander@218
    86
		if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
dvander@218
    87
		{
dvander@218
    88
			return 0;
dvander@218
    89
		}
dvander@218
    90
		index = 0;
dvander@218
    91
		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
dvander@218
    92
		{
dvander@218
    93
			if (m_Types[parent + i].dispatch == NULL)
dvander@218
    94
			{
dvander@218
    95
				index = parent + i;
dvander@218
    96
				break;
dvander@218
    97
			}
dvander@218
    98
		}
dvander@218
    99
		if (!index)
dvander@218
   100
		{
dvander@218
   101
			return 0;
dvander@218
   102
		}
dvander@218
   103
		pParent->children++;
dvander@218
   104
	} else {
dvander@218
   105
		if (m_FreeTypes == 0)
dvander@218
   106
		{
dvander@218
   107
			/* Reserve another index */
dvander@218
   108
			if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
dvander@218
   109
			{
dvander@218
   110
				return 0;
dvander@218
   111
			} else {
dvander@218
   112
				m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
dvander@218
   113
				index = m_TypeTail;
dvander@218
   114
			}
dvander@218
   115
		} else {
dvander@218
   116
			/* The "free array" is compacted into the normal array for easiness */
dvander@218
   117
			index = m_Types[m_FreeTypes--].freeID;
dvander@218
   118
		}
dvander@218
   119
	}
dvander@218
   120
dvander@218
   121
	QHandleType *pType = &m_Types[index];
dvander@218
   122
	
dvander@218
   123
	pType->dispatch = dispatch;
dvander@218
   124
	if (name && name[0] != '\0')
dvander@218
   125
	{
dvander@218
   126
		pType->nameIdx = m_strtab->AddString(name);
dvander@218
   127
		sm_trie_insert(m_TypeLookup, name, (void *)pType);
dvander@218
   128
	} else {
dvander@218
   129
		pType->nameIdx = -1;
dvander@218
   130
	}
dvander@218
   131
	pType->sec = *security;
dvander@218
   132
	pType->opened = 0;
dvander@218
   133
dvander@218
   134
	if (!isChild)
dvander@218
   135
	{
dvander@218
   136
		pType->children = 0;
dvander@218
   137
	}
dvander@218
   138
dvander@218
   139
	return index;
dvander@218
   140
}
dvander@218
   141
dvander@218
   142
bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
dvander@218
   143
{
dvander@218
   144
	QHandleType *_type;
dvander@218
   145
dvander@218
   146
	if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
dvander@218
   147
	{
dvander@218
   148
		return false;
dvander@218
   149
	}
dvander@218
   150
dvander@218
   151
	unsigned int offset = _type - m_Types;
dvander@218
   152
dvander@218
   153
	if (type)
dvander@218
   154
	{
dvander@218
   155
		*type = offset;
dvander@218
   156
	}
dvander@218
   157
dvander@218
   158
	return true;
dvander@218
   159
}
dvander@218
   160
dvander@218
   161
Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t source, IdentityToken_t ident)
dvander@218
   162
{
dvander@218
   163
	if (!type 
dvander@218
   164
		|| type >= HANDLESYS_TYPEARRAY_SIZE
dvander@218
   165
		|| m_Types[type].dispatch == NULL)
dvander@218
   166
	{
dvander@218
   167
		return 0;
dvander@218
   168
	}
dvander@218
   169
dvander@218
   170
	/* Check the security of this handle */
dvander@218
   171
	QHandleType *pType = &m_Types[type];
dvander@218
   172
	if (!pType->sec.all.canCreate
dvander@218
   173
		&& pType->sec.owner != ident)
dvander@218
   174
	{
dvander@218
   175
		return 0;
dvander@218
   176
	}
dvander@218
   177
dvander@218
   178
	unsigned int handle = 0;
dvander@218
   179
	if (m_FreeHandles == 0)
dvander@218
   180
	{
dvander@218
   181
		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
dvander@218
   182
		{
dvander@218
   183
			return 0;
dvander@218
   184
		}
dvander@218
   185
		handle = ++m_HandleTail;
dvander@218
   186
	} else {
dvander@218
   187
		handle = m_Handles[m_FreeHandles--].freeID;
dvander@218
   188
	}
dvander@218
   189
dvander@218
   190
	QHandle *pHandle = &m_Handles[handle];
dvander@218
   191
dvander@218
   192
	pHandle->type = type;
dvander@218
   193
	pHandle->source = source;
dvander@218
   194
	pHandle->set = true;
dvander@218
   195
	pHandle->object = object;
dvander@218
   196
dvander@218
   197
	if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
dvander@218
   198
	{
dvander@218
   199
		m_HSerial = 1;
dvander@218
   200
	}
dvander@218
   201
	pHandle->serial = m_HSerial;
dvander@218
   202
dvander@218
   203
	Handle_t hash = pHandle->serial;
dvander@218
   204
	hash <<= 16;
dvander@218
   205
	hash |= handle;
dvander@218
   206
dvander@218
   207
	pType->opened++;
dvander@218
   208
dvander@218
   209
	return hash;
dvander@218
   210
}
dvander@218
   211
dvander@218
   212
Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, 
dvander@218
   213
										  void *object, 
dvander@218
   214
										  sp_context_t *ctx, 
dvander@218
   215
										  IdentityToken_t ident)
dvander@218
   216
{
dvander@218
   217
	IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx);
dvander@218
   218
dvander@218
   219
	return CreateHandle(type, object, pPlugin->GetIdentity(), ident);
dvander@218
   220
}
dvander@218
   221
dvander@218
   222
HandleError HandleSystem::DestroyHandle(Handle_t handle, IdentityToken_t ident)
dvander@218
   223
{
dvander@218
   224
	unsigned int serial = (handle >> 16);
dvander@218
   225
	unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
dvander@218
   226
dvander@218
   227
	if (index == 0 || index == 0xFFFF)
dvander@218
   228
	{
dvander@218
   229
		return HandleError_Index;
dvander@218
   230
	}
dvander@218
   231
dvander@218
   232
	QHandle *pHandle = &m_Handles[index];
dvander@218
   233
	QHandleType *pType = &m_Types[pHandle->type];
dvander@218
   234
dvander@218
   235
	if (!pType->sec.all.canDelete
dvander@218
   236
		&& pType->sec.owner != ident)
dvander@218
   237
	{
dvander@218
   238
		return HandleError_Access;
dvander@218
   239
	}
dvander@218
   240
	if (!pHandle->set)
dvander@218
   241
	{
dvander@218
   242
		return HandleError_Freed;
dvander@218
   243
	}
dvander@218
   244
	if (pHandle->serial != serial)
dvander@218
   245
	{
dvander@218
   246
		return HandleError_Changed;
dvander@218
   247
	}
dvander@218
   248
dvander@218
   249
	pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
dvander@218
   250
	pType->opened--;
dvander@218
   251
	pHandle->set = false;
dvander@218
   252
	m_Handles[++m_FreeTypes].freeID = index;
dvander@218
   253
dvander@218
   254
	return HandleError_None;
dvander@218
   255
}
dvander@218
   256
dvander@218
   257
inline HandleType_t TypeParent(HandleType_t type)
dvander@218
   258
{
dvander@218
   259
	return (type & ~HANDLESYS_SUBTYPE_MASK);
dvander@218
   260
}
dvander@218
   261
dvander@218
   262
HandleError HandleSystem::ReadHandle(Handle_t handle, 
dvander@218
   263
									 HandleType_t type, 
dvander@218
   264
									 IdentityToken_t ident, 
dvander@218
   265
									 void **object)
dvander@218
   266
{
dvander@218
   267
	unsigned int serial = (handle >> 16);
dvander@218
   268
	unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
dvander@218
   269
dvander@218
   270
	if (index == 0 || index == 0xFFFF)
dvander@218
   271
	{
dvander@218
   272
		return HandleError_Index;
dvander@218
   273
	}
dvander@218
   274
dvander@218
   275
	QHandle *pHandle = &m_Handles[index];
dvander@218
   276
dvander@218
   277
	/* Do sanity checks first */
dvander@218
   278
	if (!pHandle->set)
dvander@218
   279
	{
dvander@218
   280
		return HandleError_Freed;
dvander@218
   281
	}
dvander@218
   282
	if (pHandle->serial != serial)
dvander@218
   283
	{
dvander@218
   284
		return HandleError_Changed;
dvander@218
   285
	}
dvander@218
   286
dvander@218
   287
	/* Check the type inheritance */
dvander@218
   288
	if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
dvander@218
   289
	{
dvander@218
   290
		if (pHandle->type != type
dvander@218
   291
			&& (TypeParent(pHandle->type) != TypeParent(type)))
dvander@218
   292
		{
dvander@218
   293
			return HandleError_Type;
dvander@218
   294
		}
dvander@218
   295
	} else {
dvander@218
   296
		if (pHandle->type != type)
dvander@218
   297
		{
dvander@218
   298
			return HandleError_Type;
dvander@218
   299
		}
dvander@218
   300
	}
dvander@218
   301
dvander@218
   302
	/* Now do security checks */
dvander@218
   303
	QHandleType *pType = &m_Types[pHandle->type];
dvander@218
   304
	if (!pType->sec.all.canRead
dvander@218
   305
		&& pType->sec.owner != ident)
dvander@218
   306
	{
dvander@218
   307
		return HandleError_Access;
dvander@218
   308
	}
dvander@218
   309
dvander@218
   310
	if (object)
dvander@218
   311
	{
dvander@218
   312
		*object = pHandle->object;
dvander@218
   313
	}
dvander@218
   314
dvander@218
   315
	return HandleError_None;
dvander@218
   316
}
dvander@218
   317
dvander@218
   318
bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident)
dvander@218
   319
{
dvander@218
   320
	if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
dvander@218
   321
	{
dvander@218
   322
		return false;
dvander@218
   323
	}
dvander@218
   324
dvander@218
   325
	QHandleType *pType = &m_Types[type];
dvander@218
   326
dvander@218
   327
	if (pType->sec.owner && pType->sec.owner != ident)
dvander@218
   328
	{
dvander@218
   329
		return false;
dvander@218
   330
	}
dvander@218
   331
dvander@218
   332
	if (pType->dispatch == NULL)
dvander@218
   333
	{
dvander@218
   334
		return false;
dvander@218
   335
	}
dvander@218
   336
dvander@218
   337
	/* Remove children if we have to */
dvander@218
   338
	if (!(type & HANDLESYS_SUBTYPE_MASK))
dvander@218
   339
	{
dvander@218
   340
		QHandleType *childType;
dvander@218
   341
		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
dvander@218
   342
		{
dvander@218
   343
			childType = &m_Types[type + i];
dvander@218
   344
			if (childType->dispatch)
dvander@218
   345
			{
dvander@218
   346
				RemoveType(type + i, childType->sec.owner);
dvander@218
   347
			}
dvander@218
   348
		}
dvander@218
   349
		/* Link us into the free chain */
dvander@218
   350
		m_Types[++m_FreeTypes].freeID = type;
dvander@218
   351
	}
dvander@218
   352
dvander@218
   353
	/* Invalidate the type now */
dvander@218
   354
	IHandleTypeDispatch *dispatch = pType->dispatch;
dvander@218
   355
	pType->dispatch = NULL;
dvander@218
   356
dvander@218
   357
	/* Make sure nothing is using this type. */
dvander@218
   358
	if (pType->opened)
dvander@218
   359
	{
dvander@218
   360
		QHandle *pHandle;
dvander@218
   361
		for (unsigned int i=1; i<=HANDLESYS_MAX_HANDLES; i++)
dvander@218
   362
		{
dvander@218
   363
			pHandle = &m_Handles[i];
dvander@218
   364
			if (!pHandle->set || pHandle->type != type)
dvander@218
   365
			{
dvander@218
   366
				continue;
dvander@218
   367
			}
dvander@218
   368
			dispatch->OnHandleDestroy(type, pHandle->object);
dvander@218
   369
			pHandle->set = false;
dvander@218
   370
			m_Handles[++m_FreeHandles].freeID = i;
dvander@218
   371
			if (--pType->opened == 0)
dvander@218
   372
			{
dvander@218
   373
				break;
dvander@218
   374
			}
dvander@218
   375
		}
dvander@218
   376
	}
dvander@218
   377
dvander@218
   378
	return true;
dvander@218
   379
}