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