Files
m2dev-client-src/src/ScriptLib/PythonLauncher.cpp
2026-02-03 11:12:32 +00:00

319 lines
6.1 KiB
C++

#include "StdAfx.h"
#include <python/frameobject.h>
#ifdef BYTE
#undef BYTE
#endif
#include "PackLib/PackManager.h"
#include "PythonLauncher.h"
#include <utf8.h>
CPythonLauncher::CPythonLauncher()
{
Py_Initialize();
}
CPythonLauncher::~CPythonLauncher()
{
Clear();
}
void CPythonLauncher::Clear()
{
Py_Finalize();
}
std::string g_stTraceBuffer[512];
int g_nCurTraceN = 0;
void Traceback()
{
std::string str;
for (int i = 0; i < g_nCurTraceN; ++i)
{
str.append(g_stTraceBuffer[i]);
str.append("\n");
}
PyObject * exc;
PyObject * v;
PyObject * tb;
PyErr_Fetch(&exc, &v, &tb);
PyErr_NormalizeException(&exc, &v, &tb);
if (exc)
{
PyObject* excName = PyObject_GetAttrString(exc, "__name__");
if (excName && PyString_Check(excName))
{
str.append(PyString_AS_STRING(excName));
str.append(": ");
}
Py_XDECREF(excName);
}
if (v)
{
PyObject* vStr = PyObject_Str(v);
if (vStr && PyString_Check(vStr))
{
const char* errStr = PyString_AS_STRING(vStr);
str.append(errStr);
Tracef("%s\n", errStr);
}
Py_XDECREF(vStr);
}
Py_XDECREF(exc);
Py_XDECREF(v);
Py_XDECREF(tb);
LogBoxf("Traceback:\n\n%s\n", str.c_str());
}
int TraceFunc(PyObject * obj, PyFrameObject * f, int what, PyObject *arg)
{
const char * funcname;
char szTraceBuffer[128];
switch (what)
{
case PyTrace_CALL:
if (g_nCurTraceN >= 512)
return 0;
if (Py_OptimizeFlag)
f->f_lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
funcname = PyString_AsString(f->f_code->co_name);
_snprintf(szTraceBuffer, sizeof(szTraceBuffer), "Call: File \"%s\", line %d, in %s",
PyString_AsString(f->f_code->co_filename),
f->f_lineno,
funcname);
g_stTraceBuffer[g_nCurTraceN++]=szTraceBuffer;
break;
case PyTrace_RETURN:
if (g_nCurTraceN > 0)
--g_nCurTraceN;
break;
case PyTrace_EXCEPTION:
if (g_nCurTraceN >= 512)
return 0;
PyObject * exc_type, * exc_value, * exc_traceback;
PyTuple_GetObject(arg, 0, &exc_type);
PyTuple_GetObject(arg, 1, &exc_value);
PyTuple_GetObject(arg, 2, &exc_traceback);
Py_ssize_t len;
const char * exc_str;
PyObject_AsCharBuffer(exc_type, &exc_str, &len);
_snprintf(szTraceBuffer, sizeof(szTraceBuffer), "Exception: File \"%s\", line %d, in %s",
PyString_AS_STRING(f->f_code->co_filename),
f->f_lineno,
PyString_AS_STRING(f->f_code->co_name));
g_stTraceBuffer[g_nCurTraceN++]=szTraceBuffer;
break;
}
return 0;
}
void CPythonLauncher::SetTraceFunc(int (*pFunc)(PyObject * obj, PyFrameObject * f, int what, PyObject *arg))
{
PyEval_SetTrace(pFunc, NULL);
}
bool CPythonLauncher::Create(const char* c_szProgramName)
{
NANOBEGIN
Py_SetProgramName((char*)c_szProgramName);
#ifdef _DEBUG
PyEval_SetTrace(TraceFunc, NULL);
#endif
m_poModule = PyImport_AddModule((char *) "__main__");
if (!m_poModule)
return false;
m_poDic = PyModule_GetDict(m_poModule);
PyObject * builtins = PyImport_ImportModule("__builtin__");
PyModule_AddIntConstant(builtins, "TRUE", 1);
PyModule_AddIntConstant(builtins, "FALSE", 0);
PyDict_SetItemString(m_poDic, "__builtins__", builtins);
Py_DECREF(builtins);
if (!RunLine("import __main__"))
return false;
if (!RunLine("import sys"))
return false;
NANOEND
return true;
}
bool CPythonLauncher::RunCompiledFile(const char* c_szFileName)
{
NANOBEGIN
// UTF-8 → UTF-16 conversion for Unicode path support
std::wstring wFileName = Utf8ToWide(c_szFileName);
FILE * fp = _wfopen(wFileName.c_str(), L"rb");
if (!fp)
return false;
PyCodeObject *co;
PyObject *v;
long magic;
long PyImport_GetMagicNumber(void);
magic = _PyMarshal_ReadLongFromFile(fp);
if (magic != PyImport_GetMagicNumber())
{
PyErr_SetString(PyExc_RuntimeError, "Bad magic number in .pyc file");
fclose(fp);
return false;
}
_PyMarshal_ReadLongFromFile(fp);
v = _PyMarshal_ReadLastObjectFromFile(fp);
fclose(fp);
if (!v || !PyCode_Check(v))
{
Py_XDECREF(v);
PyErr_SetString(PyExc_RuntimeError, "Bad code object in .pyc file");
return false;
}
co = (PyCodeObject *) v;
v = PyEval_EvalCode(co, m_poDic, m_poDic);
/* if (v && flags)
flags->cf_flags |= (co->co_flags & PyCF_MASK);*/
Py_DECREF(co);
if (!v)
{
Traceback();
return false;
}
Py_DECREF(v);
if (Py_FlushLine())
PyErr_Clear();
NANOEND
return true;
}
bool CPythonLauncher::RunMemoryTextFile(const char* c_szFileName, UINT uFileSize, const VOID* c_pvFileData)
{
NANOBEGIN
const CHAR* c_pcFileData=(const CHAR*)c_pvFileData;
std::string stConvFileData;
stConvFileData.reserve(uFileSize);
stConvFileData+="exec(compile('''";
// ConvertPythonTextFormat
{
for (UINT i=0; i<uFileSize; ++i)
{
if (c_pcFileData[i]!=13)
stConvFileData+=c_pcFileData[i];
}
}
stConvFileData+= "''', ";
stConvFileData+= "'";
stConvFileData+= c_szFileName;
stConvFileData+= "', ";
stConvFileData+= "'exec'))";
const CHAR* c_pcConvFileData=stConvFileData.c_str();
NANOEND
return RunLine(c_pcConvFileData);
}
bool CPythonLauncher::RunFile(const char* c_szFileName)
{
TPackFile file;
CPackManager::Instance().GetFile(c_szFileName, file);
if (file.empty())
return false;
// Convert \r\n to \n and null-terminate
std::string source;
source.reserve(file.size());
for (size_t i = 0; i < file.size(); ++i)
{
if (file[i] != '\r')
source += (char)file[i];
}
// Compile directly with the filename for proper error reporting
PyObject* code = Py_CompileString(source.c_str(), c_szFileName, Py_file_input);
if (!code)
{
Traceback();
return false;
}
PyObject* result = PyEval_EvalCode((PyCodeObject*)code, m_poDic, m_poDic);
Py_DECREF(code);
if (!result)
{
Traceback();
return false;
}
Py_DECREF(result);
if (Py_FlushLine())
PyErr_Clear();
return true;
}
bool CPythonLauncher::RunLine(const char* c_szSrc)
{
PyObject * v = PyRun_String((char *) c_szSrc, Py_file_input, m_poDic, m_poDic);
if (!v)
{
Traceback();
return false;
}
Py_DECREF(v);
return true;
}
const char* CPythonLauncher::GetError()
{
PyObject* exc;
PyObject* v;
PyObject* tb;
PyErr_Fetch(&exc, &v, &tb);
if (PyString_Check(v))
return PyString_AS_STRING(v);
return "";
}