extensions/sdktools/vcallbuilder.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Thu Jul 04 11:28:32 2013 -0400 (2013-07-04)
changeset 3931 576fa42454dc
parent 2786 8c049d1fad45
permissions -rw-r--r--
Fixed build for real.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod SDKTools Extension
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <stdio.h>
    33 #include "vcallbuilder.h"
    34 #include "extension.h"
    35 
    36 ValveCall::ValveCall()
    37 {
    38 	call = NULL;
    39 	vparams = NULL;
    40 	retinfo = NULL;
    41 	thisinfo = NULL;
    42 	retbuf = NULL;
    43 }
    44 
    45 ValveCall::~ValveCall()
    46 {
    47 	while (!stk.empty())
    48 	{
    49 		unsigned char *ptr = stk.front();
    50 		delete [] ptr;
    51 		stk.pop();
    52 	}
    53 	if (call)
    54 	{
    55 		call->Destroy();
    56 	}
    57 	delete [] retbuf;
    58 	delete [] vparams;
    59 }
    60 
    61 unsigned char *ValveCall::stk_get()
    62 {
    63 	unsigned char *ptr;
    64 	if (stk.empty())
    65 	{
    66 		ptr = new unsigned char[stackSize];
    67 	} else {
    68 		ptr = stk.front();
    69 		stk.pop();
    70 	}
    71 	return ptr;
    72 }
    73 
    74 void ValveCall::stk_put(unsigned char *ptr)
    75 {
    76 	stk.push(ptr);
    77 }
    78 
    79 ValveCall *CreateValveCall(void *addr,
    80 						   ValveCallType vcalltype,
    81 						   const ValvePassInfo *retInfo,
    82 						   const ValvePassInfo *params,
    83 						   unsigned int numParams)
    84 {
    85 	if (numParams > 32)
    86 	{
    87 		return NULL;
    88 	}
    89 
    90 	ValveCall *vc = new ValveCall;
    91 
    92 	vc->type = vcalltype;
    93 
    94 	size_t size = 0;
    95 	vc->stackSize = 0;
    96 
    97 	/* Get return information - encode only */
    98 	PassInfo retBuf;
    99 	size_t retBufSize = 0;
   100 	bool retbuf_needs_extra;
   101 	if (retInfo)
   102 	{
   103 		if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0)
   104 		{
   105 			delete vc;
   106 			return NULL;
   107 		}
   108 		retBufSize = retBuf.size;
   109 	}
   110 
   111 	/* Get parameter info */
   112 	PassInfo paramBuf[32];
   113 	size_t sizes[32];
   114 	size_t normSize = 0;
   115 	size_t extraSize = 0;
   116 	for (unsigned int i=0; i<numParams; i++)
   117 	{
   118 		bool needs_extra;
   119 		if ((size = ValveParamToBinParam(params[i].vtype, 
   120 			params[i].type,
   121 			params[i].flags,
   122 			&paramBuf[i],
   123 			needs_extra)) == 0)
   124 		{
   125 			delete vc;
   126 			return NULL;
   127 		}
   128 		if (needs_extra)
   129 		{
   130 			sizes[i] = size;
   131 		} else {
   132 			sizes[i] = 0;
   133 		}
   134 		normSize += paramBuf[i].size;
   135 		extraSize += sizes[i];
   136 	}
   137 
   138 
   139 	/* Get thisinfo if needed */
   140 	ValvePassInfo thisbuf;
   141 	ValvePassInfo *thisinfo = NULL;
   142 	CallConvention cv = CallConv_Cdecl;
   143 	if (vcalltype != ValveCall_Static)
   144 	{
   145 		thisinfo = &thisbuf;
   146 		thisinfo->type = PassType_Basic;
   147 		switch (vcalltype)
   148 		{
   149 		case ValveCall_Entity:
   150 			thisinfo->vtype = Valve_CBaseEntity;
   151 			thisinfo->flags = PASSFLAG_BYVAL;
   152 			thisinfo->decflags |= VDECODE_FLAG_ALLOWWORLD;
   153 			break;
   154 		case ValveCall_Player:
   155 			thisinfo->vtype = Valve_CBasePlayer;
   156 			thisinfo->flags = PASSFLAG_BYVAL;
   157 			thisinfo->decflags = 0;
   158 			break;
   159 		default:
   160 			thisinfo->vtype = Valve_POD;
   161 			thisinfo->flags = PASSFLAG_ASPOINTER;
   162 			thisinfo->decflags = 0;
   163 			break;
   164 		}
   165 		thisinfo->encflags = 0;
   166 		thisinfo->offset = 0;
   167 		normSize += sizeof(void *);
   168 		cv = CallConv_ThisCall;
   169 	}
   170 
   171 	/* Now we can try creating the call */
   172 	if ((vc->call = g_pBinTools->CreateCall(addr,
   173 		cv,
   174 		(retInfo ? &retBuf : NULL),
   175 		paramBuf,
   176 		numParams))
   177 		== NULL)
   178 	{
   179 		if (!vc->call)
   180 		{
   181 			delete vc;
   182 			return NULL;
   183 		}
   184 	}
   185 
   186 	/* Allocate extra space for thisptr AND ret buffer, even if we don't use it */
   187 	vc->vparams = new ValvePassInfo[numParams + 2];
   188 
   189 	/* We've got the call and everything is encoded.
   190 	 * It's time to save the valve specific information and helper variables.
   191 	 */
   192 	if (retInfo)
   193 	{
   194 		/* Allocate and copy */
   195 		vc->retinfo = &(vc->vparams[numParams]);
   196 		*vc->retinfo = *retInfo;
   197 		vc->retinfo->offset = 0;
   198 		vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0;
   199 		/* Allocate stack space */
   200 		vc->retbuf = new unsigned char[retBufSize];
   201 	} else {
   202 		vc->retinfo = NULL;
   203 		vc->retbuf = NULL;
   204 	}
   205 
   206 	if (thisinfo)
   207 	{
   208 		/* Allocate and copy */
   209 		vc->thisinfo = &(vc->vparams[numParams + 1]);
   210 		*vc->thisinfo = *thisinfo;
   211 		vc->thisinfo->offset = 0;
   212 		vc->thisinfo->obj_offset = 0;
   213 	} else {
   214 		vc->thisinfo = NULL;
   215 	}
   216 
   217 	/* Now, save info about each parameter. */
   218 	size_t last_extra_offset = 0;
   219 	for (unsigned int i=0; i<numParams; i++)
   220 	{
   221 		/* Copy */
   222 		vc->vparams[i] = params[i];
   223 		vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
   224 		vc->vparams[i].obj_offset = last_extra_offset;
   225 		last_extra_offset += sizes[i];
   226 	}
   227 
   228 	vc->stackSize = normSize + extraSize;
   229 	vc->stackEnd = normSize;
   230 
   231 	return vc;
   232 }
   233 
   234 ValveCall *CreateValveVCall(unsigned int vtableIdx,
   235 							ValveCallType vcalltype,
   236 							const ValvePassInfo *retInfo,
   237 							const ValvePassInfo *params,
   238 							unsigned int numParams)
   239 {
   240 	if (numParams > 32)
   241 	{
   242 		return NULL;
   243 	}
   244 
   245 	ValveCall *vc = new ValveCall;
   246 
   247 	vc->type = vcalltype;
   248 
   249 	size_t size = 0;
   250 	vc->stackSize = 0;
   251 
   252 	/* Get return information - encode only */
   253 	PassInfo retBuf;
   254 	size_t retBufSize = 0;
   255 	bool retbuf_needs_extra;
   256 	if (retInfo)
   257 	{
   258 		if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0)
   259 		{
   260 			delete vc;
   261 			return NULL;
   262 		}
   263 		retBufSize = retBuf.size;
   264 	}
   265 
   266 	/* Get parameter info */
   267 	PassInfo paramBuf[32];
   268 	size_t sizes[32];
   269 	size_t normSize = 0;
   270 	size_t extraSize = 0;
   271 	for (unsigned int i=0; i<numParams; i++)
   272 	{
   273 		bool needs_extra;
   274 		if ((size = ValveParamToBinParam(params[i].vtype, 
   275 										params[i].type,
   276 										params[i].flags,
   277 										&paramBuf[i],
   278 										needs_extra)) == 0)
   279 		{
   280 			delete vc;
   281 			return NULL;
   282 		}
   283 		if (needs_extra)
   284 		{
   285 			sizes[i] = size;
   286 		} else {
   287 			sizes[i] = 0;
   288 		}
   289 		normSize += paramBuf[i].size;
   290 		extraSize += sizes[i];
   291 	}
   292 
   293 	/* Now we can try creating the call */
   294 	if ((vc->call = g_pBinTools->CreateVCall(vtableIdx, 
   295 		0, 
   296 		0, 
   297 		(retInfo ? &retBuf : NULL),
   298 		paramBuf,
   299 		numParams))
   300 		== NULL)
   301 	{
   302 		if (!vc->call)
   303 		{
   304 			delete vc;
   305 			return NULL;
   306 		}
   307 	}
   308 
   309 	/* Allocate extra space for thisptr AND ret buffer, even if we don't use it */
   310 	vc->vparams = new ValvePassInfo[numParams + 2];
   311 
   312 	/* We've got the call and everything is encoded.
   313 	 * It's time to save the valve specific information and helper variables.
   314 	 */
   315 	if (retInfo)
   316 	{
   317 		/* Allocate and copy */
   318 		vc->retinfo = &(vc->vparams[numParams]);
   319 		*vc->retinfo = *retInfo;
   320 		vc->retinfo->offset = 0;
   321 		vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0;
   322 		/* Allocate stack space */
   323 		vc->retbuf = new unsigned char[retBufSize];
   324 	} else {
   325 		vc->retinfo = NULL;
   326 		vc->retbuf = NULL;
   327 	}
   328 
   329 	/* Save the this info for the dynamic decoder */
   330 	vc->thisinfo = &(vc->vparams[numParams + 1]);
   331 	vc->thisinfo->type = PassType_Basic;
   332 	switch (vcalltype)
   333 	{
   334 	case ValveCall_Entity:
   335 		vc->thisinfo->vtype = Valve_CBaseEntity;
   336 		vc->thisinfo->flags = PASSFLAG_BYVAL;
   337 		vc->thisinfo->decflags = VDECODE_FLAG_ALLOWWORLD;
   338 		break;
   339 	case ValveCall_Player:
   340 		vc->thisinfo->vtype = Valve_CBasePlayer;
   341 		vc->thisinfo->flags = PASSFLAG_BYVAL;
   342 		vc->thisinfo->decflags = 0;
   343 		break;
   344 	default:
   345 		vc->thisinfo->vtype = Valve_POD;
   346 		vc->thisinfo->flags = PASSFLAG_ASPOINTER;
   347 		vc->thisinfo->decflags = 0;
   348 		break;
   349 	}
   350 	vc->thisinfo->encflags = 0;
   351 	vc->thisinfo->offset = 0;
   352 	vc->thisinfo->obj_offset = 0;
   353 	normSize += sizeof(void *);
   354 
   355 	/* Now, save info about each parameter. */
   356 	size_t last_extra_offset = 0;
   357 	for (unsigned int i=0; i<numParams; i++)
   358 	{
   359 		/* Copy */
   360 		vc->vparams[i] = params[i];
   361 		vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
   362 		vc->vparams[i].obj_offset = last_extra_offset;
   363 		last_extra_offset += sizes[i];
   364 	}
   365 
   366 	vc->stackSize = normSize + extraSize;
   367 	vc->stackEnd = normSize;
   368 
   369 	return vc;
   370 }