extensions/sdktools/vcallbuilder.cpp
author David Anderson <dvander@alliedmods.net>
Fri Jun 22 17:24:48 2007 +0000 (2007-06-22)
changeset 1002 786f5abf93ea
parent 987 242d2382cc41
child 1031 d9cf44ddcd9c
permissions -rw-r--r--
fixed a bug where the "keyOnly" parameter to KvGotoNextKey was read backwards
     1 #include "vcallbuilder.h"
     2 #include "extension.h"
     3 
     4 ValveCall::ValveCall()
     5 {
     6 	call = NULL;
     7 	vparams = NULL;
     8 	retinfo = NULL;
     9 	thisinfo = NULL;
    10 	retbuf = NULL;
    11 }
    12 
    13 ValveCall::~ValveCall()
    14 {
    15 	while (!stk.empty())
    16 	{
    17 		unsigned char *ptr = stk.front();
    18 		delete [] ptr;
    19 		stk.pop();
    20 	}
    21 	if (call)
    22 	{
    23 		call->Destroy();
    24 	}
    25 	delete [] retbuf;
    26 	delete [] vparams;
    27 }
    28 
    29 unsigned char *ValveCall::stk_get()
    30 {
    31 	unsigned char *ptr;
    32 	if (stk.empty())
    33 	{
    34 		ptr = new unsigned char[stackSize];
    35 	} else {
    36 		ptr = stk.front();
    37 		stk.pop();
    38 	}
    39 	return ptr;
    40 }
    41 
    42 void ValveCall::stk_put(unsigned char *ptr)
    43 {
    44 	stk.push(ptr);
    45 }
    46 
    47 ValveCall *CreateValveCall(void *addr,
    48 						   ValveCallType vcalltype,
    49 						   const ValvePassInfo *retInfo,
    50 						   const ValvePassInfo *params,
    51 						   unsigned int numParams)
    52 {
    53 	if (numParams > 32)
    54 	{
    55 		return NULL;
    56 	}
    57 
    58 	ValveCall *vc = new ValveCall;
    59 
    60 	size_t size = 0;
    61 	vc->stackSize = 0;
    62 
    63 	/* Get return information - encode only */
    64 	PassInfo retBuf;
    65 	size_t retBufSize = 0;
    66 	bool retbuf_needs_extra;
    67 	if (retInfo)
    68 	{
    69 		if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0)
    70 		{
    71 			delete vc;
    72 			return NULL;
    73 		}
    74 		retBufSize = retBuf.size;
    75 		if (retbuf_needs_extra)
    76 		{
    77 			retBufSize += size;
    78 		}
    79 	}
    80 
    81 	/* Get thisinfo if needed */
    82 	ValvePassInfo thisbuf;
    83 	ValvePassInfo *thisinfo = NULL;
    84 	CallConvention cv = CallConv_Cdecl;
    85 	if (vcalltype != ValveCall_Static)
    86 	{
    87 		thisinfo = &thisbuf;
    88 		thisinfo->type = PassType_Basic;
    89 		if (vcalltype == ValveCall_Entity)
    90 		{
    91 			thisinfo->vtype = Valve_CBaseEntity;
    92 			thisinfo->decflags |= VDECODE_FLAG_ALLOWWORLD;
    93 		} else if (vcalltype == ValveCall_Player) {
    94 			thisinfo->vtype = Valve_CBasePlayer;
    95 			thisinfo->decflags = 0;
    96 		}
    97 		thisinfo->encflags = 0;
    98 		thisinfo->flags = PASSFLAG_BYVAL;
    99 		thisinfo->offset = 0;
   100 		vc->stackSize += sizeof(void *);
   101 		cv = CallConv_ThisCall;
   102 	}
   103 
   104 	/* Get parameter info */
   105 	PassInfo paramBuf[32];
   106 	size_t sizes[32];
   107 	size_t normSize = 0;
   108 	size_t extraSize = 0;
   109 	for (unsigned int i=0; i<numParams; i++)
   110 	{
   111 		bool needs_extra;
   112 		if ((size = ValveParamToBinParam(params[i].vtype, 
   113 			params[i].type,
   114 			params[i].flags,
   115 			&paramBuf[i],
   116 			needs_extra)) == 0)
   117 		{
   118 			delete vc;
   119 			return NULL;
   120 		}
   121 		if (needs_extra)
   122 		{
   123 			sizes[i] = size;
   124 		} else {
   125 			sizes[i] = 0;
   126 		}
   127 		normSize += paramBuf[i].size;
   128 		extraSize += sizes[i];
   129 	}
   130 
   131 	/* Now we can try creating the call */
   132 	if ((vc->call = g_pBinTools->CreateCall(addr,
   133 		cv,
   134 		(retInfo ? &retBuf : NULL),
   135 		paramBuf,
   136 		numParams))
   137 		== NULL)
   138 	{
   139 		if (!vc->call)
   140 		{
   141 			delete vc;
   142 			return NULL;
   143 		}
   144 	}
   145 
   146 	/* Allocate extra space for thisptr AND ret buffer, even if we don't use it */
   147 	vc->vparams = new ValvePassInfo[numParams + 2];
   148 
   149 	/* We've got the call and everything is encoded.
   150 	 * It's time to save the valve specific information and helper variables.
   151 	 */
   152 	if (retInfo)
   153 	{
   154 		/* Allocate and copy */
   155 		vc->retinfo = &(vc->vparams[numParams]);
   156 		*vc->retinfo = *retInfo;
   157 		vc->retinfo->offset = 0;
   158 		vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0;
   159 		/* Allocate stack space */
   160 		vc->retbuf = new unsigned char[retBufSize];
   161 	} else {
   162 		vc->retinfo = NULL;
   163 		vc->retbuf = NULL;
   164 	}
   165 
   166 	if (thisinfo)
   167 	{
   168 		/* Allocate and copy */
   169 		vc->thisinfo = &(vc->vparams[numParams + 1]);
   170 		*vc->thisinfo = *thisinfo;
   171 		vc->thisinfo->offset = 0;
   172 		vc->thisinfo->obj_offset = 0;
   173 	} else {
   174 		vc->thisinfo = NULL;
   175 	}
   176 
   177 	/* Now, save info about each parameter. */
   178 	size_t last_extra_offset = 0;
   179 	for (unsigned int i=0; i<numParams; i++)
   180 	{
   181 		/* Copy */
   182 		vc->vparams[i] = params[i];
   183 		vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
   184 		vc->vparams[i].obj_offset = last_extra_offset;
   185 		last_extra_offset += sizes[i];
   186 	}
   187 
   188 	vc->stackSize = normSize + extraSize;
   189 	vc->stackEnd = normSize;
   190 
   191 	return vc;
   192 }
   193 
   194 ValveCall *CreateValveVCall(unsigned int vtableIdx,
   195 							ValveCallType vcalltype,
   196 							const ValvePassInfo *retInfo,
   197 							const ValvePassInfo *params,
   198 							unsigned int numParams)
   199 {
   200 	if (numParams > 32)
   201 	{
   202 		return NULL;
   203 	}
   204 
   205 	ValveCall *vc = new ValveCall;
   206 
   207 	size_t size = 0;
   208 	vc->stackSize = 0;
   209 
   210 	/* Get return information - encode only */
   211 	PassInfo retBuf;
   212 	size_t retBufSize = 0;
   213 	bool retbuf_needs_extra;
   214 	if (retInfo)
   215 	{
   216 		if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0)
   217 		{
   218 			delete vc;
   219 			return NULL;
   220 		}
   221 		retBufSize = retBuf.size;
   222 		if (retbuf_needs_extra)
   223 		{
   224 			retBufSize += size;
   225 		}
   226 	}
   227 
   228 	/* Get parameter info */
   229 	PassInfo paramBuf[32];
   230 	size_t sizes[32];
   231 	size_t normSize = 0;
   232 	size_t extraSize = 0;
   233 	for (unsigned int i=0; i<numParams; i++)
   234 	{
   235 		bool needs_extra;
   236 		if ((size = ValveParamToBinParam(params[i].vtype, 
   237 										params[i].type,
   238 										params[i].flags,
   239 										&paramBuf[i],
   240 										needs_extra)) == 0)
   241 		{
   242 			delete vc;
   243 			return NULL;
   244 		}
   245 		if (needs_extra)
   246 		{
   247 			sizes[i] = size;
   248 		} else {
   249 			sizes[i] = 0;
   250 		}
   251 		normSize += paramBuf[i].size;
   252 		extraSize += sizes[i];
   253 	}
   254 
   255 	/* Now we can try creating the call */
   256 	if ((vc->call = g_pBinTools->CreateVCall(vtableIdx, 
   257 		0, 
   258 		0, 
   259 		(retInfo ? &retBuf : NULL),
   260 		paramBuf,
   261 		numParams))
   262 		== NULL)
   263 	{
   264 		if (!vc->call)
   265 		{
   266 			delete vc;
   267 			return NULL;
   268 		}
   269 	}
   270 
   271 	/* Allocate extra space for thisptr AND ret buffer, even if we don't use it */
   272 	vc->vparams = new ValvePassInfo[numParams + 2];
   273 
   274 	/* We've got the call and everything is encoded.
   275 	 * It's time to save the valve specific information and helper variables.
   276 	 */
   277 	if (retInfo)
   278 	{
   279 		/* Allocate and copy */
   280 		vc->retinfo = &(vc->vparams[numParams]);
   281 		*vc->retinfo = *retInfo;
   282 		vc->retinfo->offset = 0;
   283 		vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0;
   284 		/* Allocate stack space */
   285 		vc->retbuf = new unsigned char[retBufSize];
   286 	} else {
   287 		vc->retinfo = NULL;
   288 		vc->retbuf = NULL;
   289 	}
   290 
   291 	/* Save the this info for the dynamic decoder */
   292 	vc->thisinfo = &(vc->vparams[numParams + 1]);
   293 	vc->thisinfo->type = PassType_Basic;
   294 	if (vcalltype == ValveCall_Entity)
   295 	{
   296 		vc->thisinfo->vtype = Valve_CBaseEntity;
   297 		vc->thisinfo->decflags = VDECODE_FLAG_ALLOWWORLD;
   298 	} else if (vcalltype == ValveCall_Player) {
   299 		vc->thisinfo->vtype = Valve_CBasePlayer;
   300 		vc->thisinfo->decflags = 0;
   301 	}
   302 	vc->thisinfo->encflags = 0;
   303 	vc->thisinfo->flags = PASSFLAG_BYVAL;
   304 	vc->thisinfo->offset = 0;
   305 	vc->thisinfo->obj_offset = 0;
   306 	normSize += sizeof(void *);
   307 
   308 	/* Now, save info about each parameter. */
   309 	size_t last_extra_offset = 0;
   310 	for (unsigned int i=0; i<numParams; i++)
   311 	{
   312 		/* Copy */
   313 		vc->vparams[i] = params[i];
   314 		vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
   315 		vc->vparams[i].obj_offset = last_extra_offset;
   316 		last_extra_offset += sizes[i];
   317 	}
   318 
   319 	vc->stackSize = normSize + extraSize;
   320 	vc->stackEnd = normSize;
   321 
   322 	return vc;
   323 }