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