1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/systems/HandleSys.cpp Sat Dec 16 22:27:18 2006 +0000
1.3 @@ -0,0 +1,379 @@
1.4 +#include "HandleSys.h"
1.5 +#include "PluginSys.h"
1.6 +
1.7 +HandleSystem g_HandleSys;
1.8 +
1.9 +HandleSystem::HandleSystem()
1.10 +{
1.11 + m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
1.12 + memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
1.13 +
1.14 + m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
1.15 + memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
1.16 +
1.17 + m_TypeLookup = sm_trie_create();
1.18 + m_strtab = new BaseStringTable(512);
1.19 +
1.20 + m_TypeTail = 0;
1.21 +}
1.22 +
1.23 +HandleSystem::~HandleSystem()
1.24 +{
1.25 + delete [] m_Handles;
1.26 + delete [] m_Types;
1.27 + sm_trie_destroy(m_TypeLookup);
1.28 + delete m_strtab;
1.29 +}
1.30 +
1.31 +HandleType_t HandleSystem::CreateType(const char *name, IHandleTypeDispatch *dispatch)
1.32 +{
1.33 + return CreateTypeEx(name, dispatch, 0, NULL);
1.34 +}
1.35 +
1.36 +HandleType_t HandleSystem::CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch)
1.37 +{
1.38 + return CreateTypeEx(name, dispatch, parent, NULL);
1.39 +}
1.40 +
1.41 +HandleType_t HandleSystem::CreateTypeEx(const char *name,
1.42 + IHandleTypeDispatch *dispatch,
1.43 + HandleType_t parent,
1.44 + const HandleSecurity *security)
1.45 +{
1.46 + if (!dispatch)
1.47 + {
1.48 + return 0;
1.49 + }
1.50 +
1.51 + bool isChild = false;
1.52 +
1.53 + if (parent != 0)
1.54 + {
1.55 + isChild = true;
1.56 + if (parent & HANDLESYS_SUBTYPE_MASK)
1.57 + {
1.58 + return 0;
1.59 + }
1.60 + if (parent >= HANDLESYS_TYPEARRAY_SIZE
1.61 + || m_Types[parent].dispatch != NULL
1.62 + || m_Types[parent].sec.all.canInherit == false)
1.63 + {
1.64 + return 0;
1.65 + }
1.66 + }
1.67 +
1.68 + if (!security)
1.69 + {
1.70 + if (isChild)
1.71 + {
1.72 + security = &m_Types[parent].sec;
1.73 + } else {
1.74 + static HandleSecurity def_h = {0, HandleAccess() };
1.75 + security = &def_h;
1.76 + }
1.77 + }
1.78 +
1.79 + if (security->all.canCreate && sm_trie_retrieve(m_TypeLookup, name, NULL))
1.80 + {
1.81 + return 0;
1.82 + }
1.83 +
1.84 + unsigned int index;
1.85 +
1.86 + if (isChild)
1.87 + {
1.88 + QHandleType *pParent = &m_Types[parent];
1.89 + if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
1.90 + {
1.91 + return 0;
1.92 + }
1.93 + index = 0;
1.94 + for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
1.95 + {
1.96 + if (m_Types[parent + i].dispatch == NULL)
1.97 + {
1.98 + index = parent + i;
1.99 + break;
1.100 + }
1.101 + }
1.102 + if (!index)
1.103 + {
1.104 + return 0;
1.105 + }
1.106 + pParent->children++;
1.107 + } else {
1.108 + if (m_FreeTypes == 0)
1.109 + {
1.110 + /* Reserve another index */
1.111 + if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
1.112 + {
1.113 + return 0;
1.114 + } else {
1.115 + m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
1.116 + index = m_TypeTail;
1.117 + }
1.118 + } else {
1.119 + /* The "free array" is compacted into the normal array for easiness */
1.120 + index = m_Types[m_FreeTypes--].freeID;
1.121 + }
1.122 + }
1.123 +
1.124 + QHandleType *pType = &m_Types[index];
1.125 +
1.126 + pType->dispatch = dispatch;
1.127 + if (name && name[0] != '\0')
1.128 + {
1.129 + pType->nameIdx = m_strtab->AddString(name);
1.130 + sm_trie_insert(m_TypeLookup, name, (void *)pType);
1.131 + } else {
1.132 + pType->nameIdx = -1;
1.133 + }
1.134 + pType->sec = *security;
1.135 + pType->opened = 0;
1.136 +
1.137 + if (!isChild)
1.138 + {
1.139 + pType->children = 0;
1.140 + }
1.141 +
1.142 + return index;
1.143 +}
1.144 +
1.145 +bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
1.146 +{
1.147 + QHandleType *_type;
1.148 +
1.149 + if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
1.150 + {
1.151 + return false;
1.152 + }
1.153 +
1.154 + unsigned int offset = _type - m_Types;
1.155 +
1.156 + if (type)
1.157 + {
1.158 + *type = offset;
1.159 + }
1.160 +
1.161 + return true;
1.162 +}
1.163 +
1.164 +Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t source, IdentityToken_t ident)
1.165 +{
1.166 + if (!type
1.167 + || type >= HANDLESYS_TYPEARRAY_SIZE
1.168 + || m_Types[type].dispatch == NULL)
1.169 + {
1.170 + return 0;
1.171 + }
1.172 +
1.173 + /* Check the security of this handle */
1.174 + QHandleType *pType = &m_Types[type];
1.175 + if (!pType->sec.all.canCreate
1.176 + && pType->sec.owner != ident)
1.177 + {
1.178 + return 0;
1.179 + }
1.180 +
1.181 + unsigned int handle = 0;
1.182 + if (m_FreeHandles == 0)
1.183 + {
1.184 + if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
1.185 + {
1.186 + return 0;
1.187 + }
1.188 + handle = ++m_HandleTail;
1.189 + } else {
1.190 + handle = m_Handles[m_FreeHandles--].freeID;
1.191 + }
1.192 +
1.193 + QHandle *pHandle = &m_Handles[handle];
1.194 +
1.195 + pHandle->type = type;
1.196 + pHandle->source = source;
1.197 + pHandle->set = true;
1.198 + pHandle->object = object;
1.199 +
1.200 + if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
1.201 + {
1.202 + m_HSerial = 1;
1.203 + }
1.204 + pHandle->serial = m_HSerial;
1.205 +
1.206 + Handle_t hash = pHandle->serial;
1.207 + hash <<= 16;
1.208 + hash |= handle;
1.209 +
1.210 + pType->opened++;
1.211 +
1.212 + return hash;
1.213 +}
1.214 +
1.215 +Handle_t HandleSystem::CreateScriptHandle(HandleType_t type,
1.216 + void *object,
1.217 + sp_context_t *ctx,
1.218 + IdentityToken_t ident)
1.219 +{
1.220 + IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx);
1.221 +
1.222 + return CreateHandle(type, object, pPlugin->GetIdentity(), ident);
1.223 +}
1.224 +
1.225 +HandleError HandleSystem::DestroyHandle(Handle_t handle, IdentityToken_t ident)
1.226 +{
1.227 + unsigned int serial = (handle >> 16);
1.228 + unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
1.229 +
1.230 + if (index == 0 || index == 0xFFFF)
1.231 + {
1.232 + return HandleError_Index;
1.233 + }
1.234 +
1.235 + QHandle *pHandle = &m_Handles[index];
1.236 + QHandleType *pType = &m_Types[pHandle->type];
1.237 +
1.238 + if (!pType->sec.all.canDelete
1.239 + && pType->sec.owner != ident)
1.240 + {
1.241 + return HandleError_Access;
1.242 + }
1.243 + if (!pHandle->set)
1.244 + {
1.245 + return HandleError_Freed;
1.246 + }
1.247 + if (pHandle->serial != serial)
1.248 + {
1.249 + return HandleError_Changed;
1.250 + }
1.251 +
1.252 + pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
1.253 + pType->opened--;
1.254 + pHandle->set = false;
1.255 + m_Handles[++m_FreeTypes].freeID = index;
1.256 +
1.257 + return HandleError_None;
1.258 +}
1.259 +
1.260 +inline HandleType_t TypeParent(HandleType_t type)
1.261 +{
1.262 + return (type & ~HANDLESYS_SUBTYPE_MASK);
1.263 +}
1.264 +
1.265 +HandleError HandleSystem::ReadHandle(Handle_t handle,
1.266 + HandleType_t type,
1.267 + IdentityToken_t ident,
1.268 + void **object)
1.269 +{
1.270 + unsigned int serial = (handle >> 16);
1.271 + unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
1.272 +
1.273 + if (index == 0 || index == 0xFFFF)
1.274 + {
1.275 + return HandleError_Index;
1.276 + }
1.277 +
1.278 + QHandle *pHandle = &m_Handles[index];
1.279 +
1.280 + /* Do sanity checks first */
1.281 + if (!pHandle->set)
1.282 + {
1.283 + return HandleError_Freed;
1.284 + }
1.285 + if (pHandle->serial != serial)
1.286 + {
1.287 + return HandleError_Changed;
1.288 + }
1.289 +
1.290 + /* Check the type inheritance */
1.291 + if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
1.292 + {
1.293 + if (pHandle->type != type
1.294 + && (TypeParent(pHandle->type) != TypeParent(type)))
1.295 + {
1.296 + return HandleError_Type;
1.297 + }
1.298 + } else {
1.299 + if (pHandle->type != type)
1.300 + {
1.301 + return HandleError_Type;
1.302 + }
1.303 + }
1.304 +
1.305 + /* Now do security checks */
1.306 + QHandleType *pType = &m_Types[pHandle->type];
1.307 + if (!pType->sec.all.canRead
1.308 + && pType->sec.owner != ident)
1.309 + {
1.310 + return HandleError_Access;
1.311 + }
1.312 +
1.313 + if (object)
1.314 + {
1.315 + *object = pHandle->object;
1.316 + }
1.317 +
1.318 + return HandleError_None;
1.319 +}
1.320 +
1.321 +bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident)
1.322 +{
1.323 + if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
1.324 + {
1.325 + return false;
1.326 + }
1.327 +
1.328 + QHandleType *pType = &m_Types[type];
1.329 +
1.330 + if (pType->sec.owner && pType->sec.owner != ident)
1.331 + {
1.332 + return false;
1.333 + }
1.334 +
1.335 + if (pType->dispatch == NULL)
1.336 + {
1.337 + return false;
1.338 + }
1.339 +
1.340 + /* Remove children if we have to */
1.341 + if (!(type & HANDLESYS_SUBTYPE_MASK))
1.342 + {
1.343 + QHandleType *childType;
1.344 + for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
1.345 + {
1.346 + childType = &m_Types[type + i];
1.347 + if (childType->dispatch)
1.348 + {
1.349 + RemoveType(type + i, childType->sec.owner);
1.350 + }
1.351 + }
1.352 + /* Link us into the free chain */
1.353 + m_Types[++m_FreeTypes].freeID = type;
1.354 + }
1.355 +
1.356 + /* Invalidate the type now */
1.357 + IHandleTypeDispatch *dispatch = pType->dispatch;
1.358 + pType->dispatch = NULL;
1.359 +
1.360 + /* Make sure nothing is using this type. */
1.361 + if (pType->opened)
1.362 + {
1.363 + QHandle *pHandle;
1.364 + for (unsigned int i=1; i<=HANDLESYS_MAX_HANDLES; i++)
1.365 + {
1.366 + pHandle = &m_Handles[i];
1.367 + if (!pHandle->set || pHandle->type != type)
1.368 + {
1.369 + continue;
1.370 + }
1.371 + dispatch->OnHandleDestroy(type, pHandle->object);
1.372 + pHandle->set = false;
1.373 + m_Handles[++m_FreeHandles].freeID = i;
1.374 + if (--pType->opened == 0)
1.375 + {
1.376 + break;
1.377 + }
1.378 + }
1.379 + }
1.380 +
1.381 + return true;
1.382 +}