diff --git a/core/CDataPack.cpp b/core/CDataPack.cpp new file mode 100644 index 00000000..09e932e4 --- /dev/null +++ b/core/CDataPack.cpp @@ -0,0 +1,176 @@ +#include +#include +#include "CDataPack.h" + +#define DATAPACK_INITIAL_SIZE 512 + +CDataPack::CDataPack() +{ + m_pBase = (char *)malloc(DATAPACK_INITIAL_SIZE); + m_capacity = DATAPACK_INITIAL_SIZE; + Initialize(); +} + +CDataPack::~CDataPack() +{ + free(m_pBase); +} + +void CDataPack::Initialize() +{ + m_curptr = m_pBase; + m_size = 0; +} + +void CDataPack::CheckSize(size_t typesize) +{ + if (m_curptr - m_pBase + typesize <= m_capacity) + { + return; + } + + size_t pos = m_curptr - m_pBase; + do + { + m_capacity *= 2; + m_pBase = (char *)realloc(m_pBase, m_capacity); + m_curptr = m_pBase + pos; + } while (m_curptr - m_pBase + typesize > m_capacity); +} + +void CDataPack::ResetSize() +{ + m_size = 0; +} + +size_t CDataPack::CreateMemory(size_t size, void **addr) +{ + size_t pos = m_curptr - m_pBase; + + m_pBase = (char *)realloc(m_pBase, size); + m_curptr = m_pBase + pos; + m_capacity = size; + + if (addr) + { + *addr = m_pBase; + } + + return pos; +} + +void CDataPack::PackCell(cell_t cell) +{ + CheckSize(sizeof(cell_t)); + + *(cell_t *)m_curptr = cell; + m_curptr += sizeof(cell_t); + m_size += sizeof(cell_t); +} + +void CDataPack::PackFloat(float val) +{ + CheckSize(sizeof(float)); + + *(float *)m_curptr = val; + m_curptr += sizeof(float); + m_size += sizeof(float); +} + +void CDataPack::PackString(const char *string) +{ + size_t len = strlen(string); + size_t maxsize = sizeof(size_t) + len + 1; + CheckSize(maxsize); + + // Pack the string length first for buffer overrun checking. + *(size_t *)m_curptr = len; + m_curptr += sizeof(size_t); + + // Now pack the string. + memcpy(m_curptr, string, len); + m_curptr[len] = '\0'; + m_curptr += len + 1; + + m_size += maxsize; +} + +void CDataPack::Reset() const +{ + m_curptr = m_pBase; +} + +size_t CDataPack::GetPosition() const +{ + return static_cast(m_curptr - m_pBase); +} + +bool CDataPack::SetPosition(size_t pos) const +{ + if (pos > m_size-1) + { + return false; + } + m_curptr = m_pBase + pos; + + return true; +} + +cell_t CDataPack::ReadCell() const +{ + if (!IsReadable(sizeof(cell_t))) + { + return 0; + } + cell_t val = *reinterpret_cast(m_curptr); + m_curptr += sizeof(cell_t); + return val; +} + +float CDataPack::ReadFloat() const +{ + if (!IsReadable(sizeof(float))) + { + return 0; + } + float val = *reinterpret_cast(m_curptr); + m_curptr += sizeof(float); + return val; +} + +bool CDataPack::IsReadable(size_t bytes) const +{ + return (bytes + (m_curptr - m_pBase) > m_size) ? false : true; +} + +const char *CDataPack::ReadString(size_t *len) const +{ + if (!IsReadable(sizeof(size_t))) + { + return 0; + } + + size_t real_len = *(size_t *)m_curptr; + + m_curptr += sizeof(size_t); + char *str = (char *)m_curptr; + + if ((strlen(str) != real_len) || !(IsReadable(real_len+1))) + { + return NULL; + } + + if (len) + { + *len = real_len; + } + + m_curptr += real_len + 1; + + return str; +} + +void *CDataPack::GetMemory() const +{ + return m_curptr; +} diff --git a/core/CDataPack.h b/core/CDataPack.h new file mode 100644 index 00000000..0aae8592 --- /dev/null +++ b/core/CDataPack.h @@ -0,0 +1,53 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CDATAPACK_H_ +#define _INCLUDE_SOURCEMOD_CDATAPACK_H_ + +#include + +using namespace SourceMod; + +class CDataPack : public IDataPack +{ +public: + CDataPack(); + ~CDataPack(); +public: //IDataReader + void Reset() const; + size_t GetPosition() const; + bool SetPosition(size_t pos) const; + cell_t ReadCell() const; + float ReadFloat() const; + bool IsReadable(size_t bytes) const; + const char *ReadString(size_t *len) const; + void *GetMemory() const; +public: //IDataPack + void ResetSize(); + void PackCell(cell_t cell); + void PackFloat(float val); + void PackString(const char *string); + size_t CreateMemory(size_t size, void **addr); +public: + void Initialize(); +private: + void CheckSize(size_t sizetype); +private: + char *m_pBase; + mutable char *m_curptr; + size_t m_capacity; + size_t m_size; +}; + +#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_ \ No newline at end of file diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 7dfbbdde..7bdd8347 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + @@ -235,6 +239,10 @@ RelativePath="..\smn_convar.cpp" > + + @@ -285,6 +293,10 @@ RelativePath="..\CConVarManager.h" > + + diff --git a/core/smn_datapacks.cpp b/core/smn_datapacks.cpp new file mode 100644 index 00000000..fdf9ca3e --- /dev/null +++ b/core/smn_datapacks.cpp @@ -0,0 +1,288 @@ +#include "sm_globals.h" +#include "HandleSys.h" +#include "CDataPack.h" + +HandleType_t g_DataPackType; + +class DataPackNatives : + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + void OnSourceModAllInitialized() + { + g_DataPackType = g_HandleSys.CreateType("DataPack", this, 0, NULL, NULL, g_pCoreIdent, NULL); + } + void OnSourceModShutdown() + { + g_HandleSys.RemoveType(g_DataPackType, g_pCoreIdent); + g_DataPackType = 0; + } + void OnHandleDestroy(HandleType_t type, void *object) + { + g_SourceMod.FreeDataPack(reinterpret_cast(object)); + } +}; + +static cell_t smn_CreateDataPack(IPluginContext *pContext, const cell_t *params) +{ + IDataPack *pDataPack = g_SourceMod.CreateDataPack(); + + if (!pDataPack) + { + return 0; + } + + return g_HandleSys.CreateHandle(g_DataPackType, pDataPack, pContext->GetIdentity(), g_pCoreIdent, NULL); +} + +static cell_t smn_WritePackCell(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + pDataPack->PackCell(params[2]); + + return 1; +} + +static cell_t smn_WritePackFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + pDataPack->PackFloat(sp_ctof(params[2])); + + return 1; +} + +static cell_t smn_WritePackString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + int err; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + char *str; + if ((err=pContext->LocalToString(params[2], &str)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + pDataPack->PackString(str); + + return 1; +} + +static cell_t smn_ReadPackCell(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + if (!pDataPack->IsReadable(sizeof(cell_t))) + { + return pContext->ThrowNativeError("DataPack operation is out of bounds."); + } + + return pDataPack->ReadCell(); +} + +static cell_t smn_ReadPackFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + if (!pDataPack->IsReadable(sizeof(float))) + { + return pContext->ThrowNativeError("DataPack operation is out of bounds."); + } + + return sp_ftoc(pDataPack->ReadFloat()); +} + +static cell_t smn_ReadPackString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + const char *str; + if (!(str=pDataPack->ReadString(NULL))) + { + return pContext->ThrowNativeError("DataPack operation is out of bounds."); + } + + pContext->StringToLocal(params[2], params[3], str); + + return 1; +} + +static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + pDataPack->Reset(); + if (params[2]) + { + pDataPack->ResetSize(); + } + + return 1; +} + +static cell_t smn_GetPackPosition(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + return static_cast(pDataPack->GetPosition()); +} + +static cell_t smn_SetPackPosition(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + if (!pDataPack->SetPosition(params[2])) + { + return pContext->ThrowNativeError("Invalid DataPack position, %d is out of bounds", params[2]); + } + + return 1; +} + +static cell_t smn_IsPackReadable(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + return pDataPack->IsReadable(params[2]) ? 1 : 0; +} + +static DataPackNatives s_DataPackNatives; + +REGISTER_NATIVES(datapacknatives) +{ + {"CreateDataPack", smn_CreateDataPack}, + {"WritePackCell", smn_WritePackCell}, + {"WritePackFloat", smn_WritePackFloat}, + {"WritePackString", smn_WritePackString}, + {"ReadPackCell", smn_ReadPackCell}, + {"ReadPackFloat", smn_ReadPackFloat}, + {"ReadPackString", smn_ReadPackString}, + {"ResetPack", smn_ResetPack}, + {"GetPackPosition", smn_GetPackPosition}, + {"SetPackPosition", smn_SetPackPosition}, + {"IsPackReadable", smn_IsPackReadable}, + {NULL, NULL} +}; \ No newline at end of file diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 72e57d91..f25222fe 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -226,7 +226,7 @@ void SourceModBase::LevelShutdown() } } -bool SourceModBase::IsMapLoading() +bool SourceModBase::IsMapLoading() const { return m_IsMapLoading; } @@ -296,6 +296,16 @@ void SourceModBase::CloseSourceMod() pBase = pBase->m_pGlobalClassNext; } + /* Delete all data packs */ + CStack::iterator iter; + CDataPack *pd; + for (iter=m_freepacks.begin(); iter!=m_freepacks.end(); iter++) + { + pd = (*iter); + delete pd; + } + m_freepacks.popall(); + /* Notify! */ pBase = SMGlobalClass::head; while (pBase) @@ -361,12 +371,12 @@ size_t SourceModBase::FormatString(char *buffer, size_t maxlength, IPluginContex return atcprintf(buffer, maxlength, fmt, pContext, params, &lparam); } -const char *SourceModBase::GetSourceModPath() +const char *SourceModBase::GetSourceModPath() const { return m_SMBaseDir; } -const char *SourceModBase::GetModPath() +const char *SourceModBase::GetModPath() const { return g_BaseDir.c_str(); } @@ -386,6 +396,31 @@ unsigned int SourceModBase::GetGlobalTarget() const return m_target; } +IDataPack *SourceModBase::CreateDataPack() +{ + CDataPack *pack; + if (m_freepacks.empty()) + { + pack = new CDataPack; + } else { + pack = m_freepacks.front(); + m_freepacks.pop(); + pack->Initialize(); + } + return pack; +} + +void SourceModBase::FreeDataPack(IDataPack *pack) +{ + m_freepacks.push(static_cast(pack)); +} + +Handle_t SourceModBase::GetDataPackHandleType(bool readonly) +{ + //:TODO: + return 0; +} + SMGlobalClass *SMGlobalClass::head = NULL; SMGlobalClass::SMGlobalClass() diff --git a/core/sourcemod.h b/core/sourcemod.h index a906b759..f1ea52d1 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -16,6 +16,10 @@ #include "sm_globals.h" #include +#include +#include "CDataPack.h" + +using namespace SourceHook; /** * @brief Implements SourceMod's global overall management, API, and logic @@ -52,9 +56,9 @@ public: void LevelShutdown(); /** - * @brief Returns whether or not a mapload is in progress + * @brief Returns whether or not a map load is in progress */ - bool IsMapLoading(); + bool IsMapLoading() const; /** * @brief Stores the global target index. @@ -65,14 +69,21 @@ public: * @brief Returns the global target index. */ unsigned int GetGlobalTarget() const; + + /** + * @brief Sets whether if SoureMod needs to check player auths. + */ + void SetAuthChecking(bool set); public: //ISourceMod - const char *GetModPath(); - const char *GetSourceModPath(); + const char *GetModPath() const; + const char *GetSourceModPath() const; size_t BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...); void LogMessage(IExtension *pExt, const char *format, ...); void LogError(IExtension *pExt, const char *format, ...); size_t FormatString(char *buffer, size_t maxlength, IPluginContext *pContext, const cell_t *params, unsigned int param); - void SetAuthChecking(bool set); + IDataPack *CreateDataPack(); + void FreeDataPack(IDataPack *pack); + HandleType_t GetDataPackHandleType(bool readonly=false); private: /** * @brief Loading plugins @@ -80,6 +91,7 @@ private: void DoGlobalPluginLoads(); void GameFrame(bool simulating); private: + CStack m_freepacks; char m_SMBaseDir[PLATFORM_MAX_PATH+1]; char m_SMRelDir[PLATFORM_MAX_PATH+1]; bool m_IsMapLoading; diff --git a/public/IDataPack.h b/public/IDataPack.h index 1cc0446e..d5e3fc89 100644 --- a/public/IDataPack.h +++ b/public/IDataPack.h @@ -70,7 +70,8 @@ namespace SourceMod virtual float ReadFloat() const =0; /** - * @brief Returns whether or not a specified number of bytes can be read. + * @brief Returns whether or not a specified number of bytes from the current stream + * position to the end can be read. * * @param bytes Number of bytes to simulate reading. * @return True if can be read, false otherwise. @@ -94,11 +95,16 @@ namespace SourceMod }; /** - * @brief Specifices a data pack that can only be written. + * @brief Specifies a data pack that can only be written. */ class IDataPack : public IDataReader { public: + /** + * @brief Resets the used size of the stream back to zero. + */ + virtual void ResetSize() =0; + /** * @brief Packs one cell into the data stream. * diff --git a/public/ISourceMod.h b/public/ISourceMod.h index 4c3b4116..db24b346 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -24,6 +24,7 @@ #include #include +#include #define SMINTERFACE_SOURCEMOD_NAME "ISourceMod" #define SMINTERFACE_SOURCEMOD_VERSION 1 @@ -42,7 +43,7 @@ namespace SourceMod }; /** - * @brief Contains miscellanious helper functions. + * @brief Contains miscellaneous helper functions. */ class ISourceMod : public SMInterface { @@ -61,14 +62,14 @@ namespace SourceMod * * @return A string containing the full mod path. */ - virtual const char *GetModPath() =0; + virtual const char *GetModPath() const =0; /** * @brief Returns the full path to the SourceMod directory. * * @return A string containing the full SourceMod path. */ - virtual const char *GetSourceModPath() =0; + virtual const char *GetSourceModPath() const =0; /** * @brief Builds a platform path for a specific target base path. @@ -117,7 +118,6 @@ namespace SourceMod const cell_t *params, unsigned int param) =0; -#if 0 /** * @brief Creates a data pack object. * @@ -144,7 +144,6 @@ namespace SourceMod * @return The Handle type for storing generic data packs. */ virtual HandleType_t GetDataPackHandleType(bool readonly=false) =0; -#endif }; }