ds@1952: /** ds@1952: * vim: set ts=4 : ds@1952: * ============================================================================= ds@1952: * SourceMod SDKTools Extension ds@1952: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1952: * ============================================================================= ds@1952: * ds@1952: * This program is free software; you can redistribute it and/or modify it under ds@1952: * the terms of the GNU General Public License, version 3.0, as published by the ds@1952: * Free Software Foundation. ds@1952: * ds@1952: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1952: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1952: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1952: * details. ds@1952: * ds@1952: * You should have received a copy of the GNU General Public License along with ds@1952: * this program. If not, see . ds@1952: * ds@1952: * As a special exception, AlliedModders LLC gives you permission to link the ds@1952: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1952: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1952: * by the Valve Corporation. You must obey the GNU General Public License in ds@1952: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1952: * this exception to all derivative works. AlliedModders LLC defines further ds@1952: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1952: * or . ds@1952: * ds@1952: * Version: $Id$ ds@1952: */ ds@1952: ds@1952: #include "vcallbuilder.h" ds@1952: #include "extension.h" ds@1952: ds@1952: ValveCall::ValveCall() ds@1952: { ds@1952: call = NULL; ds@1952: vparams = NULL; ds@1952: retinfo = NULL; ds@1952: thisinfo = NULL; ds@1952: retbuf = NULL; ds@1952: } ds@1952: ds@1952: ValveCall::~ValveCall() ds@1952: { ds@1952: while (!stk.empty()) ds@1952: { ds@1952: unsigned char *ptr = stk.front(); ds@1952: delete [] ptr; ds@1952: stk.pop(); ds@1952: } ds@1952: if (call) ds@1952: { ds@1952: call->Destroy(); ds@1952: } ds@1952: delete [] retbuf; ds@1952: delete [] vparams; ds@1952: } ds@1952: ds@1952: unsigned char *ValveCall::stk_get() ds@1952: { ds@1952: unsigned char *ptr; ds@1952: if (stk.empty()) ds@1952: { ds@1952: ptr = new unsigned char[stackSize]; ds@1952: } else { ds@1952: ptr = stk.front(); ds@1952: stk.pop(); ds@1952: } ds@1952: return ptr; ds@1952: } ds@1952: ds@1952: void ValveCall::stk_put(unsigned char *ptr) ds@1952: { ds@1952: stk.push(ptr); ds@1952: } ds@1952: ds@1952: ValveCall *CreateValveCall(void *addr, ds@1952: ValveCallType vcalltype, ds@1952: const ValvePassInfo *retInfo, ds@1952: const ValvePassInfo *params, ds@1952: unsigned int numParams) ds@1952: { ds@1952: if (numParams > 32) ds@1952: { ds@1952: return NULL; ds@1952: } ds@1952: ds@1952: ValveCall *vc = new ValveCall; ds@1952: ds@1952: vc->type = vcalltype; ds@1952: ds@1952: size_t size = 0; ds@1952: vc->stackSize = 0; ds@1952: ds@1952: /* Get return information - encode only */ ds@1952: PassInfo retBuf; ds@1952: size_t retBufSize = 0; ds@1952: bool retbuf_needs_extra; ds@1952: if (retInfo) ds@1952: { ds@1952: if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0) ds@1952: { ds@1952: delete vc; ds@1952: return NULL; ds@1952: } ds@1952: retBufSize = retBuf.size; ds@1952: } ds@1952: ds@1952: /* Get parameter info */ ds@1952: PassInfo paramBuf[32]; ds@1952: size_t sizes[32]; ds@1952: size_t normSize = 0; ds@1952: size_t extraSize = 0; ds@1952: for (unsigned int i=0; itype = PassType_Basic; ds@1952: switch (vcalltype) ds@1952: { ds@1952: case ValveCall_Entity: ds@1952: thisinfo->vtype = Valve_CBaseEntity; ds@1952: thisinfo->flags = PASSFLAG_BYVAL; ds@1952: thisinfo->decflags |= VDECODE_FLAG_ALLOWWORLD; ds@1952: break; ds@1952: case ValveCall_Player: ds@1952: thisinfo->vtype = Valve_CBasePlayer; ds@1952: thisinfo->flags = PASSFLAG_BYVAL; ds@1952: thisinfo->decflags = 0; ds@1952: break; ds@1952: default: ds@1952: thisinfo->vtype = Valve_POD; ds@1952: thisinfo->flags = PASSFLAG_ASPOINTER; ds@1952: thisinfo->decflags = 0; ds@1952: break; ds@1952: } ds@1952: thisinfo->encflags = 0; ds@1952: thisinfo->offset = 0; ds@1952: normSize += sizeof(void *); ds@1952: cv = CallConv_ThisCall; ds@1952: } ds@1952: ds@1952: /* Now we can try creating the call */ ds@1952: if ((vc->call = g_pBinTools->CreateCall(addr, ds@1952: cv, ds@1952: (retInfo ? &retBuf : NULL), ds@1952: paramBuf, ds@1952: numParams)) ds@1952: == NULL) ds@1952: { ds@1952: if (!vc->call) ds@1952: { ds@1952: delete vc; ds@1952: return NULL; ds@1952: } ds@1952: } ds@1952: ds@1952: /* Allocate extra space for thisptr AND ret buffer, even if we don't use it */ ds@1952: vc->vparams = new ValvePassInfo[numParams + 2]; ds@1952: ds@1952: /* We've got the call and everything is encoded. ds@1952: * It's time to save the valve specific information and helper variables. ds@1952: */ ds@1952: if (retInfo) ds@1952: { ds@1952: /* Allocate and copy */ ds@1952: vc->retinfo = &(vc->vparams[numParams]); ds@1952: *vc->retinfo = *retInfo; ds@1952: vc->retinfo->offset = 0; ds@1952: vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0; ds@1952: /* Allocate stack space */ ds@1952: vc->retbuf = new unsigned char[retBufSize]; ds@1952: } else { ds@1952: vc->retinfo = NULL; ds@1952: vc->retbuf = NULL; ds@1952: } ds@1952: ds@1952: if (thisinfo) ds@1952: { ds@1952: /* Allocate and copy */ ds@1952: vc->thisinfo = &(vc->vparams[numParams + 1]); ds@1952: *vc->thisinfo = *thisinfo; ds@1952: vc->thisinfo->offset = 0; ds@1952: vc->thisinfo->obj_offset = 0; ds@1952: } else { ds@1952: vc->thisinfo = NULL; ds@1952: } ds@1952: ds@1952: /* Now, save info about each parameter. */ ds@1952: size_t last_extra_offset = 0; ds@1952: for (unsigned int i=0; ivparams[i] = params[i]; ds@1952: vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset; ds@1952: vc->vparams[i].obj_offset = last_extra_offset; ds@1952: last_extra_offset += sizes[i]; ds@1952: } ds@1952: ds@1952: vc->stackSize = normSize + extraSize; ds@1952: vc->stackEnd = normSize; ds@1952: ds@1952: return vc; ds@1952: } ds@1952: ds@1952: ValveCall *CreateValveVCall(unsigned int vtableIdx, ds@1952: ValveCallType vcalltype, ds@1952: const ValvePassInfo *retInfo, ds@1952: const ValvePassInfo *params, ds@1952: unsigned int numParams) ds@1952: { ds@1952: if (numParams > 32) ds@1952: { ds@1952: return NULL; ds@1952: } ds@1952: ds@1952: ValveCall *vc = new ValveCall; ds@1952: ds@1952: vc->type = vcalltype; ds@1952: ds@1952: size_t size = 0; ds@1952: vc->stackSize = 0; ds@1952: ds@1952: /* Get return information - encode only */ ds@1952: PassInfo retBuf; ds@1952: size_t retBufSize = 0; ds@1952: bool retbuf_needs_extra; ds@1952: if (retInfo) ds@1952: { ds@1952: if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0) ds@1952: { ds@1952: delete vc; ds@1952: return NULL; ds@1952: } ds@1952: retBufSize = retBuf.size; ds@1952: } ds@1952: ds@1952: /* Get parameter info */ ds@1952: PassInfo paramBuf[32]; ds@1952: size_t sizes[32]; ds@1952: size_t normSize = 0; ds@1952: size_t extraSize = 0; ds@1952: for (unsigned int i=0; icall = g_pBinTools->CreateVCall(vtableIdx, ds@1952: 0, ds@1952: 0, ds@1952: (retInfo ? &retBuf : NULL), ds@1952: paramBuf, ds@1952: numParams)) ds@1952: == NULL) ds@1952: { ds@1952: if (!vc->call) ds@1952: { ds@1952: delete vc; ds@1952: return NULL; ds@1952: } ds@1952: } ds@1952: ds@1952: /* Allocate extra space for thisptr AND ret buffer, even if we don't use it */ ds@1952: vc->vparams = new ValvePassInfo[numParams + 2]; ds@1952: ds@1952: /* We've got the call and everything is encoded. ds@1952: * It's time to save the valve specific information and helper variables. ds@1952: */ ds@1952: if (retInfo) ds@1952: { ds@1952: /* Allocate and copy */ ds@1952: vc->retinfo = &(vc->vparams[numParams]); ds@1952: *vc->retinfo = *retInfo; ds@1952: vc->retinfo->offset = 0; ds@1952: vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0; ds@1952: /* Allocate stack space */ ds@1952: vc->retbuf = new unsigned char[retBufSize]; ds@1952: } else { ds@1952: vc->retinfo = NULL; ds@1952: vc->retbuf = NULL; ds@1952: } ds@1952: ds@1952: /* Save the this info for the dynamic decoder */ ds@1952: vc->thisinfo = &(vc->vparams[numParams + 1]); ds@1952: vc->thisinfo->type = PassType_Basic; ds@1952: switch (vcalltype) ds@1952: { ds@1952: case ValveCall_Entity: ds@1952: vc->thisinfo->vtype = Valve_CBaseEntity; ds@1952: vc->thisinfo->flags = PASSFLAG_BYVAL; ds@1952: vc->thisinfo->decflags = VDECODE_FLAG_ALLOWWORLD; ds@1952: break; ds@1952: case ValveCall_Player: ds@1952: vc->thisinfo->vtype = Valve_CBasePlayer; ds@1952: vc->thisinfo->flags = PASSFLAG_BYVAL; ds@1952: vc->thisinfo->decflags = 0; ds@1952: break; ds@1952: default: ds@1952: vc->thisinfo->vtype = Valve_POD; ds@1952: vc->thisinfo->flags = PASSFLAG_ASPOINTER; ds@1952: vc->thisinfo->decflags = 0; ds@1952: break; ds@1952: } ds@1952: vc->thisinfo->encflags = 0; ds@1952: vc->thisinfo->offset = 0; ds@1952: vc->thisinfo->obj_offset = 0; ds@1952: normSize += sizeof(void *); ds@1952: ds@1952: /* Now, save info about each parameter. */ ds@1952: size_t last_extra_offset = 0; ds@1952: for (unsigned int i=0; ivparams[i] = params[i]; ds@1952: vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset; ds@1952: vc->vparams[i].obj_offset = last_extra_offset; ds@1952: last_extra_offset += sizes[i]; ds@1952: } ds@1952: ds@1952: vc->stackSize = normSize + extraSize; ds@1952: vc->stackEnd = normSize; ds@1952: ds@1952: return vc; ds@1952: }