diff -r e61c933190a2 -r cbc16328b1bf core/systems/HandleSys.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/systems/HandleSys.cpp Sat Dec 16 22:27:18 2006 +0000 @@ -0,0 +1,379 @@ +#include "HandleSys.h" +#include "PluginSys.h" + +HandleSystem g_HandleSys; + +HandleSystem::HandleSystem() +{ + m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1]; + memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1)); + + m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE]; + memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE); + + m_TypeLookup = sm_trie_create(); + m_strtab = new BaseStringTable(512); + + m_TypeTail = 0; +} + +HandleSystem::~HandleSystem() +{ + delete [] m_Handles; + delete [] m_Types; + sm_trie_destroy(m_TypeLookup); + delete m_strtab; +} + +HandleType_t HandleSystem::CreateType(const char *name, IHandleTypeDispatch *dispatch) +{ + return CreateTypeEx(name, dispatch, 0, NULL); +} + +HandleType_t HandleSystem::CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch) +{ + return CreateTypeEx(name, dispatch, parent, NULL); +} + +HandleType_t HandleSystem::CreateTypeEx(const char *name, + IHandleTypeDispatch *dispatch, + HandleType_t parent, + const HandleSecurity *security) +{ + if (!dispatch) + { + return 0; + } + + bool isChild = false; + + if (parent != 0) + { + isChild = true; + if (parent & HANDLESYS_SUBTYPE_MASK) + { + return 0; + } + if (parent >= HANDLESYS_TYPEARRAY_SIZE + || m_Types[parent].dispatch != NULL + || m_Types[parent].sec.all.canInherit == false) + { + return 0; + } + } + + if (!security) + { + if (isChild) + { + security = &m_Types[parent].sec; + } else { + static HandleSecurity def_h = {0, HandleAccess() }; + security = &def_h; + } + } + + if (security->all.canCreate && sm_trie_retrieve(m_TypeLookup, name, NULL)) + { + return 0; + } + + unsigned int index; + + if (isChild) + { + QHandleType *pParent = &m_Types[parent]; + if (pParent->children >= HANDLESYS_MAX_SUBTYPES) + { + return 0; + } + index = 0; + for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++) + { + if (m_Types[parent + i].dispatch == NULL) + { + index = parent + i; + break; + } + } + if (!index) + { + return 0; + } + pParent->children++; + } else { + if (m_FreeTypes == 0) + { + /* Reserve another index */ + if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE) + { + return 0; + } else { + m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1); + index = m_TypeTail; + } + } else { + /* The "free array" is compacted into the normal array for easiness */ + index = m_Types[m_FreeTypes--].freeID; + } + } + + QHandleType *pType = &m_Types[index]; + + pType->dispatch = dispatch; + if (name && name[0] != '\0') + { + pType->nameIdx = m_strtab->AddString(name); + sm_trie_insert(m_TypeLookup, name, (void *)pType); + } else { + pType->nameIdx = -1; + } + pType->sec = *security; + pType->opened = 0; + + if (!isChild) + { + pType->children = 0; + } + + return index; +} + +bool HandleSystem::FindHandleType(const char *name, HandleType_t *type) +{ + QHandleType *_type; + + if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type)) + { + return false; + } + + unsigned int offset = _type - m_Types; + + if (type) + { + *type = offset; + } + + return true; +} + +Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t source, IdentityToken_t ident) +{ + if (!type + || type >= HANDLESYS_TYPEARRAY_SIZE + || m_Types[type].dispatch == NULL) + { + return 0; + } + + /* Check the security of this handle */ + QHandleType *pType = &m_Types[type]; + if (!pType->sec.all.canCreate + && pType->sec.owner != ident) + { + return 0; + } + + unsigned int handle = 0; + if (m_FreeHandles == 0) + { + if (m_HandleTail >= HANDLESYS_MAX_HANDLES) + { + return 0; + } + handle = ++m_HandleTail; + } else { + handle = m_Handles[m_FreeHandles--].freeID; + } + + QHandle *pHandle = &m_Handles[handle]; + + pHandle->type = type; + pHandle->source = source; + pHandle->set = true; + pHandle->object = object; + + if (++m_HSerial >= HANDLESYS_MAX_SERIALS) + { + m_HSerial = 1; + } + pHandle->serial = m_HSerial; + + Handle_t hash = pHandle->serial; + hash <<= 16; + hash |= handle; + + pType->opened++; + + return hash; +} + +Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, + void *object, + sp_context_t *ctx, + IdentityToken_t ident) +{ + IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx); + + return CreateHandle(type, object, pPlugin->GetIdentity(), ident); +} + +HandleError HandleSystem::DestroyHandle(Handle_t handle, IdentityToken_t ident) +{ + unsigned int serial = (handle >> 16); + unsigned int index = (handle & HANDLESYS_HANDLE_MASK); + + if (index == 0 || index == 0xFFFF) + { + return HandleError_Index; + } + + QHandle *pHandle = &m_Handles[index]; + QHandleType *pType = &m_Types[pHandle->type]; + + if (!pType->sec.all.canDelete + && pType->sec.owner != ident) + { + return HandleError_Access; + } + if (!pHandle->set) + { + return HandleError_Freed; + } + if (pHandle->serial != serial) + { + return HandleError_Changed; + } + + pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); + pType->opened--; + pHandle->set = false; + m_Handles[++m_FreeTypes].freeID = index; + + return HandleError_None; +} + +inline HandleType_t TypeParent(HandleType_t type) +{ + return (type & ~HANDLESYS_SUBTYPE_MASK); +} + +HandleError HandleSystem::ReadHandle(Handle_t handle, + HandleType_t type, + IdentityToken_t ident, + void **object) +{ + unsigned int serial = (handle >> 16); + unsigned int index = (handle & HANDLESYS_HANDLE_MASK); + + if (index == 0 || index == 0xFFFF) + { + return HandleError_Index; + } + + QHandle *pHandle = &m_Handles[index]; + + /* Do sanity checks first */ + if (!pHandle->set) + { + return HandleError_Freed; + } + if (pHandle->serial != serial) + { + return HandleError_Changed; + } + + /* Check the type inheritance */ + if (pHandle->type & HANDLESYS_SUBTYPE_MASK) + { + if (pHandle->type != type + && (TypeParent(pHandle->type) != TypeParent(type))) + { + return HandleError_Type; + } + } else { + if (pHandle->type != type) + { + return HandleError_Type; + } + } + + /* Now do security checks */ + QHandleType *pType = &m_Types[pHandle->type]; + if (!pType->sec.all.canRead + && pType->sec.owner != ident) + { + return HandleError_Access; + } + + if (object) + { + *object = pHandle->object; + } + + return HandleError_None; +} + +bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident) +{ + if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE) + { + return false; + } + + QHandleType *pType = &m_Types[type]; + + if (pType->sec.owner && pType->sec.owner != ident) + { + return false; + } + + if (pType->dispatch == NULL) + { + return false; + } + + /* Remove children if we have to */ + if (!(type & HANDLESYS_SUBTYPE_MASK)) + { + QHandleType *childType; + for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++) + { + childType = &m_Types[type + i]; + if (childType->dispatch) + { + RemoveType(type + i, childType->sec.owner); + } + } + /* Link us into the free chain */ + m_Types[++m_FreeTypes].freeID = type; + } + + /* Invalidate the type now */ + IHandleTypeDispatch *dispatch = pType->dispatch; + pType->dispatch = NULL; + + /* Make sure nothing is using this type. */ + if (pType->opened) + { + QHandle *pHandle; + for (unsigned int i=1; i<=HANDLESYS_MAX_HANDLES; i++) + { + pHandle = &m_Handles[i]; + if (!pHandle->set || pHandle->type != type) + { + continue; + } + dispatch->OnHandleDestroy(type, pHandle->object); + pHandle->set = false; + m_Handles[++m_FreeHandles].freeID = i; + if (--pType->opened == 0) + { + break; + } + } + } + + return true; +}