diff -r 4edce76aefe3 -r 4c93f74cae51 core/logic/ShareSys.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/logic/ShareSys.cpp Fri Mar 29 11:37:29 2013 -0700
@@ -0,0 +1,611 @@
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * SourceMod
+ * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
+ * =============================================================================
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 3.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id$
+ */
+
+#include "ShareSys.h"
+#include "ExtensionSys.h"
+#include
+#include "common_logic.h"
+#include "PluginSys.h"
+#include "HandleSys.h"
+
+ShareSystem g_ShareSys;
+static unsigned int g_mark_serial = 0;
+
+ShareSystem::ShareSystem()
+{
+ m_IdentRoot.ident = 0;
+ m_TypeRoot = 0;
+ m_IfaceType = 0;
+ m_CoreType = 0;
+}
+
+IdentityToken_t *ShareSystem::CreateCoreIdentity()
+{
+ if (!m_CoreType)
+ {
+ m_CoreType = CreateIdentType("CORE");
+ }
+
+ return CreateIdentity(m_CoreType, this);
+}
+
+void ShareSystem::Initialize()
+{
+ TypeAccess sec;
+
+ handlesys->InitAccessDefaults(&sec, NULL);
+ sec.ident = GetIdentRoot();
+
+ m_TypeRoot = handlesys->CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
+ m_IfaceType = handlesys->CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
+
+ /* Initialize our static identity handle */
+ m_IdentRoot.ident = handlesys->CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
+
+ /* Add the Handle System and others... they are too innocent and pure to do it themselves */
+ AddInterface(NULL, handlesys);
+ AddInterface(NULL, libsys);
+}
+
+void ShareSystem::OnSourceModShutdown()
+{
+ if (m_CoreType)
+ {
+ handlesys->RemoveType(m_CoreType, GetIdentRoot());
+ }
+
+ handlesys->RemoveType(m_IfaceType, GetIdentRoot());
+ handlesys->RemoveType(m_TypeRoot, GetIdentRoot());
+}
+
+IdentityType_t ShareSystem::FindIdentType(const char *name)
+{
+ HandleType_t type;
+
+ if (handlesys->FindHandleType(name, &type))
+ {
+ if (g_HandleSys.TypeCheck(type, m_TypeRoot))
+ {
+ return type;
+ }
+ }
+
+ return 0;
+}
+
+IdentityType_t ShareSystem::CreateIdentType(const char *name)
+{
+ if (!m_TypeRoot)
+ {
+ return 0;
+ }
+
+ return handlesys->CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
+}
+
+void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
+{
+ /* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
+}
+
+IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
+{
+ if (!m_TypeRoot)
+ {
+ return 0;
+ }
+
+ /* :TODO: Cache? */
+ IdentityToken_t *pToken = new IdentityToken_t;
+
+ HandleSecurity sec;
+ sec.pOwner = sec.pIdentity = GetIdentRoot();
+
+ pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
+ pToken->ptr = ptr;
+ pToken->type = type;
+
+ return pToken;
+}
+
+bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
+{
+ if (!iface)
+ {
+ return false;
+ }
+
+ IfaceInfo info;
+
+ info.owner = myself;
+ info.iface = iface;
+
+ m_Interfaces.push_back(info);
+
+ return true;
+}
+
+bool ShareSystem::RequestInterface(const char *iface_name,
+ unsigned int iface_vers,
+ IExtension *myself,
+ SMInterface **pIface)
+{
+ /* See if the interface exists */
+ List::iterator iter;
+ SMInterface *iface;
+ IExtension *iface_owner;
+ bool found = false;
+ for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
+ {
+ IfaceInfo &info = (*iter);
+ iface = info.iface;
+ if (strcmp(iface->GetInterfaceName(), iface_name) == 0)
+ {
+ if (iface->GetInterfaceVersion() == iface_vers
+ || iface->IsVersionCompatible(iface_vers))
+ {
+ iface_owner = info.owner;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return false;
+ }
+
+ /* Add a dependency node */
+ if (iface_owner)
+ {
+ IfaceInfo info;
+ info.iface = iface;
+ info.owner = iface_owner;
+ g_Extensions.BindDependency(myself, &info);
+ }
+
+ if (pIface)
+ {
+ *pIface = iface;
+ }
+
+ return true;
+}
+
+void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
+{
+ CNativeOwner *pOwner;
+
+ pOwner = g_Extensions.GetNativeOwner(myself);
+
+ pOwner->AddNatives(natives);
+}
+
+void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
+{
+ HandleSecurity sec;
+
+ sec.pOwner = GetIdentRoot();
+ sec.pIdentity = GetIdentRoot();
+
+ handlesys->FreeHandle(identity->ident, &sec);
+ delete identity;
+}
+
+void ShareSystem::DestroyIdentType(IdentityType_t type)
+{
+ handlesys->RemoveType(type, GetIdentRoot());
+}
+
+void ShareSystem::RemoveInterfaces(IExtension *pExtension)
+{
+ List::iterator iter = m_Interfaces.begin();
+
+ while (iter != m_Interfaces.end())
+ {
+ if ((*iter).owner == pExtension)
+ {
+ iter = m_Interfaces.erase(iter);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+}
+
+void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload)
+{
+ g_Extensions.AddDependency(myself, filename, require, autoload);
+}
+
+void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
+{
+ g_Extensions.AddLibrary(myself, name);
+}
+
+void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
+{
+ unsigned int i;
+ NativeEntry *pEntry;
+ CNativeOwner *pOwner;
+
+ pOwner = g_Extensions.GetNativeOwner(myself);
+
+ for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
+ {
+ if ((pEntry = FindNative(natives[i].name)) == NULL)
+ {
+ continue;
+ }
+
+ if (pEntry->owner != &g_CoreNatives)
+ {
+ continue;
+ }
+
+ if (pEntry->replacement.owner != NULL)
+ {
+ continue;
+ }
+
+ /* Now it's safe to add the override */
+ pEntry->replacement.func = natives[i].func;
+ pEntry->replacement.owner = pOwner;
+ pOwner->AddReplacedNative(pEntry);
+ }
+}
+
+NativeEntry *ShareSystem::FindNative(const char *name)
+{
+ NativeEntry **ppEntry;
+
+ if ((ppEntry = m_NtvCache.retrieve(name)) == NULL)
+ {
+ return NULL;
+ }
+
+ return *ppEntry;
+}
+
+void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
+{
+ NativeEntry *pEntry;
+ sp_native_t *native;
+ uint32_t i, native_count;
+ IPluginContext *pContext;
+
+ pContext = pPlugin->GetBaseContext();
+
+ /* Generate a new serial ID, mark our dependencies with it. */
+ g_mark_serial++;
+ pPlugin->PropagateMarkSerial(g_mark_serial);
+
+ native_count = pContext->GetNativesNum();
+ for (i = 0; i < native_count; i++)
+ {
+ if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
+ {
+ continue;
+ }
+
+ /* If we're bound, check if there is a replacement available.
+ * If not, this native is totally finalized.
+ */
+ if (native->status == SP_NATIVE_BOUND)
+ {
+ pEntry = (NativeEntry *)native->user;
+ assert(pEntry != NULL);
+ if (pEntry->replacement.owner == NULL
+ || (pEntry->replacement.owner != NULL
+ && pEntry->replacement.func == native->pfn))
+ {
+ continue;
+ }
+ }
+ /* Otherwise, the native must be in our cache. */
+ else if ((pEntry = FindNative(native->name)) == NULL)
+ {
+ continue;
+ }
+
+ if (bCoreOnly && pEntry->owner != &g_CoreNatives)
+ {
+ continue;
+ }
+
+ BindNativeToPlugin(pPlugin, native, i, pEntry);
+ }
+}
+
+void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry)
+{
+ uint32_t i;
+ sp_native_t *native;
+ IPluginContext *pContext;
+
+ pContext = pPlugin->GetBaseContext();
+
+ if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE)
+ {
+ return;
+ }
+ if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
+ {
+ return;
+ }
+
+ if (native->status == SP_NATIVE_BOUND)
+ {
+ return;
+ }
+
+ BindNativeToPlugin(pPlugin, native, i, pEntry);
+}
+
+void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin,
+ sp_native_t *native,
+ uint32_t index,
+ NativeEntry *pEntry)
+{
+ /* Mark as bound... we do the rest next. */
+ native->status = SP_NATIVE_BOUND;
+ native->user = pEntry;
+
+ /* See if a replacement is available. */
+ if (pEntry->replacement.owner != NULL)
+ {
+ /* Perform a replacement bind. */
+ native->pfn = pEntry->replacement.func;
+ pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry));
+ }
+ else
+ {
+ /* Perform a normal bind. */
+ native->pfn = pEntry->func;
+
+ /* We don't bother with dependency crap if the owner is Core. */
+ if (pEntry->owner != &g_CoreNatives)
+ {
+ /* The native is optional, this is a special case */
+ if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
+ {
+ /* Only add if there is a valid owner. */
+ if (pEntry->owner != NULL)
+ {
+ pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
+ }
+ else
+ {
+ native->status = SP_NATIVE_UNBOUND;
+ }
+ }
+ /* Otherwise, we're a strong dependent and not a weak one */
+ else
+ {
+ /* See if this has already been marked as a dependent.
+ * If it has, it means this relationship has already occurred,
+ * and there is no reason to do it again.
+ */
+ if (pEntry->owner != pPlugin->ToNativeOwner()
+ && pEntry->owner->GetMarkSerial() != g_mark_serial)
+ {
+ /* This has not been marked as a dependency yet */
+ //pPlugin->AddDependency(pEntry->owner);
+ pEntry->owner->AddDependent(pPlugin);
+ pEntry->owner->SetMarkSerial(g_mark_serial);
+ }
+ }
+ }
+ }
+}
+
+NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
+{
+ NativeEntry *pEntry;
+
+ if ((pEntry = FindNative(ntv->name)) == NULL)
+ {
+ pEntry = new NativeEntry;
+
+ pEntry->owner = pOwner;
+ pEntry->name = ntv->name;
+ pEntry->func = ntv->func;
+ pEntry->replacement.func = NULL;
+ pEntry->replacement.owner = NULL;
+ pEntry->fake = NULL;
+
+ m_NtvCache.insert(ntv->name, pEntry);
+
+ return pEntry;
+ }
+
+ if (pEntry->owner != NULL)
+ {
+ return NULL;
+ }
+
+ pEntry->owner = pOwner;
+ pEntry->func = ntv->func;
+ pEntry->name = ntv->name;
+
+ return pEntry;
+}
+
+void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
+{
+ NativeEntry *pEntry;
+
+ if ((pEntry = FindNative(name)) == NULL)
+ {
+ return;
+ }
+
+ if (pEntry->owner != pOwner)
+ {
+ return;
+ }
+
+ if (pEntry->fake != NULL)
+ {
+ g_pSourcePawn2->DestroyFakeNative(pEntry->func);
+ delete pEntry->fake;
+ pEntry->fake = NULL;
+ }
+
+ pEntry->func = NULL;
+ pEntry->name = NULL;
+ pEntry->owner = NULL;
+ pEntry->replacement.func = NULL;
+ pEntry->replacement.owner = NULL;
+}
+
+NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
+{
+ FakeNative *pFake;
+ NativeEntry *pEntry;
+ SPVM_NATIVE_FUNC gate;
+
+ if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL)
+ {
+ return NULL;
+ }
+
+ pFake = new FakeNative;
+
+ if ((gate = g_pSourcePawn2->CreateFakeNative(func, pFake)) == NULL)
+ {
+ delete pFake;
+ return NULL;
+ }
+
+ if (pEntry == NULL)
+ {
+ pEntry = new NativeEntry;
+ m_NtvCache.insert(name, pEntry);
+ }
+
+ pFake->call = pFunc;
+ pFake->ctx = pFunc->GetParentContext();
+ smcore.strncopy(pFake->name, name, sizeof(pFake->name));
+
+ pEntry->fake = pFake;
+ pEntry->func = gate;
+ pEntry->name = pFake->name;
+ pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext());
+ pEntry->replacement.func = NULL;
+ pEntry->replacement.owner = NULL;
+
+ return pEntry;
+}
+
+void ShareSystem::AddCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
+ const char *name)
+{
+ if (m_caps.retrieve(name) != NULL)
+ return;
+
+ Capability cap;
+ cap.ext = myself;
+ cap.provider = provider;
+
+ m_caps.insert(name, cap);
+}
+
+void ShareSystem::DropCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
+ const char *name)
+{
+ Capability *pCap = m_caps.retrieve(name);
+ if (pCap == NULL)
+ return;
+
+ if (pCap->ext != myself || pCap->provider != provider)
+ return;
+
+ m_caps.remove(name);
+}
+
+FeatureStatus ShareSystem::TestFeature(IPluginRuntime *pRuntime, FeatureType feature,
+ const char *name)
+{
+ switch (feature)
+ {
+ case FeatureType_Native:
+ return TestNative(pRuntime, name);
+ case FeatureType_Capability:
+ return TestCap(name);
+ default:
+ break;
+ }
+
+ return FeatureStatus_Unknown;
+}
+
+FeatureStatus ShareSystem::TestNative(IPluginRuntime *pRuntime, const char *name)
+{
+ uint32_t index;
+
+ if (pRuntime->FindNativeByName(name, &index) == SP_ERROR_NONE)
+ {
+ sp_native_t *native;
+ if (pRuntime->GetNativeByIndex(index, &native) == SP_ERROR_NONE)
+ {
+ if (native->status == SP_NATIVE_BOUND)
+ return FeatureStatus_Available;
+ else
+ return FeatureStatus_Unknown;
+ }
+ }
+
+ NativeEntry *entry = FindNative(name);
+ if (entry == NULL)
+ return FeatureStatus_Unknown;
+
+ if ((entry->replacement.owner != NULL || entry->owner != NULL) &&
+ (entry->replacement.func != NULL || entry->func != NULL))
+ {
+ return FeatureStatus_Available;
+ }
+ else
+ {
+ return FeatureStatus_Unavailable;
+ }
+}
+
+FeatureStatus ShareSystem::TestCap(const char *name)
+{
+ Capability *cap = m_caps.retrieve(name);
+ if (cap == NULL)
+ return FeatureStatus_Unknown;
+
+ return cap->provider->GetFeatureStatus(FeatureType_Capability, name);
+}