1.1 --- a/core/msvc8/sourcemod_mm.vcproj Mon Mar 12 00:07:54 2007 +0000
1.2 +++ b/core/msvc8/sourcemod_mm.vcproj Mon Mar 12 07:08:05 2007 +0000
1.3 @@ -1,7 +1,7 @@
1.4 <?xml version="1.0" encoding="Windows-1252"?>
1.5 <VisualStudioProject
1.6 ProjectType="Visual C++"
1.7 - Version="8,00"
1.8 + Version="8.00"
1.9 Name="sourcemod_mm"
1.10 ProjectGUID="{E39527CD-7CAB-4420-97CC-DA1B93B260BC}"
1.11 RootNamespace="sourcemod_mm"
1.12 @@ -714,6 +714,10 @@
1.13 >
1.14 </File>
1.15 <File
1.16 + RelativePath="..\smn_fakenatives.cpp"
1.17 + >
1.18 + </File>
1.19 + <File
1.20 RelativePath="..\smn_filesystem.cpp"
1.21 >
1.22 </File>
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/core/smn_fakenatives.cpp Mon Mar 12 07:08:05 2007 +0000
2.3 @@ -0,0 +1,430 @@
2.4 +/**
2.5 + * ===============================================================
2.6 + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
2.7 + * ===============================================================
2.8 + *
2.9 + * This file is not open source and may not be copied without explicit
2.10 + * written permission of AlliedModders LLC. This file may not be redistributed
2.11 + * in whole or significant part.
2.12 + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
2.13 + *
2.14 + * Version: $Id$
2.15 + */
2.16 +
2.17 +#include <sh_list.h>
2.18 +#include <sh_string.h>
2.19 +#include "sm_trie.h"
2.20 +#include "sm_globals.h"
2.21 +#include "PluginSys.h"
2.22 +#include "sourcemod.h"
2.23 +#include "sm_stringutil.h"
2.24 +
2.25 +using namespace SourceHook;
2.26 +
2.27 +static cell_t s_curparams[SP_MAX_EXEC_PARAMS+1];
2.28 +static FakeNative *s_curnative = NULL;
2.29 +static IPluginContext *s_curcaller = NULL;
2.30 +
2.31 +cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pData)
2.32 +{
2.33 + FakeNative *native = (FakeNative *)pData;
2.34 +
2.35 + /* Check if too many parameters were passed */
2.36 + if (params[0] > SP_MAX_EXEC_PARAMS)
2.37 + {
2.38 + return pContext->ThrowNativeError("Called native with too many parameters (%d>%d)", params[9], SP_MAX_EXEC_PARAMS);
2.39 + }
2.40 +
2.41 + /* Check if the native is paused */
2.42 + sp_context_t *pNativeCtx = native->ctx->GetContext();
2.43 + if ((pNativeCtx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
2.44 + {
2.45 + return pContext->ThrowNativeError("Plugin owning this native is currently paused.");
2.46 + }
2.47 +
2.48 + CPlugin *pCaller = g_PluginSys.GetPluginByCtx(pContext->GetContext());
2.49 +
2.50 + /* Save any old data on the stack */
2.51 + FakeNative *pSaveNative = s_curnative;
2.52 + IPluginContext *pSaveCaller = s_curcaller;
2.53 + cell_t save_params[SP_MAX_EXEC_PARAMS+1];
2.54 + if (pSaveNative != NULL)
2.55 + {
2.56 + /* Copy all old parameters */
2.57 + for (cell_t i=0; i<=s_curparams[0]; i++)
2.58 + {
2.59 + save_params[i] = s_curparams[i];
2.60 + }
2.61 + }
2.62 +
2.63 + /* Save the current parameters */
2.64 + s_curnative = native;
2.65 + s_curcaller = pContext;
2.66 + for (cell_t i=0; i<=params[0]; i++)
2.67 + {
2.68 + s_curparams[i] = params[i];
2.69 + }
2.70 +
2.71 + /* Push info and execute. */
2.72 + cell_t result = 0;
2.73 + native->call->PushCell(pCaller->GetMyHandle());
2.74 + native->call->PushCell(params[0]);
2.75 + if (native->call->Execute(&result) != SP_ERROR_NONE)
2.76 + {
2.77 + if (pContext->GetContext()->n_err == SP_ERROR_NONE)
2.78 + {
2.79 + pContext->ThrowNativeError("Error encountered while processing a dynamic native");
2.80 + }
2.81 + }
2.82 +
2.83 + /* Restore everything from the stack if necessary */
2.84 + if (pSaveNative != NULL)
2.85 + {
2.86 + s_curnative = pSaveNative;
2.87 + s_curcaller = pSaveCaller;
2.88 + for (cell_t i=0; i<=save_params[0]; i++)
2.89 + {
2.90 + s_curparams[i] = save_params[i];
2.91 + }
2.92 + }
2.93 +
2.94 + return result;
2.95 +}
2.96 +
2.97 +static cell_t CreateNative(IPluginContext *pContext, const cell_t *params)
2.98 +{
2.99 + char *name;
2.100 + pContext->LocalToString(params[1], &name);
2.101 +
2.102 + IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
2.103 + if (!pFunction)
2.104 + {
2.105 + return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
2.106 + }
2.107 +
2.108 + if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter))
2.109 + {
2.110 + return pContext->ThrowNativeError("Fatal error creating dynamic native!");
2.111 + }
2.112 +
2.113 + return 1;
2.114 +}
2.115 +
2.116 +static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params)
2.117 +{
2.118 + if (!s_curnative || (s_curnative->ctx != pContext))
2.119 + {
2.120 + return pContext->ThrowNativeError("Not called from inside a native function");
2.121 + }
2.122 +
2.123 + char buffer[512];
2.124 +
2.125 + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
2.126 +
2.127 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
2.128 + {
2.129 + s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
2.130 + } else {
2.131 + s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
2.132 + }
2.133 +
2.134 + return 0;
2.135 +}
2.136 +
2.137 +static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
2.138 +{
2.139 + if (!s_curnative || (s_curnative->ctx != pContext))
2.140 + {
2.141 + return pContext->ThrowNativeError("Not called from inside a native function");
2.142 + }
2.143 +
2.144 + cell_t param = params[1];
2.145 + if (param < 1 || param > s_curparams[0])
2.146 + {
2.147 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
2.148 + }
2.149 +
2.150 + int err;
2.151 + char *str;
2.152 + if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
2.153 + {
2.154 + return err;
2.155 + }
2.156 +
2.157 + cell_t *addr;
2.158 + pContext->LocalToPhysAddr(params[2], &addr);
2.159 + *addr = (cell_t)strlen(str);
2.160 +
2.161 + return SP_ERROR_NONE;
2.162 +}
2.163 +
2.164 +static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
2.165 +{
2.166 + if (!s_curnative || (s_curnative->ctx != pContext))
2.167 + {
2.168 + return pContext->ThrowNativeError("Not called from inside a native function");
2.169 + }
2.170 +
2.171 + cell_t param = params[1];
2.172 + if (param < 1 || param > s_curparams[0])
2.173 + {
2.174 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
2.175 + }
2.176 +
2.177 + int err;
2.178 + char *str;
2.179 + if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
2.180 + {
2.181 + return err;
2.182 + }
2.183 +
2.184 + size_t bytes = 0;
2.185 + pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
2.186 +
2.187 + cell_t *addr;
2.188 + pContext->LocalToPhysAddr(params[4], &addr);
2.189 + *addr = (cell_t)bytes;
2.190 +
2.191 + return SP_ERROR_NONE;
2.192 +}
2.193 +
2.194 +static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
2.195 +{
2.196 + if (!s_curnative || (s_curnative->ctx != pContext))
2.197 + {
2.198 + return pContext->ThrowNativeError("Not called from inside a native function");
2.199 + }
2.200 +
2.201 + cell_t param = params[1];
2.202 + if (param < 1 || param > s_curparams[0])
2.203 + {
2.204 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
2.205 + }
2.206 +
2.207 + char *str;
2.208 + pContext->LocalToString(params[2], &str);
2.209 +
2.210 + int err;
2.211 + size_t bytes = 0;
2.212 + if (params[4])
2.213 + {
2.214 + err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
2.215 + } else {
2.216 + err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
2.217 + /* Eww */
2.218 + bytes = strlen(str);
2.219 + if (bytes >= (size_t)params[3])
2.220 + {
2.221 + bytes = params[3] - 1;
2.222 + }
2.223 + }
2.224 +
2.225 + if (err != SP_ERROR_NONE)
2.226 + {
2.227 + return err;
2.228 + }
2.229 +
2.230 + cell_t *addr;
2.231 + pContext->LocalToPhysAddr(params[5], &addr);
2.232 + *addr = (cell_t)bytes;
2.233 +
2.234 + return SP_ERROR_NONE;
2.235 +}
2.236 +
2.237 +static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
2.238 +{
2.239 + if (!s_curnative || (s_curnative->ctx != pContext))
2.240 + {
2.241 + return pContext->ThrowNativeError("Not called from inside a native function");
2.242 + }
2.243 +
2.244 + cell_t param = params[1];
2.245 + if (param < 1 || param > s_curparams[0])
2.246 + {
2.247 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
2.248 + }
2.249 +
2.250 + return s_curparams[param];
2.251 +}
2.252 +
2.253 +static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
2.254 +{
2.255 + if (!s_curnative || (s_curnative->ctx != pContext))
2.256 + {
2.257 + return pContext->ThrowNativeError("Not called from inside a native function");
2.258 + }
2.259 +
2.260 + cell_t param = params[1];
2.261 + if (param < 1 || param > s_curparams[0])
2.262 + {
2.263 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
2.264 + }
2.265 +
2.266 + cell_t *addr;
2.267 + if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
2.268 + {
2.269 + return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
2.270 + }
2.271 +
2.272 + return *addr;
2.273 +}
2.274 +
2.275 +static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params)
2.276 +{
2.277 + if (!s_curnative || (s_curnative->ctx != pContext))
2.278 + {
2.279 + return pContext->ThrowNativeError("Not called from inside a native function");
2.280 + }
2.281 +
2.282 + cell_t param = params[1];
2.283 + if (param < 1 || param > s_curparams[0])
2.284 + {
2.285 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
2.286 + }
2.287 +
2.288 + cell_t *addr;
2.289 + if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
2.290 + {
2.291 + return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
2.292 + }
2.293 +
2.294 + *addr = params[2];
2.295 +
2.296 + return 1;
2.297 +}
2.298 +
2.299 +static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
2.300 +{
2.301 + if (!s_curnative || (s_curnative->ctx != pContext))
2.302 + {
2.303 + return pContext->ThrowNativeError("Not called from inside a native function");
2.304 + }
2.305 +
2.306 + cell_t param = params[1];
2.307 + if (param < 1 || param > s_curparams[0])
2.308 + {
2.309 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
2.310 + }
2.311 +
2.312 + int err;
2.313 + cell_t *addr;
2.314 + if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
2.315 + {
2.316 + return err;
2.317 + }
2.318 +
2.319 + cell_t *src;
2.320 + pContext->LocalToPhysAddr(params[2], &src);
2.321 +
2.322 + memcpy(src, addr, sizeof(cell_t) * params[3]);
2.323 +
2.324 + return SP_ERROR_NONE;
2.325 +}
2.326 +
2.327 +static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
2.328 +{
2.329 + if (!s_curnative || (s_curnative->ctx != pContext))
2.330 + {
2.331 + return pContext->ThrowNativeError("Not called from inside a native function");
2.332 + }
2.333 +
2.334 + cell_t param = params[1];
2.335 + if (param < 1 || param > s_curparams[0])
2.336 + {
2.337 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
2.338 + }
2.339 +
2.340 + int err;
2.341 + cell_t *addr;
2.342 + if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
2.343 + {
2.344 + return err;
2.345 + }
2.346 +
2.347 + cell_t *src;
2.348 + pContext->LocalToPhysAddr(params[2], &src);
2.349 +
2.350 + memcpy(addr, src, sizeof(cell_t) * params[3]);
2.351 +
2.352 + return SP_ERROR_NONE;
2.353 +}
2.354 +
2.355 +static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
2.356 +{
2.357 + if (!s_curnative || (s_curnative->ctx != pContext))
2.358 + {
2.359 + return pContext->ThrowNativeError("Not called from inside a native function");
2.360 + }
2.361 +
2.362 + int out_param = params[1];
2.363 + int fmt_param = params[2];
2.364 + int var_param = params[3];
2.365 +
2.366 + /* Validate input */
2.367 + if (out_param && (out_param < 1 || out_param > s_curparams[0]))
2.368 + {
2.369 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
2.370 + }
2.371 + if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
2.372 + {
2.373 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
2.374 + }
2.375 + if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
2.376 + {
2.377 + return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
2.378 + }
2.379 +
2.380 + /* Get buffer information */
2.381 + int err;
2.382 + char *output_buffer;
2.383 + char *format_buffer;
2.384 +
2.385 + if (out_param)
2.386 + {
2.387 + if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
2.388 + {
2.389 + return err;
2.390 + }
2.391 + } else {
2.392 + pContext->LocalToString(params[6], &output_buffer);
2.393 + }
2.394 +
2.395 + if (fmt_param)
2.396 + {
2.397 + if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
2.398 + {
2.399 + return err;
2.400 + }
2.401 + } else {
2.402 + pContext->LocalToString(params[7], &format_buffer);
2.403 + }
2.404 +
2.405 + /* Get maximum length */
2.406 + size_t maxlen = (size_t)params[4];
2.407 +
2.408 + /* Do the format */
2.409 + size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
2.410 +
2.411 + cell_t *addr;
2.412 + pContext->LocalToPhysAddr(params[5], &addr);
2.413 + *addr = (cell_t)written;
2.414 +
2.415 + return s_curcaller->GetContext()->n_err;
2.416 +}
2.417 +
2.418 +//tee hee
2.419 +REGISTER_NATIVES(nativeNatives)
2.420 +{
2.421 + {"CreateNative", CreateNative},
2.422 + {"GetNativeArray", GetNativeArray},
2.423 + {"GetNativeCell", GetNativeCell},
2.424 + {"GetNativeCellRef", GetNativeCellRef},
2.425 + {"GetNativeString", GetNativeString},
2.426 + {"GetNativeStringLength", GetNativeStringLength},
2.427 + {"FormatNativeString", FormatNativeString},
2.428 + {"ThrowNativeError", ThrowNativeError},
2.429 + {"SetNativeArray", SetNativeArray},
2.430 + {"SetNativeCellRef", SetNativeCellRef},
2.431 + {"SetNativeString", SetNativeString},
2.432 + {NULL, NULL},
2.433 +};
3.1 --- a/core/systems/PluginSys.cpp Mon Mar 12 00:07:54 2007 +0000
3.2 +++ b/core/systems/PluginSys.cpp Mon Mar 12 07:08:05 2007 +0000
3.3 @@ -588,6 +588,7 @@
3.4 m_LoadLookup = sm_trie_create();
3.5 m_AllPluginsLoaded = false;
3.6 m_MyIdent = NULL;
3.7 + m_pNativeLookup = sm_trie_create();
3.8 }
3.9
3.10 CPluginManager::~CPluginManager()
3.11 @@ -598,9 +599,9 @@
3.12 * will crash anyway. YAY
3.13 */
3.14 sm_trie_destroy(m_LoadLookup);
3.15 + sm_trie_destroy(m_pNativeLookup);
3.16 }
3.17
3.18 -
3.19 void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
3.20 {
3.21 /* First read in the database of plugin settings */
3.22 @@ -958,6 +959,7 @@
3.23
3.24 /* Bind all extra natives */
3.25 g_Extensions.BindAllNativesToPlugin(pPlugin);
3.26 + AddFakeNativesToPlugin(pPlugin);
3.27
3.28 /* Find any unbound natives
3.29 * Right now, these are not allowed
3.30 @@ -1013,6 +1015,32 @@
3.31 }
3.32 }
3.33
3.34 +void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin)
3.35 +{
3.36 + IPluginContext *pContext = pPlugin->GetBaseContext();
3.37 + sp_nativeinfo_t native;
3.38 +
3.39 + List<FakeNative *>::iterator iter;
3.40 + FakeNative *pNative;
3.41 + sp_context_t *ctx;
3.42 + for (iter = m_Natives.begin(); iter != m_Natives.end(); iter++)
3.43 + {
3.44 + pNative = (*iter);
3.45 + ctx = pNative->ctx->GetContext();
3.46 + if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
3.47 + {
3.48 + /* Ignore natives in paused plugins */
3.49 + continue;
3.50 + }
3.51 + native.name = pNative->name.c_str();
3.52 + native.func = pNative->func;
3.53 + if (pContext->BindNative(&native) == SP_ERROR_NONE)
3.54 + {
3.55 + /* :TODO: add to dependency list */
3.56 + }
3.57 + }
3.58 +}
3.59 +
3.60 bool CPluginManager::UnloadPlugin(IPlugin *plugin)
3.61 {
3.62 CPlugin *pPlugin = (CPlugin *)plugin;
3.63 @@ -1675,3 +1703,28 @@
3.64 }
3.65 }
3.66
3.67 +bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func)
3.68 +{
3.69 + if (sm_trie_retrieve(m_pNativeLookup, name, NULL))
3.70 + {
3.71 + return false;
3.72 + }
3.73 +
3.74 + FakeNative *pNative = new FakeNative;
3.75 +
3.76 + pNative->func = g_pVM->CreateFakeNative(func, pNative);
3.77 + if (!pNative->func)
3.78 + {
3.79 + delete pNative;
3.80 + return false;
3.81 + }
3.82 +
3.83 + pNative->call = pFunction;
3.84 + pNative->name.assign(name);
3.85 + pNative->ctx = pFunction->GetParentContext();
3.86 +
3.87 + m_Natives.push_back(pNative);
3.88 + sm_trie_insert(m_pNativeLookup, name,pNative);
3.89 +
3.90 + return true;
3.91 +}
4.1 --- a/core/systems/PluginSys.h Mon Mar 12 00:07:54 2007 +0000
4.2 +++ b/core/systems/PluginSys.h Mon Mar 12 07:08:05 2007 +0000
4.3 @@ -22,6 +22,7 @@
4.4 #include <sh_list.h>
4.5 #include <sh_stack.h>
4.6 #include <sh_vector.h>
4.7 +#include <sh_string.h>
4.8 #include "sm_globals.h"
4.9 #include "vm/sp_vm_basecontext.h"
4.10 #include "PluginInfoDatabase.h"
4.11 @@ -232,6 +233,14 @@
4.12 Trie *m_pProps;
4.13 };
4.14
4.15 +struct FakeNative
4.16 +{
4.17 + IPluginContext *ctx;
4.18 + IPluginFunction *call;
4.19 + String name;
4.20 + SPVM_NATIVE_FUNC func;
4.21 +};
4.22 +
4.23 class CPluginManager :
4.24 public IPluginManager,
4.25 public SMGlobalClass,
4.26 @@ -380,6 +389,10 @@
4.27 {
4.28 return m_MyIdent;
4.29 }
4.30 +public:
4.31 + bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
4.32 +private:
4.33 + void AddFakeNativesToPlugin(CPlugin *pPlugin);
4.34 private:
4.35 List<IPluginsListener *> m_listeners;
4.36 List<CPlugin *> m_plugins;
4.37 @@ -389,6 +402,11 @@
4.38 Trie *m_LoadLookup;
4.39 bool m_AllPluginsLoaded;
4.40 IdentityToken_t *m_MyIdent;
4.41 +
4.42 + /* Dynamic native stuff */
4.43 + List<FakeNative *> m_Natives;
4.44 + Trie *m_pNativeLookup;
4.45 +
4.46 };
4.47
4.48 extern CPluginManager g_PluginSys;
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/plugins/include/functions.inc Mon Mar 12 07:08:05 2007 +0000
5.3 @@ -0,0 +1,205 @@
5.4 +/**
5.5 + * vim: set ts=4 :
5.6 + * ===============================================================
5.7 + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5.8 + * ===============================================================
5.9 + *
5.10 + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used
5.11 + * or modified under the Terms and Conditions of its License Agreement, which is found
5.12 + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins
5.13 + * may change at any time. To view the latest information, see:
5.14 + * http://www.sourcemod.net/license.php
5.15 + *
5.16 + * Version: $Id$
5.17 + */
5.18 +
5.19 +#define SP_ERROR_NONE 0 /**< No error occurred */
5.20 +#define SP_ERROR_FILE_FORMAT 1 /**< File format unrecognized */
5.21 +#define SP_ERROR_DECOMPRESSOR 2 /**< A decompressor was not found */
5.22 +#define SP_ERROR_HEAPLOW 3 /**< Not enough space left on the heap */
5.23 +#define SP_ERROR_PARAM 4 /**< Invalid parameter or parameter type */
5.24 +#define SP_ERROR_INVALID_ADDRESS 5 /**< A memory address was not valid */
5.25 +#define SP_ERROR_NOT_FOUND 6 /**< The object in question was not found */
5.26 +#define SP_ERROR_INDEX 7 /**< Invalid index parameter */
5.27 +#define SP_ERROR_STACKLOW 8 /**< Nnot enough space left on the stack */
5.28 +#define SP_ERROR_NOTDEBUGGING 9 /**< Debug mode was not on or debug section not found */
5.29 +#define SP_ERROR_INVALID_INSTRUCTION 10 /**< Invalid instruction was encountered */
5.30 +#define SP_ERROR_MEMACCESS 11 /**< Invalid memory access */
5.31 +#define SP_ERROR_STACKMIN 12 /**< Stack went beyond its minimum value */
5.32 +#define SP_ERROR_HEAPMIN 13 /**< Heap went beyond its minimum value */
5.33 +#define SP_ERROR_DIVIDE_BY_ZERO 14 /**< Division by zero */
5.34 +#define SP_ERROR_ARRAY_BOUNDS 15 /**< Array index is out of bounds */
5.35 +#define SP_ERROR_INSTRUCTION_PARAM 16 /**< Instruction had an invalid parameter */
5.36 +#define SP_ERROR_STACKLEAK 17 /**< A native leaked an item on the stack */
5.37 +#define SP_ERROR_HEAPLEAK 18 /**< A native leaked an item on the heap */
5.38 +#define SP_ERROR_ARRAY_TOO_BIG 19 /**< A dynamic array is too big */
5.39 +#define SP_ERROR_TRACKER_BOUNDS 20 /**< Tracker stack is out of bounds */
5.40 +#define SP_ERROR_INVALID_NATIVE 21 /**< Native was pending or invalid */
5.41 +#define SP_ERROR_PARAMS_MAX 22 /**< Maximum number of parameters reached */
5.42 +#define SP_ERROR_NATIVE 23 /**< Error originates from a native */
5.43 +#define SP_ERROR_NOT_RUNNABLE 24 /**< Function or plugin is not runnable */
5.44 +#define SP_ERROR_ABORTED 25 /**< Function call was aborted */
5.45 +
5.46 +/**
5.47 + * Defines a native function.
5.48 + *
5.49 + * It is not necessary to validate the parameter count
5.50 + *
5.51 + * @param plugin Handle of the calling plugin.
5.52 + * @param numParams Number of parameters passed to the native.
5.53 + * @return Value for the native call to return.
5.54 + */
5.55 +functag NativeCall public(Handle:plugin, numParams);
5.56 +
5.57 +/**
5.58 + * Creates a dynamic native. This should only be called in AskPluginLoad(), or
5.59 + * else you risk not having your native shared with other plugins.
5.60 + *
5.61 + * @param name Name of the dynamic native; must be unique amongst
5.62 + * all other registered dynamic native.s
5.63 + * @param func Function to use as the dynamic native.
5.64 + * @noreturn
5.65 + */
5.66 +native CreateNative(const String:name[], NativeCall:func);
5.67 +
5.68 +/**
5.69 + * Throws an error in the calling plugin of a native, instead of your own plugin.
5.70 + *
5.71 + * @param error Error code to use.
5.72 + * @param fmt Error message format.
5.73 + * @param ... Format arguments.
5.74 + */
5.75 +native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,_}:...);
5.76 +
5.77 +/**
5.78 + * Retrieves the string length from a native parameter string. This is useful
5.79 + * fetching the entire string using dynamic arrays.
5.80 + * @note If this function succeeds, Get/SetNativeString will also succeed.
5.81 + *
5.82 + * @param param Parameter number, starting from 1.
5.83 + * @param length Stores the length of the string.
5.84 + * @return SP_ERROR_NONE on sucecss, any other integer on failure.
5.85 + * @error Invalid parameter number or calling from a non-native function.
5.86 + */
5.87 +native GetNativeStringLength(param, &length);
5.88 +
5.89 +/**
5.90 + * Retrieves a string from a native parameter.
5.91 + * @note Output conditions are undefined on failure.
5.92 + *
5.93 + * @param param Parameter number, starting from 1.
5.94 + * @param buffer Buffer to store the string in.
5.95 + * @param maxlength Maximum length of the buffer.
5.96 + * @param bytes Optionally store the number of bytes written.
5.97 + * @return SP_ERROR_NONE on success, any other integer on failure.
5.98 + * @error Invalid parameter number or calling from a non-native function.
5.99 + */
5.100 +native GetNativeString(param, String:buffer[], maxlength, &bytes=0);
5.101 +
5.102 +/**
5.103 + * Sets a string in a native parameter.
5.104 + * @note Output conditions are undefined on failure.
5.105 + *
5.106 + * @param param Parameter number, starting from 1.
5.107 + * @param source Source string to use.
5.108 + * @param maxlength Maximum number of bytes to write.
5.109 + * @param utf8 If false, string will not be written
5.110 + * with UTF8 safety.
5.111 + * @param bytes Optionally store the number of bytes written.
5.112 + * @return SP_ERROR_NONE on success, any other integer on failure.
5.113 + * @error Invalid parameter number or calling from a non-native function.
5.114 + */
5.115 +native SetNativeString(param, const String:source[], maxlength, bool:utf8=true, &bytes=0);
5.116 +
5.117 +/**
5.118 + * Gets a cell from a native parameter.
5.119 + *
5.120 + * @param param Parameter number, starting from 1.
5.121 + * @return Cell value at the parameter number.
5.122 + * @error Invalid parameter number or calling from a non-native function.
5.123 + */
5.124 +native GetNativeCell(param);
5.125 +
5.126 +/**
5.127 + * Gets a cell from a native parameter, by reference.
5.128 + *
5.129 + * @param param Parameter number, starting from 1.
5.130 + * @return Cell value at the parameter number.
5.131 + * @error Invalid parameter number or calling from a non-native function.
5.132 + */
5.133 +native GetNativeCellRef(param);
5.134 +
5.135 +/**
5.136 + * Sets a cell from a native parameter, by reference.
5.137 + *
5.138 + * @param param Parameter number, starting from 1.
5.139 + * @param value Cell value at the parameter number to set by reference.
5.140 + * @noreturn
5.141 + * @error Invalid parameter number or calling from a non-native function.
5.142 + */
5.143 +native SetNativeCellRef(param, {Float,Handle,_}:value);
5.144 +
5.145 +/**
5.146 + * Gets an array from a native parameter (always by reference).
5.147 + *
5.148 + * @param param Parameter number, starting from 1.
5.149 + * @param local Local array to copy into.
5.150 + * @param size Maximum size of local array.
5.151 + * @return SP_ERROR_NONE on success, anything else on failure.
5.152 + * @error Invalid parameter number or calling from a non-native function.
5.153 + */
5.154 +native GetNativeArray(param, {Float,Handle,_}:local[], size);
5.155 +
5.156 +/**
5.157 + * Copies a local array into a native parameter array (always by reference).
5.158 + *
5.159 + * @param param Parameter number, starting from 1.
5.160 + * @param local Local array to copy from.
5.161 + * @param size Size of the local array to copy.
5.162 + * @return SP_ERROR_NONE on success, anything else on failure.
5.163 + * @error Invalid parameter number or calling from a non-native function.
5.164 + */
5.165 +native SetNativeArray(param, const {Float,Handle,_}:local[], size);
5.166 +
5.167 +/**
5.168 + * Formats a string using parameters from a native.
5.169 + *
5.170 + * @note All parameter indexes start at 1.
5.171 + * @note If the input and output buffers overlap, the contents
5.172 + * of the output buffer at the end is undefined.
5.173 + *
5.174 + * @param out_param Output parameter number to write to. If 0, out_string is used.
5.175 + * @param fmt_param Format parameter number. If 0, fmt_string is used.
5.176 + * @param vararg_param First variable parameter number.
5.177 + * @param out_len Output string buffer maximum length (always required).
5.178 + * @param written Optionally stores the number of bytes written.
5.179 + * @param out_string Output string buffer to use if out_param is not used.
5.180 + * @param fmt_string Format string to use if fmt_param is not used.
5.181 + * @return SP_ERROR_NONE on success, anything else on failure.
5.182 + */
5.183 +native FormatNativeString(out_param,
5.184 + fmt_param,
5.185 + vararg_param,
5.186 + out_len,
5.187 + &written=0,
5.188 + String:out_string[]="",
5.189 + const String:fmt_string[]="");
5.190 +
5.191 +stock Float:GetNativeFloat(param, bool:byref)
5.192 +{
5.193 + if (!byref)
5.194 + {
5.195 + return Float:GetNativeCell(param);
5.196 + } else {
5.197 + return Float:GetNativeCellRef(param);
5.198 + }
5.199 +}
5.200 +stock Handle:GetNativeHandle(param, bool:byref)
5.201 +{
5.202 + if (!byref)
5.203 + {
5.204 + return Handle:GetNativeCell(param);
5.205 + } else {
5.206 + return Handle:GetNativeCellRef(param);
5.207 + }
5.208 +}
6.1 --- a/plugins/include/sourcemod.inc Mon Mar 12 00:07:54 2007 +0000
6.2 +++ b/plugins/include/sourcemod.inc Mon Mar 12 07:08:05 2007 +0000
6.3 @@ -39,6 +39,7 @@
6.4 #include <clients>
6.5 #include <usermessages>
6.6 #include <events>
6.7 +#include <functions>
6.8
6.9 /**
6.10 * Declare this as a struct in your plugin to expose its information.
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/plugins/testsuite/fakenative1.sp Mon Mar 12 07:08:05 2007 +0000
7.3 @@ -0,0 +1,85 @@
7.4 +#include <sourcemod>
7.5 +
7.6 +public Plugin:myinfo =
7.7 +{
7.8 + name = "FakeNative Testing Lab #1",
7.9 + author = "AlliedModders LLC",
7.10 + description = "Test suite #1 for dynamic natives",
7.11 + version = "1.0.0.0",
7.12 + url = "http://www.sourcemod.net/"
7.13 +};
7.14 +
7.15 +public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
7.16 +{
7.17 + CreateNative("TestNative1", __TestNative1);
7.18 + CreateNative("TestNative2", __TestNative2);
7.19 + CreateNative("TestNative3", __TestNative3);
7.20 + CreateNative("TestNative4", __TestNative4);
7.21 + CreateNative("TestNative5", __TestNative5);
7.22 + return true;
7.23 +}
7.24 +
7.25 +public __TestNative1(Handle:plugin, numParams)
7.26 +{
7.27 + PrintToServer("TestNative1: Plugin: %x params: %d", plugin, numParams);
7.28 + if (numParams == 4)
7.29 + {
7.30 + ThrowNativeError(SP_ERROR_NATIVE, "Four parameters ARE NOT ALLOWED lol");
7.31 + }
7.32 + return 5;
7.33 +}
7.34 +
7.35 +public __TestNative2(Handle:plugin, numParams)
7.36 +{
7.37 + new String:buffer[512];
7.38 + new bytes;
7.39 +
7.40 + GetNativeString(1, buffer, sizeof(buffer), bytes);
7.41 +
7.42 + for (new i=0; i<bytes; i++)
7.43 + {
7.44 + buffer[i] = buffer[i] + 1;
7.45 + }
7.46 +
7.47 + SetNativeString(1, buffer, bytes+1);
7.48 +}
7.49 +
7.50 +public __TestNative3(Handle:plugin, numParams)
7.51 +{
7.52 + new val1 = GetNativeCell(1);
7.53 + new val2 = GetNativeCellRef(2);
7.54 +
7.55 + SetNativeCellRef(2, val1+val2);
7.56 +}
7.57 +
7.58 +public __TestNative4(Handle:plugin, numParams)
7.59 +{
7.60 + new size = GetNativeCell(3);
7.61 + new local[size];
7.62 +
7.63 + GetNativeArray(1, local, size);
7.64 + SetNativeArray(2, local, size);
7.65 +}
7.66 +
7.67 +public __TestNative5(Handle:plugin, numParams)
7.68 +{
7.69 + new local = GetNativeCell(1);
7.70 +
7.71 + if (local)
7.72 + {
7.73 + FormatNativeString(2, 4, 5, GetNativeCell(3));
7.74 + } else {
7.75 + new len = GetNativeCell(3);
7.76 + new fmt_len;
7.77 + new String:buffer[len];
7.78 +
7.79 + GetNativeStringLength(4, fmt_len);
7.80 +
7.81 + new String:format[fmt_len];
7.82 +
7.83 + GetNativeString(2, buffer, len);
7.84 + GetNativeString(4, format, fmt_len);
7.85 +
7.86 + FormatNativeString(0, 0, 5, len, _, buffer, format);
7.87 + }
7.88 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/plugins/testsuite/fakenative2.sp Mon Mar 12 07:08:05 2007 +0000
8.3 @@ -0,0 +1,87 @@
8.4 +#include <sourcemod>
8.5 +
8.6 +native TestNative1(gaben, ...);
8.7 +native TestNative2(String:buffer[]);
8.8 +native TestNative3(value1, &value2);
8.9 +native TestNative4(const input[], output[], size);
8.10 +native TestNative5(bool:local, String:buffer[], maxlength, const String:fmt[], {Handle,Float,String,_}:...);
8.11 +
8.12 +public Plugin:myinfo =
8.13 +{
8.14 + name = "FakeNative Testing Lab #2",
8.15 + author = "AlliedModders LLC",
8.16 + description = "Test suite #2 for dynamic natives",
8.17 + version = "1.0.0.0",
8.18 + url = "http://www.sourcemod.net/"
8.19 +};
8.20 +
8.21 +public OnPluginStart()
8.22 +{
8.23 + RegServerCmd("test_native1", Test_Native1);
8.24 + RegServerCmd("test_native2", Test_Native2);
8.25 + RegServerCmd("test_native3", Test_Native3);
8.26 + RegServerCmd("test_native4", Test_Native4);
8.27 + RegServerCmd("test_native5", Test_Native5);
8.28 +}
8.29 +
8.30 +public Action:Test_Native1(args)
8.31 +{
8.32 + PrintToServer("Returned: %d", TestNative1(1));
8.33 + PrintToServer("Returned: %d", TestNative1(1,2));
8.34 + PrintToServer("Returned: %d", TestNative1(1,2,3,4));
8.35 +
8.36 + return Plugin_Handled;
8.37 +}
8.38 +
8.39 +public Action:Test_Native2(args)
8.40 +{
8.41 + new String:buffer[] = "IBM";
8.42 +
8.43 + PrintToServer("Before: %s", buffer);
8.44 +
8.45 + TestNative2(buffer);
8.46 +
8.47 + PrintToServer("AfteR: %s", buffer);
8.48 +
8.49 + return Plugin_Handled;
8.50 +}
8.51 +
8.52 +public Action:Test_Native3(args)
8.53 +{
8.54 + new value1 = 5, value2 = 6
8.55 +
8.56 + PrintToServer("Before: %d, %d", value1, value2);
8.57 +
8.58 + TestNative3(value1, value2);
8.59 +
8.60 + PrintToServer("After: %d, %d", value1, value2);
8.61 +
8.62 + return Plugin_Handled;
8.63 +}
8.64 +
8.65 +public Action:Test_Native4(args)
8.66 +{
8.67 + new input[5] = {0, 1, 2, 3, 4};
8.68 + new output[5];
8.69 +
8.70 + TestNative4(input, output, 5);
8.71 +
8.72 + PrintToServer("[0=%d] [1=%d] [2=%d] [3=%d] [4=%d]", input[0], input[1], input[2], input[3], input[4]);
8.73 + PrintToServer("[0=%d] [1=%d] [2=%d] [3=%d] [4=%d]", output[0], output[1], output[2], output[3], output[4]);
8.74 +
8.75 + return Plugin_Handled;
8.76 +}
8.77 +
8.78 +public Action:Test_Native5(args)
8.79 +{
8.80 + new String:buffer1[512];
8.81 + new String:buffer2[512];
8.82 +
8.83 + TestNative5(true, buffer1, sizeof(buffer1), "%d gabens in the %s", 50, "gabpark");
8.84 + TestNative5(true, buffer2, sizeof(buffer2), "%d gabens in the %s", 50, "gabpark");
8.85 +
8.86 + PrintToServer("Test 1: %s", buffer1);
8.87 + PrintToServer("Test 2: %s", buffer2);
8.88 +
8.89 + return Plugin_Handled;
8.90 +}
9.1 --- a/public/sourcepawn/sp_vm_api.h Mon Mar 12 00:07:54 2007 +0000
9.2 +++ b/public/sourcepawn/sp_vm_api.h Mon Mar 12 07:08:05 2007 +0000
9.3 @@ -28,7 +28,7 @@
9.4 #include "sp_vm_types.h"
9.5
9.6 /** SourcePawn VM API Version */
9.7 -#define SOURCEPAWN_VM_API_VERSION 1
9.8 +#define SOURCEPAWN_VM_API_VERSION 2
9.9
9.10 #if defined SOURCEMOD_BUILD
9.11 namespace SourceMod
9.12 @@ -820,6 +820,23 @@
9.13 * @return True if code index is valid, false otherwise.
9.14 */
9.15 virtual bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0;
9.16 +
9.17 + /**
9.18 + * @brief Creates a fake native and binds it to a general callback function.
9.19 + *
9.20 + * @param callback Callback function to bind the native to.
9.21 + * @param pData Private data to pass to the callback when the native is invoked.
9.22 + * @return A new fake native function as a wrapper around the callback.
9.23 + */
9.24 + virtual SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) =0;
9.25 +
9.26 + /**
9.27 + * @brief Destroys a fake native function wrapper.
9.28 + *
9.29 + * @param function Pointer to the fake native created by CreateFakeNative.
9.30 + * @noreturn
9.31 + */
9.32 + virtual void DestroyFakenative(SPVM_NATIVE_FUNC func) =0;
9.33 };
9.34 };
9.35
10.1 --- a/public/sourcepawn/sp_vm_types.h Mon Mar 12 00:07:54 2007 +0000
10.2 +++ b/public/sourcepawn/sp_vm_types.h Mon Mar 12 07:08:05 2007 +0000
10.3 @@ -136,6 +136,12 @@
10.4 */
10.5 typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *);
10.6
10.7 +/**
10.8 + * @brief Fake native callback prototype, passed a context, parameter stack, and private data.
10.9 + * A cell must be returned.
10.10 + */
10.11 +typedef cell_t (*SPVM_FAKENATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *, void *);
10.12 +
10.13 /**********************************************
10.14 *** The following structures are bound to the VM/JIT.
10.15 *** Changing them will result in necessary recompilation.
11.1 --- a/sourcepawn/jit/x86/dll_exports.cpp Mon Mar 12 00:07:54 2007 +0000
11.2 +++ b/sourcepawn/jit/x86/dll_exports.cpp Mon Mar 12 07:08:05 2007 +0000
11.3 @@ -17,7 +17,7 @@
11.4 #include "dll_exports.h"
11.5
11.6 SourcePawn::ISourcePawnEngine *engine = NULL;
11.7 -JITX86 jit;
11.8 +JITX86 g_jit;
11.9
11.10 EXPORTFUNC int GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p)
11.11 {
11.12 @@ -45,7 +45,7 @@
11.13 return NULL;
11.14 }
11.15
11.16 - return &jit;
11.17 + return &g_jit;
11.18 }
11.19
11.20 #if defined __linux__
12.1 --- a/sourcepawn/jit/x86/jit_x86.cpp Mon Mar 12 00:07:54 2007 +0000
12.2 +++ b/sourcepawn/jit/x86/jit_x86.cpp Mon Mar 12 07:08:05 2007 +0000
12.3 @@ -2188,6 +2188,52 @@
12.4 return ctx;
12.5 }
12.6
12.7 +SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
12.8 +{
12.9 + JitWriter jw;
12.10 + JitWriter *jit = &jw;
12.11 +
12.12 + jw.outbase = NULL;
12.13 + jw.outptr = NULL;
12.14 + jw.data = NULL;
12.15 +
12.16 + /* First pass, calculate size */
12.17 +rewind:
12.18 + //push pData ;push pData
12.19 + //push [esp+12] ;push params
12.20 + //push [esp+12] ;push ctx
12.21 + //call [callback] ;invoke the meta-callback
12.22 + //add esp, 12 ;restore the stack
12.23 + //ret ;return
12.24 + IA32_Push_Imm32(jit, (jit_int32_t)pData);
12.25 + IA32_Push_Rm_Disp8_ESP(jit, 12);
12.26 + IA32_Push_Rm_Disp8_ESP(jit, 12);
12.27 + uint32_t call = IA32_Call_Imm32(jit, 0);
12.28 + IA32_Write_Jump32_Abs(jit, call, (void *)callback);
12.29 + IA32_Add_Rm_Imm8(jit, REG_ESP, 12, MOD_REG);
12.30 + IA32_Return(jit);
12.31 +
12.32 + if (jw.outbase == NULL)
12.33 + {
12.34 + /* Second pass: Actually write */
12.35 + jw.outbase = (jitcode_t)engine->ExecAlloc(jw.get_outputpos());
12.36 + if (!jw.outbase)
12.37 + {
12.38 + return NULL;
12.39 + }
12.40 + jw.outptr = jw.outbase;
12.41 +
12.42 + goto rewind;
12.43 + }
12.44 +
12.45 + return (SPVM_NATIVE_FUNC)jw.outbase;
12.46 +}
12.47 +
12.48 +void JITX86::DestroyFakenative(SPVM_NATIVE_FUNC func)
12.49 +{
12.50 + engine->ExecFree(func);
12.51 +}
12.52 +
12.53 const char *JITX86::GetVMName()
12.54 {
12.55 return "JIT (x86)";
13.1 --- a/sourcepawn/jit/x86/jit_x86.h Mon Mar 12 00:07:54 2007 +0000
13.2 +++ b/sourcepawn/jit/x86/jit_x86.h Mon Mar 12 07:08:05 2007 +0000
13.3 @@ -98,6 +98,8 @@
13.4 unsigned int FunctionCount(const sp_context_t *ctx);
13.5 const char *GetVersionString();
13.6 const char *GetCPUOptimizations();
13.7 + SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
13.8 + void DestroyFakenative(SPVM_NATIVE_FUNC func);
13.9 };
13.10
13.11 cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
14.1 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj Mon Mar 12 00:07:54 2007 +0000
14.2 +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj Mon Mar 12 07:08:05 2007 +0000
14.3 @@ -235,6 +235,10 @@
14.4 UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
14.5 >
14.6 <File
14.7 + RelativePath="..\jit_version.tpl"
14.8 + >
14.9 + </File>
14.10 + <File
14.11 RelativePath="..\opcode_switch.inc"
14.12 >
14.13 </File>