From 330a049abf18835f5cc8227dffe6bdeb4c55df82 Mon Sep 17 00:00:00 2001 From: MCMrARM Date: Wed, 10 Jan 2018 15:51:46 +0100 Subject: [PATCH] dlsym() wrapper generator script (work-in-progress) --- CMakeLists.txt | 3 +- src/main.cpp | 40 +- src/minecraft/App.h | 6 +- src/minecraft/AppPlatform.h | 19 +- src/minecraft/AutomationClient.h | 6 +- src/minecraft/CommandOutput.h | 6 +- src/minecraft/CommandOutputSender.h | 18 +- src/minecraft/Common.h | 2 +- src/minecraft/DedicatedServerCommandOrigin.h | 6 +- src/minecraft/FilePathManager.h | 6 +- src/minecraft/I18n.h | 11 +- src/minecraft/ImagePickingCallback.h | 6 +- src/minecraft/Keyboard.h | 4 +- src/minecraft/LevelSettings.h | 12 +- src/minecraft/Minecraft.h | 6 +- src/minecraft/MinecraftCommands.h | 11 +- src/minecraft/MinecraftEventing.h | 14 +- src/minecraft/MinecraftGame.h | 27 +- src/minecraft/Mouse.h | 2 +- src/minecraft/MultiplayerService.h | 6 +- src/minecraft/Options.h | 11 +- src/minecraft/ResourcePack.h | 41 +- src/minecraft/ResourcePackStack.h | 6 +- src/minecraft/Scheduler.h | 3 +- src/minecraft/ServerInstance.h | 17 +- src/minecraft/UUID.h | 2 +- src/minecraft/UserManager.h | 2 +- src/minecraft/Xbox.h | 3 +- src/minecraft/gl.h | 11 +- src/minecraft/symbols.cpp | 336 +++ src/minecraft/symbols.h | 3 + src/minecraft/types.cpp | 102 +- src/server.cpp | 38 +- tools/cppheaderparser/CppHeaderParser.py | 2642 ++++++++++++++++++ tools/cppheaderparser/__init__.py | 6 + tools/process_headers.py | 218 ++ 36 files changed, 3288 insertions(+), 364 deletions(-) create mode 100644 src/minecraft/symbols.cpp create mode 100644 src/minecraft/symbols.h create mode 100644 tools/cppheaderparser/CppHeaderParser.py create mode 100644 tools/cppheaderparser/__init__.py create mode 100644 tools/process_headers.py diff --git a/CMakeLists.txt b/CMakeLists.txt index d505be2..15b40fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,11 +38,12 @@ endif() include_directories(${PNG_INCLUDE_DIRS}) include_directories(eglut) include_directories(libs/rapidxml) +include_directories(hybris/include) set(HYBRIS_SOURCES hybris/src/cache.c hybris/src/dlfcn.c hybris/src/hooks.c hybris/src/hooks_shm.c hybris/src/logging.c hybris/src/properties.c hybris/src/strlcpy.c hybris/src/ctype.c hybris/src/sysconf.c hybris/src/jb/dlfcn.c hybris/src/jb/linker.c hybris/src/jb/linker_environ.c hybris/src/jb/linker_format.c hybris/src/jb/rt.c) set(EGLUT_SOURCES eglut/eglut.c eglut/eglut_x11.c) -set(COMMON_SOURCE_FILES src/common.cpp src/hook.cpp src/linux_appplatform.cpp src/minecraft/types.cpp src/minecraft/ImagePickingCallback.h src/minecraft/FilePickerSettings.h src/minecraft/Common.h src/minecraft/Xbox.h src/minecraft/string.cpp src/minecraft/string.h src/base64.cpp src/base64.h src/async_result_util.h src/extract.cpp src/extract.h src/path_helper.cpp src/path_helper.h src/log.cpp src/log.h) +set(COMMON_SOURCE_FILES src/common.cpp src/hook.cpp src/linux_appplatform.cpp src/minecraft/types.cpp src/minecraft/ImagePickingCallback.h src/minecraft/FilePickerSettings.h src/minecraft/Common.h src/minecraft/Xbox.h src/minecraft/string.cpp src/minecraft/string.h src/base64.cpp src/base64.h src/async_result_util.h src/extract.cpp src/extract.h src/path_helper.cpp src/path_helper.h src/log.cpp src/log.h src/minecraft/symbols.cpp src/minecraft/symbols.h) set(CLIENT_SOURCE_FILES src/main.cpp src/amdfix.s src/linux_appplatform.cpp src/msa.cpp src/msa.h src/msa_token.h src/msa_network.cpp src/msa_network.h src/xboxlive.h src/xboxlive.cpp src/cll.cpp src/cll.h) set(CLIENT_SOURCE_FILES_CEF src/browser.cpp src/browser.h src/xbox_login_browser.h src/xbox_login_browser.cpp src/initial_setup_browser.cpp src/initial_setup_browser.h) set(CLIENT_SOURCE_FILES_PLAYAPI gplay_api/src/config.h gplay_api/src/config.cpp src/google_login_browser.h src/google_login_browser.cpp src/google_play_helper.cpp src/google_play_helper.h) diff --git a/src/main.cpp b/src/main.cpp index 5d0755f..a127eeb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,6 +21,7 @@ #include "symbols/egl_symbols.h" #include "symbols/fmod_symbols.h" #include "symbols/libm_symbols.h" +#include "minecraft/symbols.h" #include "minecraft/gl.h" #include "minecraft/AppPlatform.h" #include "minecraft/MinecraftGame.h" @@ -177,7 +178,7 @@ static void minecraft_keyboard(char str[5], int action) { } std::stringstream ss; ss << str; - Keyboard::Keyboard_feedText(ss.str(), false, 0); + Keyboard::feedText(ss.str(), false, 0); } } bool modCTRL = false; @@ -195,10 +196,10 @@ static void minecraft_keyboard_special(int key, int action) { } int mKey = getKeyMinecraft(key); if (action == EGLUT_KEY_PRESS) { - Keyboard::Keyboard_feed((unsigned char) mKey, 1); + Keyboard::feed((unsigned char) mKey, 1); //Keyboard::states[mKey] = 1; } else if (action == EGLUT_KEY_RELEASE) { - Keyboard::Keyboard_feed((unsigned char) mKey, 0); + Keyboard::feed((unsigned char) mKey, 0); //Keyboard::states[mKey] = 0; } } @@ -210,7 +211,7 @@ static void minecraft_paste(const char* str, int len) { l = 3; else if ((c & 0b11100000) == 0b11000000) l = 2; - Keyboard::Keyboard_feedText(mcpe::string(&str[i], (size_t) l), false, 0); + Keyboard::feedText(mcpe::string(&str[i], (size_t) l), false, 0); } } static void minecraft_close() { @@ -545,39 +546,17 @@ int main(int argc, char *argv[]) { mcpe::string::empty = (mcpe::string*) hybris_dlsym(handle, "_ZN4Util12EMPTY_STRINGE"); - Common::Common_getGameVersionStringNet = (mcpe::string (*)()) hybris_dlsym(handle, "_ZN6Common23getGameVersionStringNetEv"); + minecraft_symbols_init(handle); - Log::info("Launcher", "Game version: %s", Common::Common_getGameVersionStringNet().c_str()); - XboxLiveHelper::getCLL()->setAppVersion(Common::Common_getGameVersionStringNet().std()); - - gl::getOpenGLVendor = (mcpe::string (*)()) hybris_dlsym(handle, "_ZN2gl15getOpenGLVendorEv"); - gl::getOpenGLRenderer = (mcpe::string (*)()) hybris_dlsym(handle, "_ZN2gl17getOpenGLRendererEv"); - gl::getOpenGLVersion = (mcpe::string (*)()) hybris_dlsym(handle, "_ZN2gl16getOpenGLVersionEv"); - gl::getOpenGLExtensions = (mcpe::string (*)()) hybris_dlsym(handle, "_ZN2gl19getOpenGLExtensionsEv"); - mce::Platform::OGL::OGL_initBindings = (void (*)()) hybris_dlsym(handle, "_ZN3mce8Platform3OGL12InitBindingsEv"); + Log::info("Launcher", "Game version: %s", Common::getGameVersionStringNet().c_str()); + XboxLiveHelper::getCLL()->setAppVersion(Common::getGameVersionStringNet().std()); AppPlatform::myVtable = (void**) hybris_dlsym(handle, "_ZTV11AppPlatform"); AppPlatform::_singleton = (AppPlatform**) hybris_dlsym(handle, "_ZN11AppPlatform10mSingletonE"); - AppPlatform::AppPlatform_construct = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatformC2Ev"); - AppPlatform::AppPlatform_initialize = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatform10initializeEv"); - AppPlatform::AppPlatform__fireAppFocusGained = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatform19_fireAppFocusGainedEv"); - App::App_init = (void (*)(App*, AppContext&)) hybris_dlsym(handle, "_ZN3App4initER10AppContext"); - MinecraftGame::MinecraftGame_construct = (void (*)(MinecraftGame*, int, char**)) hybris_dlsym(handle, "_ZN13MinecraftGameC2EiPPc"); MinecraftGame::MinecraftGame_destruct = (void (*)(MinecraftGame*)) hybris_dlsym(handle, "_ZN13MinecraftGameD2Ev"); - MinecraftGame::MinecraftGame_update = (void (*)(MinecraftGame*)) hybris_dlsym(handle, "_ZN13MinecraftGame6updateEv"); - MinecraftGame::MinecraftGame_setRenderingSize = (void (*)(MinecraftGame*, int, int)) hybris_dlsym(handle, "_ZN13MinecraftGame16setRenderingSizeEii"); - MinecraftGame::MinecraftGame_setUISizeAndScale = (void (*)(MinecraftGame*, int, int, float)) hybris_dlsym(handle, "_ZN13MinecraftGame17setUISizeAndScaleEiif"); - MinecraftGame::MinecraftGame_getPrimaryUserOptions = (std::shared_ptr (*)(MinecraftGame*)) hybris_dlsym(handle, "_ZN13MinecraftGame21getPrimaryUserOptionsEv"); - - Options::Options_getFullscreen = (bool (*)(Options*)) hybris_dlsym(handle, "_ZNK7Options13getFullscreenEv"); - Options::Options_setFullscreen = (void (*)(Options*, bool)) hybris_dlsym(handle, "_ZN7Options13setFullscreenEb"); - - Mouse::feed = (void (*)(char, char, short, short, short, short)) hybris_dlsym(handle, "_ZN5Mouse4feedEccssss"); Keyboard::states = (int*) hybris_dlsym(handle, "_ZN8Keyboard7_statesE"); - Keyboard::Keyboard_feed = (void (*)(unsigned char, int)) hybris_dlsym(handle, "_ZN8Keyboard4feedEhi"); - Keyboard::Keyboard_feedText = (void (*)(const mcpe::string&, bool, unsigned char)) hybris_dlsym(handle, "_ZN8Keyboard8feedTextERKSsbh"); xbox::services::xbox_services_error_code_category = (void* (*)()) hybris_dlsym(handle, "_ZN4xbox8services33xbox_services_error_code_categoryEv"); pplx::task_completion_event_java_rps_ticket::task_completion_event_java_rps_ticket_set = (void (*)(pplx::task_completion_event_java_rps_ticket*, xbox::services::system::java_rps_ticket)) hybris_dlsym(handle, "_ZNK4pplx21task_completion_eventIN4xbox8services6system15java_rps_ticketEE3setES4_"); @@ -597,7 +576,6 @@ int main(int argc, char *argv[]) { xbox::services::system::auth_config::auth_config_set_xtoken_composition = (void (*)(xbox::services::system::auth_config*, std::vector)) hybris_dlsym(handle, "_ZN4xbox8services6system11auth_config22set_xtoken_compositionESt6vectorINS1_19token_identity_typeESaIS4_EE"); xbox::services::system::auth_config::auth_config_xbox_live_endpoint = (mcpe::string const& (*)(xbox::services::system::auth_config*)) hybris_dlsym(handle, "_ZNK4xbox8services6system11auth_config18xbox_live_endpointEv"); xbox::services::java_interop::get_java_interop_singleton = (std::shared_ptr (*)()) hybris_dlsym(handle, "_ZN4xbox8services12java_interop26get_java_interop_singletonEv"); - Social::MultiplayerXBL::MultiplayerXBL_MultiplayerXBL = (void (*)(Social::MultiplayerXBL*)) hybris_dlsym(handle, "_ZN6Social14MultiplayerXBLC2Ev"); Log::info("Launcher", "Creating window"); eglutInitWindowSize(windowWidth, windowHeight); @@ -622,7 +600,7 @@ int main(int argc, char *argv[]) { platform->initialize(); Log::trace("Launcher", "Initializing OpenGL bindings"); - mce::Platform::OGL::initBindings(); + mce::Platform::OGL::InitBindings(); Log::trace("Launcher", "Initializing MinecraftGame (create instance)"); client = new MinecraftGame(argc, argv); diff --git a/src/minecraft/App.h b/src/minecraft/App.h index df735bc..d1f1d54 100644 --- a/src/minecraft/App.h +++ b/src/minecraft/App.h @@ -10,13 +10,9 @@ struct AppContext { class App { public: - static void (*App_init)(App*, AppContext&); - void** vtable; - void init(AppContext& ctx) { - App_init(this, ctx); - } + void init(AppContext& ctx); void quit() { ((void (*)(App*)) vtable[26])(this); diff --git a/src/minecraft/AppPlatform.h b/src/minecraft/AppPlatform.h index 2d2cd5b..e1a7852 100644 --- a/src/minecraft/AppPlatform.h +++ b/src/minecraft/AppPlatform.h @@ -4,26 +4,17 @@ class AppPlatform { public: static void** myVtable; - - static void (*AppPlatform_construct)(AppPlatform*); - static void (*AppPlatform_initialize)(AppPlatform*); - static void (*AppPlatform__fireAppFocusGained)(AppPlatform*); + static AppPlatform** _singleton; void** vtable; char filler[0xA0 - sizeof(void**)]; long long usedMemory, totalMemory, availableMemory; char filler2[0x1000]; - AppPlatform() { - AppPlatform_construct(this); - } + AppPlatform(); - static AppPlatform** _singleton; - void _fireAppFocusGained() { - AppPlatform__fireAppFocusGained(this); - } - void initialize() { - AppPlatform_initialize(this); - } + void _fireAppFocusGained(); + + void initialize(); }; \ No newline at end of file diff --git a/src/minecraft/AutomationClient.h b/src/minecraft/AutomationClient.h index 1bf6b63..49a3518 100644 --- a/src/minecraft/AutomationClient.h +++ b/src/minecraft/AutomationClient.h @@ -6,13 +6,9 @@ class AutomationClient { public: - static void (*AutomationClient_construct)(AutomationClient*, IMinecraftApp&); - char filler[0x300]; - AutomationClient(IMinecraftApp& a) { - AutomationClient_construct(this, a); - } + AutomationClient(IMinecraftApp& a); }; diff --git a/src/minecraft/CommandOutput.h b/src/minecraft/CommandOutput.h index b745b90..3d3aab6 100644 --- a/src/minecraft/CommandOutput.h +++ b/src/minecraft/CommandOutput.h @@ -17,10 +17,6 @@ class CommandOutput { public: - static std::vector const& (*CommandOutput_getMessages)(CommandOutput const*); - - std::vector const& getMessages() const { - return CommandOutput_getMessages(this); - } + std::vector const& getMessages() const; }; \ No newline at end of file diff --git a/src/minecraft/CommandOutputSender.h b/src/minecraft/CommandOutputSender.h index c09e07a..64db8f2 100644 --- a/src/minecraft/CommandOutputSender.h +++ b/src/minecraft/CommandOutputSender.h @@ -2,32 +2,24 @@ class CommandOrigin; class CommandOutput; +namespace Automation { class AutomationClient; } class CommandOutputSender { public: - static void (*CommandOutputSender_construct)(CommandOutputSender*, Automation::AutomationClient&); static void (*CommandOutputSender_destruct)(CommandOutputSender*); - static void (*CommandOutputSender_send)(CommandOutputSender*, CommandOrigin const&, CommandOutput const&); - static std::vector (*CommandOutputSender_translate)(std::vector const&); - static std::vector translate(std::vector const& v) { - return CommandOutputSender_translate(v); - } + static std::vector translate(std::vector const& v); - CommandOutputSender(Automation::AutomationClient& automationClient) { - CommandOutputSender_construct(this, automationClient); - } + CommandOutputSender(Automation::AutomationClient& automationClient); virtual ~CommandOutputSender() { CommandOutputSender_destruct(this); } - virtual void send(CommandOrigin const& origin, CommandOutput const& output) { - CommandOutputSender_send(this, origin, output); - } + virtual void send(CommandOrigin const& origin, CommandOutput const& output); - virtual void registerOutputCallback() { } + virtual void registerOutputCallback(); }; \ No newline at end of file diff --git a/src/minecraft/Common.h b/src/minecraft/Common.h index 412c47d..e055474 100644 --- a/src/minecraft/Common.h +++ b/src/minecraft/Common.h @@ -5,6 +5,6 @@ class Common { public: - static mcpe::string (*Common_getGameVersionStringNet)(); + static mcpe::string getGameVersionStringNet(); }; \ No newline at end of file diff --git a/src/minecraft/DedicatedServerCommandOrigin.h b/src/minecraft/DedicatedServerCommandOrigin.h index de06259..72993c6 100644 --- a/src/minecraft/DedicatedServerCommandOrigin.h +++ b/src/minecraft/DedicatedServerCommandOrigin.h @@ -11,12 +11,8 @@ class DedicatedServerCommandOrigin : public CommandOrigin { public: - static void (*DedicatedServerCommandOrigin_construct)(DedicatedServerCommandOrigin*, mcpe::string const&, Minecraft&); - char filler[0x1C]; - DedicatedServerCommandOrigin(mcpe::string const& s, Minecraft& m) { - DedicatedServerCommandOrigin_construct(this, s, m); - } + DedicatedServerCommandOrigin(mcpe::string const& s, Minecraft& m); }; \ No newline at end of file diff --git a/src/minecraft/FilePathManager.h b/src/minecraft/FilePathManager.h index 9b20883..9a5d767 100644 --- a/src/minecraft/FilePathManager.h +++ b/src/minecraft/FilePathManager.h @@ -8,11 +8,7 @@ class FilePathManager { char filler[0x20]; - static void (*FilePathManager_construct)(FilePathManager*, mcpe::string, bool); - - FilePathManager(mcpe::string str, bool b) { - FilePathManager_construct(this, std::move(str), b); - } + FilePathManager(mcpe::string, bool); }; \ No newline at end of file diff --git a/src/minecraft/I18n.h b/src/minecraft/I18n.h index 21c5a60..1b2bd72 100644 --- a/src/minecraft/I18n.h +++ b/src/minecraft/I18n.h @@ -9,13 +9,8 @@ class SkinRepository; class I18n { public: - - static mcpe::string (*I18n_get)(mcpe::string const&, std::vector const&); - static void (*I18n_chooseLanguage)(mcpe::string const&); - static void (*I18n_loadLanguages)(ResourcePackManager&, SkinRepository*, mcpe::string const&); - - static void loadLanguages(ResourcePackManager& m, SkinRepository* r, mcpe::string const& s) { - I18n_loadLanguages(m, r, s); - } + static mcpe::string get(mcpe::string const&, std::vector const&); + static void chooseLanguage(mcpe::string const&); + static void loadLanguages(ResourcePackManager&, SkinRepository*, mcpe::string const&); }; \ No newline at end of file diff --git a/src/minecraft/ImagePickingCallback.h b/src/minecraft/ImagePickingCallback.h index 4906cb0..0356f6b 100644 --- a/src/minecraft/ImagePickingCallback.h +++ b/src/minecraft/ImagePickingCallback.h @@ -5,8 +5,8 @@ class ImagePickingCallback { public: - virtual ~ImagePickingCallback(); - virtual void onImagePickingSuccess(const mcpe::string&); - virtual void onImagePickingCanceled(); + virtual ~ImagePickingCallback() = 0; + virtual void onImagePickingSuccess(const mcpe::string&) = 0; + virtual void onImagePickingCanceled() = 0; }; \ No newline at end of file diff --git a/src/minecraft/Keyboard.h b/src/minecraft/Keyboard.h index 8581bb0..bb9038f 100644 --- a/src/minecraft/Keyboard.h +++ b/src/minecraft/Keyboard.h @@ -6,8 +6,8 @@ class Keyboard { public: - static void (*Keyboard_feed)(unsigned char, int); - static void (*Keyboard_feedText)(const mcpe::string&, bool, unsigned char); + static void feed(unsigned char, int); + static void feedText(mcpe::string const&, bool, unsigned char); static int* states; diff --git a/src/minecraft/LevelSettings.h b/src/minecraft/LevelSettings.h index e8ac9f9..6ecfa04 100644 --- a/src/minecraft/LevelSettings.h +++ b/src/minecraft/LevelSettings.h @@ -6,9 +6,6 @@ class LevelSettings { public: - static void (*LevelSettings_construct)(LevelSettings*); - static void (*LevelSettings_construct2)(LevelSettings*, LevelSettings const&); - int seed; // 4 int gametype; // 8 int difficulty; // c @@ -22,12 +19,7 @@ class LevelSettings { bool mpGame, lanBroadcast, xblBroadcast, commandsEnabled, texturepacksRequired, overrideSavedSettings; // 2d, 2e, 2f, 30, 31, 32~34 char filler[0x300]; - LevelSettings() { - LevelSettings_construct(this); - } - LevelSettings(LevelSettings const& org) { - //memcpy((void*) this, (void const*) &org, sizeof(LevelSettings)); - LevelSettings_construct2(this, org); - } + LevelSettings(); + LevelSettings(LevelSettings const& org); }; \ No newline at end of file diff --git a/src/minecraft/Minecraft.h b/src/minecraft/Minecraft.h index d1c18d1..a5cbdfe 100644 --- a/src/minecraft/Minecraft.h +++ b/src/minecraft/Minecraft.h @@ -6,10 +6,6 @@ class Minecraft { public: - static MinecraftCommands* (*Minecraft_getCommands)(Minecraft*); - - MinecraftCommands* getCommands() { - return Minecraft_getCommands(this); - } + MinecraftCommands* getCommands(); }; \ No newline at end of file diff --git a/src/minecraft/MinecraftCommands.h b/src/minecraft/MinecraftCommands.h index 0ae1735..97dbfa0 100644 --- a/src/minecraft/MinecraftCommands.h +++ b/src/minecraft/MinecraftCommands.h @@ -20,15 +20,8 @@ class MinecraftCommands { public: - static void (*MinecraftCommands_setOutputSender)(MinecraftCommands*, std::unique_ptr); - static MCRESULT (*MinecraftCommands_requestCommandExecution)(MinecraftCommands*, std::unique_ptr, mcpe::string const&, int, bool); + void setOutputSender(std::unique_ptr sender) const; - void setOutputSender(std::unique_ptr sender) { - MinecraftCommands_setOutputSender(this, std::move(sender)); - } - - MCRESULT requestCommandExecution(std::unique_ptr o, mcpe::string const& s, int i, bool b) { - MinecraftCommands_requestCommandExecution(this, std::move(o), s, i, b); - } + MCRESULT requestCommandExecution(std::unique_ptr o, mcpe::string const& s, int i, bool b) const; }; \ No newline at end of file diff --git a/src/minecraft/MinecraftEventing.h b/src/minecraft/MinecraftEventing.h index be94aa1..05aeed1 100644 --- a/src/minecraft/MinecraftEventing.h +++ b/src/minecraft/MinecraftEventing.h @@ -1,23 +1,17 @@ #pragma once +#include "string.h" + class IPackTelemetry {}; class MinecraftEventing : public IPackTelemetry { public: - static void (*MinecraftEventing_construct)(MinecraftEventing*, mcpe::string const&); - - static void (*MinecraftEventing_init)(MinecraftEventing*); - char filler[0x100]; - MinecraftEventing(std::string const& str) { - MinecraftEventing_construct(this, str); - } + MinecraftEventing(mcpe::string const& str); - void init() { - MinecraftEventing_init(this); - } + void init(); }; \ No newline at end of file diff --git a/src/minecraft/MinecraftGame.h b/src/minecraft/MinecraftGame.h index 5742e9b..dacec59 100644 --- a/src/minecraft/MinecraftGame.h +++ b/src/minecraft/MinecraftGame.h @@ -8,37 +8,22 @@ class Options; class MinecraftGame : public App { public: - static void (*MinecraftGame_construct)(MinecraftGame*, int, char**); static void (*MinecraftGame_destruct)(MinecraftGame*); - static void (*MinecraftGame_update)(MinecraftGame*); - static void (*MinecraftGame_setRenderingSize)(MinecraftGame*, int, int); - static void (*MinecraftGame_setUISizeAndScale)(MinecraftGame*, int, int, float); - static std::shared_ptr (*MinecraftGame_getPrimaryUserOptions)(MinecraftGame*); - char filler [0x4000-4]; + char filler [0x4000]; - MinecraftGame(int carg, char** args) { - MinecraftGame_construct(this, carg, args); - } + MinecraftGame(int carg, char** args); ~MinecraftGame() { MinecraftGame_destruct(this); } - void update() { - MinecraftGame_update(this); - } + void update(); - void setRenderingSize(int w, int h) { - MinecraftGame_setRenderingSize(this, w, h); - } + void setRenderingSize(int, int); - void setUISizeAndScale(int w, int h, float px) { - MinecraftGame_setUISizeAndScale(this, w, h, px); - } + void setUISizeAndScale(int, int, float); - std::shared_ptr getPrimaryUserOptions() { - return MinecraftGame_getPrimaryUserOptions(this); - } + std::shared_ptr getPrimaryUserOptions(); }; diff --git a/src/minecraft/Mouse.h b/src/minecraft/Mouse.h index 61b47e4..38b9dae 100644 --- a/src/minecraft/Mouse.h +++ b/src/minecraft/Mouse.h @@ -3,6 +3,6 @@ class Mouse { public: - static void (*feed)(char button, char type, short x, short y, short dx, short dy); + static void feed(char button, char type, short x, short y, short dx, short dy); }; \ No newline at end of file diff --git a/src/minecraft/MultiplayerService.h b/src/minecraft/MultiplayerService.h index 6c2e9af..9230c48 100644 --- a/src/minecraft/MultiplayerService.h +++ b/src/minecraft/MultiplayerService.h @@ -10,13 +10,9 @@ struct MultiplayerService { struct MultiplayerXBL : public MultiplayerService, public std::enable_shared_from_this { - static void (*MultiplayerXBL_MultiplayerXBL)(MultiplayerXBL*); - char filler[0x200]; - MultiplayerXBL() { - MultiplayerXBL_MultiplayerXBL(this); - } + MultiplayerXBL(); }; diff --git a/src/minecraft/Options.h b/src/minecraft/Options.h index 380f7af..8661107 100644 --- a/src/minecraft/Options.h +++ b/src/minecraft/Options.h @@ -3,14 +3,7 @@ class Options { public: - static bool (*Options_getFullscreen)(Options*); - static void (*Options_setFullscreen)(Options*, bool); - - bool getFullscreen() { - return Options_getFullscreen(this); - } - void setFullscreen(bool b) { - Options_setFullscreen(this, b); - } + bool getFullscreen() const; + void setFullscreen(bool b); }; \ No newline at end of file diff --git a/src/minecraft/ResourcePack.h b/src/minecraft/ResourcePack.h index 388c235..6c78c7c 100644 --- a/src/minecraft/ResourcePack.h +++ b/src/minecraft/ResourcePack.h @@ -17,13 +17,10 @@ class IContentAccessibilityProvider { class SkinPackKeyProvider : public IContentAccessibilityProvider { public: - int filler; - static void (*SkinPackKeyProvider_construct)(SkinPackKeyProvider*); + int filler; - SkinPackKeyProvider() { - SkinPackKeyProvider_construct(this); - } + SkinPackKeyProvider(); }; @@ -34,11 +31,7 @@ class PackManifestFactory { char filler[4]; - static void (*PackManifestFactory_construct)(PackManifestFactory*, IPackTelemetry&); - - PackManifestFactory(IPackTelemetry& ev) { - PackManifestFactory_construct(this, ev); - } + PackManifestFactory(IPackTelemetry&); }; @@ -48,11 +41,7 @@ class PackSourceFactory { char filler[0x100]; - static void (*PackSourceFactory_construct)(PackSourceFactory*, Options *); - - PackSourceFactory(Options* o) { - PackSourceFactory_construct(this, o); - } + PackSourceFactory(Options*); }; @@ -64,11 +53,7 @@ class ResourcePackRepository { ResourcePack* vanillaPack; char filler2[0x100]; - static void (*ResourcePackRepository_construct)(ResourcePackRepository*, MinecraftEventing&, PackManifestFactory&, IContentAccessibilityProvider&, FilePathManager*, PackSourceFactory&); - - ResourcePackRepository(MinecraftEventing& ev, PackManifestFactory& fact, IContentAccessibilityProvider& ap, FilePathManager* pm, PackSourceFactory& ps) { - ResourcePackRepository_construct(this, ev, fact, ap, pm, ps); - } + ResourcePackRepository(MinecraftEventing&, PackManifestFactory&, IContentAccessibilityProvider&, FilePathManager*, PackSourceFactory&); }; @@ -76,13 +61,9 @@ struct ContentTierManager { public: - static void (*ContentTierManager_construct)(ContentTierManager*); - int filler; - ContentTierManager() { - ContentTierManager_construct(this); - } + ContentTierManager(); }; @@ -93,19 +74,13 @@ class ResourcePackManager { char filler[0x100]; static void (*ResourcePackManager_construct)(ResourcePackManager*, std::function const&, ContentTierManager const&); - static void (*ResourcePackManager_setStack)(ResourcePackManager*, std::unique_ptr, ResourcePackStackType, bool); - static void (*ResourcePackManager_onLanguageChanged)(ResourcePackManager*); ResourcePackManager(std::function const& f, ContentTierManager const& m) { ResourcePackManager_construct(this, f, m); } - void setStack(std::unique_ptr s, ResourcePackStackType t, bool b) { - ResourcePackManager_setStack(this, std::move(s), t, b); - } + void setStack(std::unique_ptr, ResourcePackStackType, bool); - void onLanguageChanged() { - ResourcePackManager_onLanguageChanged(this); - } + void onLanguageChanged(); }; \ No newline at end of file diff --git a/src/minecraft/ResourcePackStack.h b/src/minecraft/ResourcePackStack.h index f38bb80..ba4269d 100644 --- a/src/minecraft/ResourcePackStack.h +++ b/src/minecraft/ResourcePackStack.h @@ -7,13 +7,9 @@ class ResourcePackRepository; struct PackInstance { - static void (*PackInstance_construct)(PackInstance*, ResourcePack*, int, bool); - char filler[0x71]; - PackInstance(ResourcePack* r, int i, bool b) { - PackInstance_construct(this, r, i, b); - } + PackInstance(ResourcePack*, int, bool); }; diff --git a/src/minecraft/Scheduler.h b/src/minecraft/Scheduler.h index ba567d0..fe1711d 100644 --- a/src/minecraft/Scheduler.h +++ b/src/minecraft/Scheduler.h @@ -6,9 +6,10 @@ struct Scheduler { public: - static Scheduler* (*singleton)(); static void (*Scheduler_processCoroutines)(Scheduler*, std::chrono::duration); + static Scheduler* singleton(); + void processCoroutines(std::chrono::duration d) { Scheduler_processCoroutines(this, d); } diff --git a/src/minecraft/ServerInstance.h b/src/minecraft/ServerInstance.h index 82530fa..69ba276 100644 --- a/src/minecraft/ServerInstance.h +++ b/src/minecraft/ServerInstance.h @@ -17,17 +17,16 @@ class MinecraftEventing; class ResourcePackRepository; class ResourcePackManager; class ContentTierManager; +class FilePathManager; +class IContentAccessibilityProvider; class NetworkHandler { public: - static void (*NetworkHandler_construct)(NetworkHandler*); char filler[0x200]; - NetworkHandler() { - NetworkHandler_construct(this); - } + NetworkHandler(); }; @@ -40,15 +39,9 @@ class ServerInstance { char filler2[0x200]; static void (*ServerInstance_construct)(ServerInstance*, IMinecraftApp&, Whitelist const&, OpsList const&, FilePathManager*, std::chrono::duration, mcpe::string, mcpe::string, mcpe::string, IContentAccessibilityProvider const&, mcpe::string, LevelSettings, minecraft::api::Api&, int, bool, int, int, int, bool, std::vector const&, mcpe::string, mce::UUID const&, MinecraftEventing&, NetworkHandler&, ResourcePackRepository&, ContentTierManager const&, ResourcePackManager&, ResourcePackManager*, std::function); - static void (*ServerInstance_update)(ServerInstance*); - static void (*ServerInstance_mainThreadNetworkUpdate_HACK)(ServerInstance*); - void update() { - ServerInstance_update(this); - } + void update(); - void mainThreadNetworkUpdate_HACK() { - ServerInstance_mainThreadNetworkUpdate_HACK(this); - } + void mainThreadNetworkUpdate_HACK(); }; \ No newline at end of file diff --git a/src/minecraft/UUID.h b/src/minecraft/UUID.h index a1b6516..eea1049 100644 --- a/src/minecraft/UUID.h +++ b/src/minecraft/UUID.h @@ -8,7 +8,7 @@ class UUID { static UUID* EMPTY; - static mce::UUID (*fromString)(mcpe::string const&); + static mce::UUID fromString(mcpe::string const&); char filler[0x14]; diff --git a/src/minecraft/UserManager.h b/src/minecraft/UserManager.h index 8362584..6b426c5 100644 --- a/src/minecraft/UserManager.h +++ b/src/minecraft/UserManager.h @@ -7,7 +7,7 @@ class UserManager { public: - static std::unique_ptr (*CreateUserManager)(); + static std::unique_ptr CreateUserManager(); }; diff --git a/src/minecraft/Xbox.h b/src/minecraft/Xbox.h index 54ef2b6..0130df3 100644 --- a/src/minecraft/Xbox.h +++ b/src/minecraft/Xbox.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "string.h" namespace xbox { @@ -113,7 +114,7 @@ struct task_completion_event_xbox_live_result_void { }; struct task_impl { - virtual ~task_impl(); + virtual ~task_impl() = 0; }; struct task { std::shared_ptr impl; diff --git a/src/minecraft/gl.h b/src/minecraft/gl.h index d38578e..6909474 100644 --- a/src/minecraft/gl.h +++ b/src/minecraft/gl.h @@ -3,10 +3,10 @@ #include "string.h" struct gl { - static mcpe::string (*getOpenGLVendor)(); - static mcpe::string (*getOpenGLRenderer)(); - static mcpe::string (*getOpenGLVersion)(); - static mcpe::string (*getOpenGLExtensions)(); + static mcpe::string getOpenGLVendor(); + static mcpe::string getOpenGLRenderer(); + static mcpe::string getOpenGLVersion(); + static mcpe::string getOpenGLExtensions(); }; namespace mce { @@ -15,8 +15,7 @@ namespace Platform { struct OGL { - static void (*OGL_initBindings)(); - static void initBindings() { OGL_initBindings(); } + static void InitBindings(); }; diff --git a/src/minecraft/symbols.cpp b/src/minecraft/symbols.cpp new file mode 100644 index 0000000..04abeb9 --- /dev/null +++ b/src/minecraft/symbols.cpp @@ -0,0 +1,336 @@ +// This file was automatically generated using tools/process_headers.py +// Generated on Wed Jan 10 2018 14:55:47 UTC + +#include + +#include "UserManager.h" +static std::unique_ptr (*_Social_UserManager_CreateUserManager)(); +std::unique_ptr Social::UserManager::CreateUserManager() { + return _Social_UserManager_CreateUserManager(); +} + +#include "Xbox.h" + +#include "ServerInstance.h" +static void (NetworkHandler::*_NetworkHandler_NetworkHandler)(); +NetworkHandler::NetworkHandler() { + (this->*_NetworkHandler_NetworkHandler)(); +} +static void (ServerInstance::*_ServerInstance_update)(); +void ServerInstance::update() { + (this->*_ServerInstance_update)(); +} +static void (ServerInstance::*_ServerInstance_mainThreadNetworkUpdate_HACK)(); +void ServerInstance::mainThreadNetworkUpdate_HACK() { + (this->*_ServerInstance_mainThreadNetworkUpdate_HACK)(); +} + +#include "OpsList.h" + +#include "Mouse.h" +static void (*_Mouse_feed)(char, char, short, short, short, short); +void Mouse::feed(char p1, char p2, short p3, short p4, short p5, short p6) { + _Mouse_feed(p1, p2, p3, p4, p5, p6); +} + +#include "MinecraftCommands.h" +static void (MinecraftCommands::*_MinecraftCommands_setOutputSender)(std::unique_ptr) const; +void MinecraftCommands::setOutputSender(std::unique_ptr p1) const { + (this->*_MinecraftCommands_setOutputSender)(std::move(p1)); +} +static MCRESULT (MinecraftCommands::*_MinecraftCommands_requestCommandExecution)(std::unique_ptr, mcpe::string const &, int, bool) const; +MCRESULT MinecraftCommands::requestCommandExecution(std::unique_ptr p1, mcpe::string const & p2, int p3, bool p4) const { + return (this->*_MinecraftCommands_requestCommandExecution)(std::move(p1), p2, p3, p4); +} + +#include "I18n.h" +static mcpe::string (*_I18n_get)(mcpe::string const &, std::vector const &); +mcpe::string I18n::get(mcpe::string const & p1, std::vector const & p2) { + return _I18n_get(p1, p2); +} +static void (*_I18n_chooseLanguage)(mcpe::string const &); +void I18n::chooseLanguage(mcpe::string const & p1) { + _I18n_chooseLanguage(p1); +} +static void (*_I18n_loadLanguages)(ResourcePackManager &, SkinRepository *, mcpe::string const &); +void I18n::loadLanguages(ResourcePackManager & p1, SkinRepository * p2, mcpe::string const & p3) { + _I18n_loadLanguages(p1, p2, p3); +} + +#include "gl.h" +static mcpe::string (*_gl_getOpenGLVendor)(); +mcpe::string gl::getOpenGLVendor() { + return _gl_getOpenGLVendor(); +} +static mcpe::string (*_gl_getOpenGLRenderer)(); +mcpe::string gl::getOpenGLRenderer() { + return _gl_getOpenGLRenderer(); +} +static mcpe::string (*_gl_getOpenGLVersion)(); +mcpe::string gl::getOpenGLVersion() { + return _gl_getOpenGLVersion(); +} +static mcpe::string (*_gl_getOpenGLExtensions)(); +mcpe::string gl::getOpenGLExtensions() { + return _gl_getOpenGLExtensions(); +} +static void (*_mce_Platform_OGL_InitBindings)(); +void mce::Platform::OGL::InitBindings() { + _mce_Platform_OGL_InitBindings(); +} + +#include "ResourcePackStack.h" +static void (PackInstance::*_PackInstance_PackInstance)(ResourcePack *, int, bool); +PackInstance::PackInstance(ResourcePack * p1, int p2, bool p3) { + (this->*_PackInstance_PackInstance)(p1, p2, p3); +} + +#include "MinecraftEventing.h" +static void (MinecraftEventing::*_MinecraftEventing_MinecraftEventing)(mcpe::string const &); +MinecraftEventing::MinecraftEventing(mcpe::string const & p1) { + (this->*_MinecraftEventing_MinecraftEventing)(p1); +} +static void (MinecraftEventing::*_MinecraftEventing_init)(); +void MinecraftEventing::init() { + (this->*_MinecraftEventing_init)(); +} + +#include "Api.h" + +#include "MinecraftGame.h" +static void (MinecraftGame::*_MinecraftGame_MinecraftGame)(int, char * *); +MinecraftGame::MinecraftGame(int p1, char * * p2) { + (this->*_MinecraftGame_MinecraftGame)(p1, p2); +} +static void (MinecraftGame::*_MinecraftGame_update)(); +void MinecraftGame::update() { + (this->*_MinecraftGame_update)(); +} +static void (MinecraftGame::*_MinecraftGame_setRenderingSize)(int, int); +void MinecraftGame::setRenderingSize(int p1, int p2) { + (this->*_MinecraftGame_setRenderingSize)(p1, p2); +} +static void (MinecraftGame::*_MinecraftGame_setUISizeAndScale)(int, int, float); +void MinecraftGame::setUISizeAndScale(int p1, int p2, float p3) { + (this->*_MinecraftGame_setUISizeAndScale)(p1, p2, p3); +} +static std::shared_ptr (MinecraftGame::*_MinecraftGame_getPrimaryUserOptions)(); +std::shared_ptr MinecraftGame::getPrimaryUserOptions() { + return (this->*_MinecraftGame_getPrimaryUserOptions)(); +} + +#include "Keyboard.h" +static void (*_Keyboard_feed)(unsigned char, int); +void Keyboard::feed(unsigned char p1, int p2) { + _Keyboard_feed(p1, p2); +} +static void (*_Keyboard_feedText)(mcpe::string const &, bool, unsigned char); +void Keyboard::feedText(mcpe::string const & p1, bool p2, unsigned char p3) { + _Keyboard_feedText(p1, p2, p3); +} + +#include "CommandOutput.h" +static std::vector const & (CommandOutput::*_CommandOutput_getMessages)() const; +std::vector const & CommandOutput::getMessages() const { + return (this->*_CommandOutput_getMessages)(); +} + +#include "Scheduler.h" +static Scheduler * (*_Scheduler_singleton)(); +Scheduler * Scheduler::singleton() { + return _Scheduler_singleton(); +} + +#include "FilePathManager.h" +static void (FilePathManager::*_FilePathManager_FilePathManager)(mcpe::string, bool); +FilePathManager::FilePathManager(mcpe::string p1, bool p2) { + (this->*_FilePathManager_FilePathManager)(p1, p2); +} + +#include "App.h" +static void (App::*_App_init)(AppContext &); +void App::init(AppContext & p1) { + (this->*_App_init)(p1); +} + +#include "ImagePickingCallback.h" + +#include "IMinecraftApp.h" + +#include "Whitelist.h" + +#include "AppPlatform.h" +static void (AppPlatform::*_AppPlatform_AppPlatform)(); +AppPlatform::AppPlatform() { + (this->*_AppPlatform_AppPlatform)(); +} +static void (AppPlatform::*_AppPlatform__fireAppFocusGained)(); +void AppPlatform::_fireAppFocusGained() { + (this->*_AppPlatform__fireAppFocusGained)(); +} +static void (AppPlatform::*_AppPlatform_initialize)(); +void AppPlatform::initialize() { + (this->*_AppPlatform_initialize)(); +} + +#include "CommandOutputSender.h" +static std::vector (*_CommandOutputSender_translate)(std::vector const &); +std::vector CommandOutputSender::translate(std::vector const & p1) { + return _CommandOutputSender_translate(p1); +} +static void (CommandOutputSender::*_CommandOutputSender_CommandOutputSender)(Automation::AutomationClient &); +CommandOutputSender::CommandOutputSender(Automation::AutomationClient & p1) { + (this->*_CommandOutputSender_CommandOutputSender)(p1); +} +static void (CommandOutputSender::*_CommandOutputSender_send)(CommandOrigin const &, CommandOutput const &); +void CommandOutputSender::send(CommandOrigin const & p1, CommandOutput const & p2) { + (this->*_CommandOutputSender_send)(p1, p2); +} +static void (CommandOutputSender::*_CommandOutputSender_registerOutputCallback)(); +void CommandOutputSender::registerOutputCallback() { + (this->*_CommandOutputSender_registerOutputCallback)(); +} + +#include "FilePickerSettings.h" + +#include "AutomationClient.h" +static void (Automation::AutomationClient::*_Automation_AutomationClient_AutomationClient)(IMinecraftApp &); +Automation::AutomationClient::AutomationClient(IMinecraftApp & p1) { + (this->*_Automation_AutomationClient_AutomationClient)(p1); +} + +#include "ResourcePack.h" +static void (SkinPackKeyProvider::*_SkinPackKeyProvider_SkinPackKeyProvider)(); +SkinPackKeyProvider::SkinPackKeyProvider() { + (this->*_SkinPackKeyProvider_SkinPackKeyProvider)(); +} +static void (PackManifestFactory::*_PackManifestFactory_PackManifestFactory)(IPackTelemetry &); +PackManifestFactory::PackManifestFactory(IPackTelemetry & p1) { + (this->*_PackManifestFactory_PackManifestFactory)(p1); +} +static void (PackSourceFactory::*_PackSourceFactory_PackSourceFactory)(Options *); +PackSourceFactory::PackSourceFactory(Options * p1) { + (this->*_PackSourceFactory_PackSourceFactory)(p1); +} +static void (ResourcePackRepository::*_ResourcePackRepository_ResourcePackRepository)(MinecraftEventing &, PackManifestFactory &, IContentAccessibilityProvider &, FilePathManager *, PackSourceFactory &); +ResourcePackRepository::ResourcePackRepository(MinecraftEventing & p1, PackManifestFactory & p2, IContentAccessibilityProvider & p3, FilePathManager * p4, PackSourceFactory & p5) { + (this->*_ResourcePackRepository_ResourcePackRepository)(p1, p2, p3, p4, p5); +} +static void (ContentTierManager::*_ContentTierManager_ContentTierManager)(); +ContentTierManager::ContentTierManager() { + (this->*_ContentTierManager_ContentTierManager)(); +} +static void (ResourcePackManager::*_ResourcePackManager_setStack)(std::unique_ptr, ResourcePackStackType, bool); +void ResourcePackManager::setStack(std::unique_ptr p1, ResourcePackStackType p2, bool p3) { + (this->*_ResourcePackManager_setStack)(std::move(p1), p2, p3); +} +static void (ResourcePackManager::*_ResourcePackManager_onLanguageChanged)(); +void ResourcePackManager::onLanguageChanged() { + (this->*_ResourcePackManager_onLanguageChanged)(); +} + +#include "DedicatedServerCommandOrigin.h" +static void (DedicatedServerCommandOrigin::*_DedicatedServerCommandOrigin_DedicatedServerCommandOrigin)(mcpe::string const &, Minecraft &); +DedicatedServerCommandOrigin::DedicatedServerCommandOrigin(mcpe::string const & p1, Minecraft & p2) { + (this->*_DedicatedServerCommandOrigin_DedicatedServerCommandOrigin)(p1, p2); +} + +#include "MultiplayerService.h" +static void (Social::MultiplayerXBL::*_Social_MultiplayerXBL_MultiplayerXBL)(); +Social::MultiplayerXBL::MultiplayerXBL() { + (this->*_Social_MultiplayerXBL_MultiplayerXBL)(); +} + +#include "UUID.h" +static mce::UUID (*_mce_UUID_fromString)(mcpe::string const &); +mce::UUID mce::UUID::fromString(mcpe::string const & p1) { + return _mce_UUID_fromString(p1); +} + +#include "Minecraft.h" +static MinecraftCommands * (Minecraft::*_Minecraft_getCommands)(); +MinecraftCommands * Minecraft::getCommands() { + return (this->*_Minecraft_getCommands)(); +} + +#include "LevelSettings.h" +static void (LevelSettings::*_LevelSettings_LevelSettings)(); +LevelSettings::LevelSettings() { + (this->*_LevelSettings_LevelSettings)(); +} +static void (LevelSettings::*_LevelSettings_LevelSettings2)(LevelSettings const &); +LevelSettings::LevelSettings(LevelSettings const & p1) { + (this->*_LevelSettings_LevelSettings2)(p1); +} + +#include "Options.h" +static bool (Options::*_Options_getFullscreen)() const; +bool Options::getFullscreen() const { + return (this->*_Options_getFullscreen)(); +} +static void (Options::*_Options_setFullscreen)(bool); +void Options::setFullscreen(bool p1) { + (this->*_Options_setFullscreen)(p1); +} + +#include "Common.h" +static mcpe::string (*_Common_getGameVersionStringNet)(); +mcpe::string Common::getGameVersionStringNet() { + return _Common_getGameVersionStringNet(); +} + +void minecraft_symbols_init(void* handle) { + ((void*&) _Social_UserManager_CreateUserManager) = hybris_dlsym(handle, "_ZN6Social11UserManager17CreateUserManagerEv"); + ((void*&) _NetworkHandler_NetworkHandler) = hybris_dlsym(handle, "_ZN14NetworkHandlerC2Ev"); + ((void*&) _ServerInstance_update) = hybris_dlsym(handle, "_ZN14ServerInstance6updateEv"); + ((void*&) _ServerInstance_mainThreadNetworkUpdate_HACK) = hybris_dlsym(handle, "_ZN14ServerInstance28mainThreadNetworkUpdate_HACKEv"); + ((void*&) _Mouse_feed) = hybris_dlsym(handle, "_ZN5Mouse4feedEccssss"); + ((void*&) _MinecraftCommands_setOutputSender) = hybris_dlsym(handle, "_ZNK17MinecraftCommands15setOutputSenderESt10unique_ptrI19CommandOutputSenderSt14default_deleteIS1_EE"); + ((void*&) _MinecraftCommands_requestCommandExecution) = hybris_dlsym(handle, "_ZNK17MinecraftCommands23requestCommandExecutionESt10unique_ptrI13CommandOriginSt14default_deleteIS1_EERKSsib"); + ((void*&) _I18n_get) = hybris_dlsym(handle, "_ZN4I18n3getERKSsRKSt6vectorISsE"); + ((void*&) _I18n_chooseLanguage) = hybris_dlsym(handle, "_ZN4I18n14chooseLanguageERKSs"); + ((void*&) _I18n_loadLanguages) = hybris_dlsym(handle, "_ZN4I18n13loadLanguagesER19ResourcePackManagerP14SkinRepositoryRKSs"); + ((void*&) _gl_getOpenGLVendor) = hybris_dlsym(handle, "_ZN2gl15getOpenGLVendorEv"); + ((void*&) _gl_getOpenGLRenderer) = hybris_dlsym(handle, "_ZN2gl17getOpenGLRendererEv"); + ((void*&) _gl_getOpenGLVersion) = hybris_dlsym(handle, "_ZN2gl16getOpenGLVersionEv"); + ((void*&) _gl_getOpenGLExtensions) = hybris_dlsym(handle, "_ZN2gl19getOpenGLExtensionsEv"); + ((void*&) _mce_Platform_OGL_InitBindings) = hybris_dlsym(handle, "_ZN3mce8Platform3OGL12InitBindingsEv"); + ((void*&) _PackInstance_PackInstance) = hybris_dlsym(handle, "_ZN12PackInstanceC2EP12ResourcePackib"); + ((void*&) _MinecraftEventing_MinecraftEventing) = hybris_dlsym(handle, "_ZN17MinecraftEventingC2ERKSs"); + ((void*&) _MinecraftEventing_init) = hybris_dlsym(handle, "_ZN17MinecraftEventing4initEv"); + ((void*&) _MinecraftGame_MinecraftGame) = hybris_dlsym(handle, "_ZN13MinecraftGameC2EiPPc"); + ((void*&) _MinecraftGame_update) = hybris_dlsym(handle, "_ZN13MinecraftGame6updateEv"); + ((void*&) _MinecraftGame_setRenderingSize) = hybris_dlsym(handle, "_ZN13MinecraftGame16setRenderingSizeEii"); + ((void*&) _MinecraftGame_setUISizeAndScale) = hybris_dlsym(handle, "_ZN13MinecraftGame17setUISizeAndScaleEiif"); + ((void*&) _MinecraftGame_getPrimaryUserOptions) = hybris_dlsym(handle, "_ZN13MinecraftGame21getPrimaryUserOptionsEv"); + ((void*&) _Keyboard_feed) = hybris_dlsym(handle, "_ZN8Keyboard4feedEhi"); + ((void*&) _Keyboard_feedText) = hybris_dlsym(handle, "_ZN8Keyboard8feedTextERKSsbh"); + ((void*&) _CommandOutput_getMessages) = hybris_dlsym(handle, "_ZNK13CommandOutput11getMessagesEv"); + ((void*&) _Scheduler_singleton) = hybris_dlsym(handle, "_ZN9Scheduler9singletonEv"); + ((void*&) _FilePathManager_FilePathManager) = hybris_dlsym(handle, "_ZN15FilePathManagerC2ESsb"); + ((void*&) _App_init) = hybris_dlsym(handle, "_ZN3App4initER10AppContext"); + ((void*&) _AppPlatform_AppPlatform) = hybris_dlsym(handle, "_ZN11AppPlatformC2Ev"); + ((void*&) _AppPlatform__fireAppFocusGained) = hybris_dlsym(handle, "_ZN11AppPlatform19_fireAppFocusGainedEv"); + ((void*&) _AppPlatform_initialize) = hybris_dlsym(handle, "_ZN11AppPlatform10initializeEv"); + ((void*&) _CommandOutputSender_translate) = hybris_dlsym(handle, "_ZN19CommandOutputSender9translateERKSt6vectorISsE"); + ((void*&) _CommandOutputSender_CommandOutputSender) = hybris_dlsym(handle, "_ZN19CommandOutputSenderC2ER10Automation16AutomationClient"); + ((void*&) _CommandOutputSender_send) = hybris_dlsym(handle, "_ZN19CommandOutputSender4sendERK13CommandOriginRK13CommandOutput"); + ((void*&) _CommandOutputSender_registerOutputCallback) = hybris_dlsym(handle, "_ZN19CommandOutputSender22registerOutputCallbackEv"); + ((void*&) _Automation_AutomationClient_AutomationClient) = hybris_dlsym(handle, "_ZN10Automation16AutomationClientC2ER13IMinecraftApp"); + ((void*&) _SkinPackKeyProvider_SkinPackKeyProvider) = hybris_dlsym(handle, "_ZN19SkinPackKeyProviderC2Ev"); + ((void*&) _PackManifestFactory_PackManifestFactory) = hybris_dlsym(handle, "_ZN19PackManifestFactoryC2ER14IPackTelemetry"); + ((void*&) _PackSourceFactory_PackSourceFactory) = hybris_dlsym(handle, "_ZN17PackSourceFactoryC2EP7Options"); + ((void*&) _ResourcePackRepository_ResourcePackRepository) = hybris_dlsym(handle, "_ZN22ResourcePackRepositoryC2ER17MinecraftEventingR19PackManifestFactoryR29IContentAccessibilityProviderP15FilePathManagerR17PackSourceFactory"); + ((void*&) _ContentTierManager_ContentTierManager) = hybris_dlsym(handle, "_ZN18ContentTierManagerC2Ev"); + ((void*&) _ResourcePackManager_setStack) = hybris_dlsym(handle, "_ZN19ResourcePackManager8setStackESt10unique_ptrI17ResourcePackStackSt14default_deleteIS1_EE21ResourcePackStackTypeb"); + ((void*&) _ResourcePackManager_onLanguageChanged) = hybris_dlsym(handle, "_ZN19ResourcePackManager17onLanguageChangedEv"); + ((void*&) _DedicatedServerCommandOrigin_DedicatedServerCommandOrigin) = hybris_dlsym(handle, "_ZN28DedicatedServerCommandOriginC2ERKSsR9Minecraft"); + ((void*&) _Social_MultiplayerXBL_MultiplayerXBL) = hybris_dlsym(handle, "_ZN6Social14MultiplayerXBLC2Ev"); + ((void*&) _mce_UUID_fromString) = hybris_dlsym(handle, "_ZN3mce4UUID10fromStringERKSs"); + ((void*&) _Minecraft_getCommands) = hybris_dlsym(handle, "_ZN9Minecraft11getCommandsEv"); + ((void*&) _LevelSettings_LevelSettings) = hybris_dlsym(handle, "_ZN13LevelSettingsC2Ev"); + ((void*&) _LevelSettings_LevelSettings2) = hybris_dlsym(handle, "_ZN13LevelSettingsC2ERKS_"); + ((void*&) _Options_getFullscreen) = hybris_dlsym(handle, "_ZNK7Options13getFullscreenEv"); + ((void*&) _Options_setFullscreen) = hybris_dlsym(handle, "_ZN7Options13setFullscreenEb"); + ((void*&) _Common_getGameVersionStringNet) = hybris_dlsym(handle, "_ZN6Common23getGameVersionStringNetEv"); +} diff --git a/src/minecraft/symbols.h b/src/minecraft/symbols.h new file mode 100644 index 0000000..740533a --- /dev/null +++ b/src/minecraft/symbols.h @@ -0,0 +1,3 @@ +#pragma once + +void minecraft_symbols_init(void* handle); \ No newline at end of file diff --git a/src/minecraft/types.cpp b/src/minecraft/types.cpp index 531dc46..3b1c028 100644 --- a/src/minecraft/types.cpp +++ b/src/minecraft/types.cpp @@ -5,44 +5,13 @@ AppPlatform** AppPlatform::_singleton = nullptr; void** AppPlatform::myVtable = nullptr; -void (*AppPlatform::AppPlatform_construct)(AppPlatform*); -void (*AppPlatform::AppPlatform__fireAppFocusGained)(AppPlatform*); -void (*AppPlatform::AppPlatform_initialize)(AppPlatform*); - -#include "App.h" - -void (*App::App_init)(App*, AppContext&); #include "MinecraftGame.h" -void (*MinecraftGame::MinecraftGame_construct)(MinecraftGame*, int, char**); void (*MinecraftGame::MinecraftGame_destruct)(MinecraftGame*); -void (*MinecraftGame::MinecraftGame_update)(MinecraftGame*); -void (*MinecraftGame::MinecraftGame_setRenderingSize)(MinecraftGame*, int, int); -void (*MinecraftGame::MinecraftGame_setUISizeAndScale)(MinecraftGame*, int, int, float); -std::shared_ptr (*MinecraftGame::MinecraftGame_getPrimaryUserOptions)(MinecraftGame*); - -#include "Options.h" - -bool (*Options::Options_getFullscreen)(Options*); -void (*Options::Options_setFullscreen)(Options*, bool); - -#include "gl.h" - -mcpe::string (*gl::getOpenGLVendor)(); -mcpe::string (*gl::getOpenGLRenderer)(); -mcpe::string (*gl::getOpenGLVersion)(); -mcpe::string (*gl::getOpenGLExtensions)(); -void (*mce::Platform::OGL::OGL_initBindings)(); - -#include "Mouse.h" - -void (*Mouse::feed)(char, char, short, short, short, short); #include "Keyboard.h" -void (*Keyboard::Keyboard_feed)(unsigned char, int); -void (*Keyboard::Keyboard_feedText)(const mcpe::string&, bool, unsigned char); int* Keyboard::states; #include "Xbox.h" @@ -74,96 +43,27 @@ xbox::services::xbox_live_result (*task::task_xbox_live_result_void_get)(t xbox::services::xbox_live_result (*task::task_xbox_live_result_token_and_signature_get)(task*); } -#include "MultiplayerService.h" - -void (*Social::MultiplayerXBL::MultiplayerXBL_MultiplayerXBL)(Social::MultiplayerXBL*); - -#include "Common.h" - -mcpe::string (*Common::Common_getGameVersionStringNet)(); - -#include "LevelSettings.h" - -void (*LevelSettings::LevelSettings_construct)(LevelSettings*); -void (*LevelSettings::LevelSettings_construct2)(LevelSettings*, LevelSettings const&); - -#include "MinecraftEventing.h" - -void (*MinecraftEventing::MinecraftEventing_construct)(MinecraftEventing*, mcpe::string const&); -void (*MinecraftEventing::MinecraftEventing_init)(MinecraftEventing*); - #include "ResourcePack.h" -void (*SkinPackKeyProvider::SkinPackKeyProvider_construct)(SkinPackKeyProvider*); -void (*PackManifestFactory::PackManifestFactory_construct)(PackManifestFactory*, IPackTelemetry&); -void (*PackSourceFactory::PackSourceFactory_construct)(PackSourceFactory*, Options*); -void (*ContentTierManager::ContentTierManager_construct)(ContentTierManager*); -void (*ResourcePackRepository::ResourcePackRepository_construct)(ResourcePackRepository*, MinecraftEventing&, PackManifestFactory&, IContentAccessibilityProvider&, FilePathManager*, PackSourceFactory &); void (*ResourcePackManager::ResourcePackManager_construct)(ResourcePackManager*, std::function const&, ContentTierManager const&); -void (*ResourcePackManager::ResourcePackManager_setStack)(ResourcePackManager*, std::unique_ptr, ResourcePackStackType, bool); -void (*ResourcePackManager::ResourcePackManager_onLanguageChanged)(ResourcePackManager*); - -#include "FilePathManager.h" - -void (*FilePathManager::FilePathManager_construct)(FilePathManager*, mcpe::string, bool); #include "UUID.h" mce::UUID* mce::UUID::EMPTY; -mce::UUID (*mce::UUID::fromString)(mcpe::string const&); #include "ServerInstance.h" -void (*NetworkHandler::NetworkHandler_construct)(NetworkHandler*); void (*ServerInstance::ServerInstance_construct)(ServerInstance*, IMinecraftApp&, Whitelist const&, OpsList const&, FilePathManager*, std::chrono::duration, mcpe::string, mcpe::string, mcpe::string, IContentAccessibilityProvider const&, mcpe::string, LevelSettings, minecraft::api::Api&, int, bool, int, int, int, bool, std::vector const&, mcpe::string, mce::UUID const&, MinecraftEventing&, NetworkHandler&, ResourcePackRepository&, ContentTierManager const&, ResourcePackManager&, ResourcePackManager*, std::function); -void (*ServerInstance::ServerInstance_update)(ServerInstance*); -void (*ServerInstance::ServerInstance_mainThreadNetworkUpdate_HACK)(ServerInstance*); - -#include "UserManager.h" - -std::unique_ptr (*Social::UserManager::CreateUserManager)(); - -#include "AutomationClient.h" - -void (*Automation::AutomationClient::AutomationClient_construct)(Automation::AutomationClient*, IMinecraftApp&); #include "Scheduler.h" -Scheduler* (*Scheduler::singleton)(); void (*Scheduler::Scheduler_processCoroutines)(Scheduler*, std::chrono::duration); -#include "Minecraft.h" - -MinecraftCommands* (*Minecraft::Minecraft_getCommands)(Minecraft*); - -#include "MinecraftCommands.h" - -void (*MinecraftCommands::MinecraftCommands_setOutputSender)(MinecraftCommands*, std::unique_ptr); -MCRESULT (*MinecraftCommands::MinecraftCommands_requestCommandExecution)(MinecraftCommands*, std::unique_ptr, mcpe::string const&, int, bool); - -#include "DedicatedServerCommandOrigin.h" - -void (*DedicatedServerCommandOrigin::DedicatedServerCommandOrigin_construct)(DedicatedServerCommandOrigin*, mcpe::string const&, Minecraft&); - #include "CommandOutputSender.h" -void (*CommandOutputSender::CommandOutputSender_construct)(CommandOutputSender*, Automation::AutomationClient&); void (*CommandOutputSender::CommandOutputSender_destruct)(CommandOutputSender*); -void (*CommandOutputSender::CommandOutputSender_send)(CommandOutputSender*, CommandOrigin const&, CommandOutput const&); -std::vector (*CommandOutputSender::CommandOutputSender_translate)(std::vector const&); - -#include "CommandOutput.h" - -std::vector const& (*CommandOutput::CommandOutput_getMessages)(CommandOutput const*); - -#include "I18n.h" - -mcpe::string (*I18n::I18n_get)(mcpe::string const&, std::vector const&); -void (*I18n::I18n_chooseLanguage)(mcpe::string const&); -void (*I18n::I18n_loadLanguages)(ResourcePackManager&, SkinRepository*, mcpe::string const&); #include "ResourcePackStack.h" void** ResourcePackStack::ResourcePackStack_vtable; -void (*PackInstance::PackInstance_construct)(PackInstance*, ResourcePack*, int, bool); -void (*ResourcePackStack::ResourcePackStack_add)(ResourcePackStack*, PackInstance const&, ResourcePackRepository const&, bool); \ No newline at end of file +void (*ResourcePackStack::ResourcePackStack_add)(ResourcePackStack*, PackInstance const&, ResourcePackRepository const&, bool); diff --git a/src/server.cpp b/src/server.cpp index decd84c..e3228dc 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -12,6 +12,7 @@ #include "common.h" #include "log.h" #include "linux_appplatform.h" +#include "minecraft/symbols.h" #include "minecraft/Api.h" #include "minecraft/Whitelist.h" #include "minecraft/OpsList.h" @@ -85,51 +86,18 @@ int main(int argc, char *argv[]) { Log::info("Launcher", "Loaded Minecraft library"); Log::debug("Launcher", "Minecraft is at offset 0x%x", libBase); + minecraft_symbols_init(handle); + mcpe::string::empty = (mcpe::string*) hybris_dlsym(handle, "_ZN4Util12EMPTY_STRINGE"); AppPlatform::myVtable = (void**) hybris_dlsym(handle, "_ZTV11AppPlatform"); AppPlatform::_singleton = (AppPlatform**) hybris_dlsym(handle, "_ZN11AppPlatform10mSingletonE"); - AppPlatform::AppPlatform_construct = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatformC2Ev"); - AppPlatform::AppPlatform_initialize = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatform10initializeEv"); - AppPlatform::AppPlatform__fireAppFocusGained = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatform19_fireAppFocusGainedEv"); - - LevelSettings::LevelSettings_construct = (void (*)(LevelSettings*)) hybris_dlsym(handle, "_ZN13LevelSettingsC2Ev"); - LevelSettings::LevelSettings_construct2 = (void (*)(LevelSettings*, LevelSettings const&)) hybris_dlsym(handle, "_ZN13LevelSettingsC2ERKS_"); - MinecraftEventing::MinecraftEventing_construct = (void (*)(MinecraftEventing*, mcpe::string const&)) hybris_dlsym(handle, "_ZN17MinecraftEventingC2ERKSs"); - MinecraftEventing::MinecraftEventing_init = (void (*)(MinecraftEventing*)) hybris_dlsym(handle, "_ZN17MinecraftEventing4initEv"); - SkinPackKeyProvider::SkinPackKeyProvider_construct = (void (*)(SkinPackKeyProvider*)) hybris_dlsym(handle, "_ZN19SkinPackKeyProviderC2Ev"); - PackManifestFactory::PackManifestFactory_construct = (void (*)(PackManifestFactory*, IPackTelemetry&)) hybris_dlsym(handle, "_ZN19PackManifestFactoryC2ER14IPackTelemetry"); - PackSourceFactory::PackSourceFactory_construct = (void (*)(PackSourceFactory*, Options*)) hybris_dlsym(handle, "_ZN17PackSourceFactoryC2EP7Options"); ResourcePackManager::ResourcePackManager_construct = (void (*)(ResourcePackManager*, std::function const&, ContentTierManager const&)) hybris_dlsym(handle, "_ZN19ResourcePackManagerC2ESt8functionIFSsvEERK18ContentTierManager"); - ResourcePackManager::ResourcePackManager_setStack = (void (*)(ResourcePackManager*, std::unique_ptr, ResourcePackStackType, bool)) hybris_dlsym(handle, "_ZN19ResourcePackManager8setStackESt10unique_ptrI17ResourcePackStackSt14default_deleteIS1_EE21ResourcePackStackTypeb"); - ResourcePackManager::ResourcePackManager_onLanguageChanged = (void (*)(ResourcePackManager*)) hybris_dlsym(handle, "_ZN19ResourcePackManager17onLanguageChangedEv"); - ResourcePackRepository::ResourcePackRepository_construct = (void (*)(ResourcePackRepository*, MinecraftEventing&, PackManifestFactory&, IContentAccessibilityProvider&, FilePathManager*, PackSourceFactory &)) hybris_dlsym(handle, "_ZN22ResourcePackRepositoryC2ER17MinecraftEventingR19PackManifestFactoryR29IContentAccessibilityProviderP15FilePathManagerR17PackSourceFactory"); - ContentTierManager::ContentTierManager_construct = (void (*)(ContentTierManager*)) hybris_dlsym(handle, "_ZN18ContentTierManagerC2Ev"); - FilePathManager::FilePathManager_construct = (void (*)(FilePathManager*, mcpe::string, bool)) hybris_dlsym(handle, "_ZN15FilePathManagerC2ESsb"); ((void*&) ServerInstance::ServerInstance_construct) = hybris_dlsym(handle, "_ZN14ServerInstanceC2ER13IMinecraftAppRK9WhitelistRK7OpsListP15FilePathManagerNSt6chrono8durationIxSt5ratioILx1ELx1EEEESsSsSsRK19IContentKeyProviderSs13LevelSettingsRN9minecraft3api3ApiEibiiibRKSt6vectorISsSaISsEESsRKN3mce4UUIDER17MinecraftEventingR14NetworkHandlerR22ResourcePackRepositoryRK18ContentTierManagerR19ResourcePackManagerPS15_St8functionIFvRKSsEE"); - ServerInstance::ServerInstance_update = (void (*)(ServerInstance*)) hybris_dlsym(handle, "_ZN14ServerInstance6updateEv"); - ServerInstance::ServerInstance_mainThreadNetworkUpdate_HACK = (void (*)(ServerInstance*)) hybris_dlsym(handle, "_ZN14ServerInstance28mainThreadNetworkUpdate_HACKEv"); mce::UUID::EMPTY = (mce::UUID*) hybris_dlsym(handle, "_ZN3mce4UUID5EMPTYE"); - mce::UUID::fromString = (mce::UUID (*)(mcpe::string const&)) hybris_dlsym(handle, "_ZN3mce4UUID10fromStringERKSs"); - NetworkHandler::NetworkHandler_construct = (void (*)(NetworkHandler*)) hybris_dlsym(handle, "_ZN14NetworkHandlerC2Ev"); - Social::UserManager::CreateUserManager = (std::unique_ptr (*)()) hybris_dlsym(handle, "_ZN6Social11UserManager17CreateUserManagerEv"); - Automation::AutomationClient::AutomationClient_construct = (void (*)(Automation::AutomationClient*, IMinecraftApp&)) hybris_dlsym(handle, "_ZN10Automation16AutomationClientC2ER13IMinecraftApp"); - Scheduler::singleton = (Scheduler* (*)()) hybris_dlsym(handle, "_ZN9Scheduler9singletonEv"); Scheduler::Scheduler_processCoroutines = (void (*)(Scheduler*, std::chrono::duration)) hybris_dlsym(handle, "_ZN9Scheduler17processCoroutinesENSt6chrono8durationIxSt5ratioILx1ELx1000000000EEEE"); - Minecraft::Minecraft_getCommands = (MinecraftCommands* (*)(Minecraft*)) hybris_dlsym(handle, "_ZN9Minecraft11getCommandsEv"); - MinecraftCommands::MinecraftCommands_requestCommandExecution = (MCRESULT (*)(MinecraftCommands*, std::unique_ptr, mcpe::string const&, int, bool)) hybris_dlsym(handle, "_ZNK17MinecraftCommands23requestCommandExecutionESt10unique_ptrI13CommandOriginSt14default_deleteIS1_EERKSsib"); - MinecraftCommands::MinecraftCommands_setOutputSender = (void (*)(MinecraftCommands*, std::unique_ptr)) hybris_dlsym(handle, "_ZN17MinecraftCommands15setOutputSenderESt10unique_ptrI19CommandOutputSenderSt14default_deleteIS1_EE"); - DedicatedServerCommandOrigin::DedicatedServerCommandOrigin_construct = (void (*)(DedicatedServerCommandOrigin*, mcpe::string const&, Minecraft&)) hybris_dlsym(handle, "_ZN28DedicatedServerCommandOriginC2ERKSsR9Minecraft"); - CommandOutputSender::CommandOutputSender_construct = (void (*)(CommandOutputSender*, Automation::AutomationClient&)) hybris_dlsym(handle, "_ZN19CommandOutputSenderC2ERN10Automation16AutomationClientE"); CommandOutputSender::CommandOutputSender_destruct = (void (*)(CommandOutputSender*)) hybris_dlsym(handle, "_ZN19CommandOutputSenderD2Ev"); - CommandOutputSender::CommandOutputSender_send = (void (*)(CommandOutputSender*, CommandOrigin const&, CommandOutput const&)) hybris_dlsym(handle, "_ZN19CommandOutputSender4sendERK13CommandOriginRK13CommandOutput"); - CommandOutputSender::CommandOutputSender_translate = (std::vector (*)(std::vector const&)) hybris_dlsym(handle, "_ZN19CommandOutputSender9translateERKSt6vectorISsSaISsEE"); - CommandOutput::CommandOutput_getMessages = (std::vector const& (*)(CommandOutput const*)) hybris_dlsym(handle, "_ZNK13CommandOutput11getMessagesEv"); - I18n::I18n_get = (mcpe::string (*)(mcpe::string const&, std::vector const&)) hybris_dlsym(handle, "_ZN4I18n3getERKSsRKSt6vectorISsSaISsEE"); - I18n::I18n_loadLanguages = (void (*)(ResourcePackManager&, SkinRepository*, mcpe::string const&)) hybris_dlsym(handle, "_ZN4I18n13loadLanguagesER19ResourcePackManagerP14SkinRepositoryRKSs"); - I18n::I18n_chooseLanguage = (void (*)(mcpe::string const&)) hybris_dlsym(handle, "_ZN4I18n14chooseLanguageERKSs"); ResourcePackStack::ResourcePackStack_vtable = (void**) hybris_dlsym(handle, "_ZTV11AppPlatform"); - PackInstance::PackInstance_construct = (void (*)(PackInstance*, ResourcePack*, int, bool)) hybris_dlsym(handle, "_ZN12PackInstanceC2EP12ResourcePackib"); ResourcePackStack::ResourcePackStack_add = (void (*)(ResourcePackStack*, PackInstance const&, ResourcePackRepository const&, bool)) hybris_dlsym(handle, "_ZN17ResourcePackStack3addE12PackInstanceRK22ResourcePackRepositoryb"); Log::info("Launcher", "Starting server initialization"); diff --git a/tools/cppheaderparser/CppHeaderParser.py b/tools/cppheaderparser/CppHeaderParser.py new file mode 100644 index 0000000..6279f2b --- /dev/null +++ b/tools/cppheaderparser/CppHeaderParser.py @@ -0,0 +1,2642 @@ +#!/usr/bin/python +# +# Author: Jashua R. Cloutier (contact via https://bitbucket.org/senex) +# Project: http://senexcanis.com/open-source/cppheaderparser/ +# +# Copyright (C) 2011, Jashua R. Cloutier +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# * Neither the name of Jashua R. Cloutier nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. Stories, +# blog entries etc making reference to this project may mention the +# name Jashua R. Cloutier in terms of project originator/creator etc. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# +# The CppHeaderParser.py script is written in Python 2.4 and released to +# the open source community for continuous improvements under the BSD +# 2.0 new license, which can be found at: +# +# http://www.opensource.org/licenses/bsd-license.php +# +"""Parse C++ header files and generate a data structure +representing the class +""" + +import ply.lex as lex +import os +import sys +import re + +import inspect + +def lineno(): + """Returns the current line number in our program.""" + return inspect.currentframe().f_back.f_lineno + +version = __version__ = "2.7.3" + +tokens = [ + 'NUMBER', + 'FLOAT_NUMBER', + 'TEMPLATE_NAME', + 'NAME', + 'OPEN_PAREN', + 'CLOSE_PAREN', + 'OPEN_BRACE', + 'CLOSE_BRACE', + 'OPEN_SQUARE_BRACKET', + 'CLOSE_SQUARE_BRACKET', + 'COLON', + 'SEMI_COLON', + 'COMMA', + 'TAB', + 'BACKSLASH', + 'PIPE', + 'PERCENT', + 'EXCLAMATION', + 'CARET', + 'COMMENT_SINGLELINE', + 'COMMENT_MULTILINE', + 'PRECOMP_MACRO', + 'PRECOMP_MACRO_CONT', + 'ASTERISK', + 'AMPERSTAND', + 'EQUALS', + 'MINUS', + 'PLUS', + 'DIVIDE', + 'CHAR_LITERAL', + 'STRING_LITERAL', + 'NEW_LINE', + 'SQUOTE', +] + +t_ignore = " \r.?@\f" +t_NUMBER = r'[0-9][0-9XxA-Fa-f]*' +t_FLOAT_NUMBER = r'[-+]?[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?' +t_TEMPLATE_NAME = r'CppHeaderParser_template_[0-9]+' +t_NAME = r'[<>A-Za-z_~][A-Za-z0-9_]*' +t_OPEN_PAREN = r'\(' +t_CLOSE_PAREN = r'\)' +t_OPEN_BRACE = r'{' +t_CLOSE_BRACE = r'}' +t_OPEN_SQUARE_BRACKET = r'\[' +t_CLOSE_SQUARE_BRACKET = r'\]' +t_SEMI_COLON = r';' +t_COLON = r':' +t_COMMA = r',' +t_TAB = r'\t' +t_BACKSLASH = r'\\' +t_PIPE = r'\|' +t_PERCENT = r'%' +t_CARET = r'\^' +t_EXCLAMATION = r'!' +t_PRECOMP_MACRO = r'\#.*' +t_PRECOMP_MACRO_CONT = r'.*\\\n' +def t_COMMENT_SINGLELINE(t): + r'\/\/.*\n' + global doxygenCommentCache + if t.value.startswith("///") or t.value.startswith("//!"): + if doxygenCommentCache: + doxygenCommentCache += "\n" + if t.value.endswith("\n"): + doxygenCommentCache += t.value[:-1] + else: + doxygenCommentCache += t.value + t.lexer.lineno += len([a for a in t.value if a=="\n"]) +t_ASTERISK = r'\*' +t_MINUS = r'\-' +t_PLUS = r'\+' +t_DIVIDE = r'/(?!/)' +t_AMPERSTAND = r'&' +t_EQUALS = r'=' +t_CHAR_LITERAL = "'.'" +t_SQUOTE = "'" +#found at http://wordaligned.org/articles/string-literals-and-regular-expressions +#TODO: This does not work with the string "bla \" bla" +t_STRING_LITERAL = r'"([^"\\]|\\.)*"' +#Found at http://ostermiller.org/findcomment.html +def t_COMMENT_MULTILINE(t): + r'/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/' + global doxygenCommentCache + if t.value.startswith("/**") or t.value.startswith("/*!"): + #not sure why, but get double new lines + v = t.value.replace("\n\n", "\n") + #strip prefixing whitespace + v = re.sub("\n[\s]+\*", "\n*", v) + doxygenCommentCache += v + t.lexer.lineno += len([a for a in t.value if a=="\n"]) +def t_NEWLINE(t): + r'\n+' + t.lexer.lineno += len(t.value) + +def t_error(v): + print(( "Lex error: ", v )) + +lex.lex() +# Controls error_print +print_errors = 1 +# Controls warning_print +print_warnings = 1 +# Controls debug_print +debug = 0 +# Controls trace_print +debug_trace = 0 + +def error_print(arg): + if print_errors: print(("[%4d] %s"%(inspect.currentframe().f_back.f_lineno, arg))) + +def warning_print(arg): + if print_warnings: print(("[%4d] %s"%(inspect.currentframe().f_back.f_lineno, arg))) + +def debug_print(arg): + global debug + if debug: print(("[%4d] %s"%(inspect.currentframe().f_back.f_lineno, arg))) + +def trace_print(*arg): + global debug_trace + if debug_trace: + sys.stdout.write("[%s] "%(inspect.currentframe().f_back.f_lineno)) + for a in arg: sys.stdout.write("%s "%a) + sys.stdout.write("\n") + +supportedAccessSpecifier = [ + 'public', + 'protected', + 'private' +] + +#Symbols to ignore, usually special macros +ignoreSymbols = [ + 'Q_OBJECT', +] + +doxygenCommentCache = "" + +#Track what was added in what order and at what depth +parseHistory = [] + +def is_namespace(nameStack): + """Determines if a namespace is being specified""" + if len(nameStack) == 0: + return False + if nameStack[0] == "namespace": + return True + return False + +def is_enum_namestack(nameStack): + """Determines if a namestack is an enum namestack""" + if len(nameStack) == 0: + return False + if nameStack[0] == "enum": + return True + if len(nameStack) > 1 and nameStack[0] == "typedef" and nameStack[1] == "enum": + return True + return False + +def is_fundamental(s): + for a in s.split(): + if a not in ["size_t", "struct", "union", "unsigned", "signed", "bool", "char", "short", "int", "float", "double", "long", "void", "*", "&"]: return False + return True + +def is_function_pointer_stack(stack): + """Count how many non-nested paranthesis are in the stack. Useful for determining if a stack is a function pointer""" + paren_depth = 0 + paren_count = 0 + star_after_first_paren = False + last_e = None + for e in stack: + if e == "(": + paren_depth += 1 + elif e == ")" and paren_depth > 0: + paren_depth -= 1 + if paren_depth == 0: + paren_count += 1 + elif e == "*" and last_e == "(" and paren_count == 0 and paren_depth == 1: + star_after_first_paren = True + last_e = e + + if star_after_first_paren and paren_count == 2: + return True + else: + return False + +def is_method_namestack(stack): + r = False + if '(' not in stack: r = False + elif stack[0] == 'typedef': r = False # TODO deal with typedef function prototypes + #elif '=' in stack and stack.index('=') < stack.index('(') and stack[stack.index('=')-1] != 'operator': r = False #disabled July6th - allow all operators + elif 'operator' in stack: r = True # allow all operators + elif '{' in stack and stack.index('{') < stack.index('('): r = False # struct that looks like a method/class + elif '[' in stack and stack.index('[') < stack.index('('): r = False # array with sizeof() + elif '(' in stack and ')' in stack: + if '{' in stack and '}' in stack: r = True + elif stack[-1] == ';': + if is_function_pointer_stack(stack): + r = False + else: + r = True + elif '{' in stack: r = True # ideally we catch both braces... TODO + else: r = False + #Test for case of property set to something with parens such as "static const int CONST_A = (1 << 7) - 1;" + if r and "(" in stack and "=" in stack and 'operator' not in stack: + if stack.index("=") < stack.index("("): r = False + # Test for template functions (std::function) + if stack[0] != 'template': + in_template = False + for e in stack: + if e.startswith('<'): + in_template = True + elif e == '>': + in_template = False + elif e == '(' and in_template: + return False + return r + +def is_property_namestack(nameStack): + r = False + if '(' not in nameStack and ')' not in nameStack: r = True + elif "(" in nameStack and "=" in nameStack and nameStack.index("=") < nameStack.index("("): r = True + #See if we are a function pointer + if not r and is_function_pointer_stack(nameStack): r = True + return r + +def detect_lineno(s): + """Detect the line number for a given token string""" + try: + rtn = s.lineno() + if rtn != -1: + return rtn + except: pass + global curLine + return curLine + +def filter_out_attribute_keyword(stack): + """Strips __attribute__ and its parenthetical expression from the stack""" + if "__attribute__" not in stack: return stack + try: + debug_print("Stripping __attribute__ from %s"% stack) + attr_index = stack.index("__attribute__") + attr_end = attr_index + 1 #Assuming not followed by parenthetical expression which wont happen + #Find final paren + if stack[attr_index + 1] == '(': + paren_count = 1 + for i in range(attr_index + 2, len(stack)): + elm = stack[i] + if elm == '(': + paren_count += 1 + elif elm == ')': + paren_count -= 1 + if paren_count == 0: + attr_end = i + 1 + break + new_stack = stack[0:attr_index] + stack[attr_end:] + debug_print("stripped stack is %s"% new_stack) + return new_stack + except: + return stack + + +class TagStr(str): + """Wrapper for a string that allows us to store the line number associated with it""" + lineno_reg = {} + def __new__(cls,*args,**kw): + new_obj = str.__new__(cls,*args) + if "lineno" in kw: + TagStr.lineno_reg[id(new_obj)] = kw["lineno"] + return new_obj + + def __del__(self): + try: + del TagStr.lineno_reg[id(self)] + except: pass + + def lineno(self): + return TagStr.lineno_reg.get(id(self), -1) + +class CppParseError(Exception): pass + +class CppClass(dict): + """Takes a name stack and turns it into a class + + Contains the following Keys: + self['name'] - Name of the class + self['doxygen'] - Doxygen comments associated with the class if they exist + self['inherits'] - List of Classes that this one inherits where the values + are of the form {"access": Anything in supportedAccessSpecifier + "class": Name of the class + self['methods'] - Dictionary where keys are from supportedAccessSpecifier + and values are a lists of CppMethod's + self['properties'] - Dictionary where keys are from supportedAccessSpecifier + and values are lists of CppVariable's + self['enums'] - Dictionary where keys are from supportedAccessSpecifier and + values are lists of CppEnum's + self['structs'] - Dictionary where keys are from supportedAccessSpecifier and + values are lists of nested Struct's + + An example of how this could look is as follows: + #self = + { + 'name': "" + 'inherits':[] + 'methods': + { + 'public':[], + 'protected':[], + 'private':[] + }, + 'properties': + { + 'public':[], + 'protected':[], + 'private':[] + }, + 'enums': + { + 'public':[], + 'protected':[], + 'private':[] + } + } + """ + + def get_all_methods(self): + r = [] + for typ in supportedAccessSpecifier: r += self['methods'][typ] + return r + + def get_all_method_names( self ): + r = [] + for typ in supportedAccessSpecifier: r += self.get_method_names(typ) # returns list + return r + + def get_all_pure_virtual_methods( self ): + r = {} + for typ in supportedAccessSpecifier: r.update(self.get_pure_virtual_methods(typ)) # returns dict + return r + + + def get_method_names( self, type='public' ): return [ meth['name'] for meth in self['methods'][ type ] ] + + def get_pure_virtual_methods( self, type='public' ): + r = {} + for meth in self['methods'][ type ]: + if meth['pure_virtual']: r[ meth['name'] ] = meth + return r + + def __init__(self, nameStack, curTemplate): + self['nested_classes'] = [] + self['parent'] = None + self['abstract'] = False + self._public_enums = {} + self._public_structs = {} + self._public_typedefs = {} + self._public_forward_declares = [] + self['namespace'] = "" + + debug_print( "Class: %s"%nameStack ) + debug_print( "Template: %s"%curTemplate) + + if (len(nameStack) < 2): + nameStack.insert(1, "")#anonymous struct + global doxygenCommentCache + if len(doxygenCommentCache): + self["doxygen"] = doxygenCommentCache + doxygenCommentCache = "" + + if "::" in "".join(nameStack): + #Re-Join class paths (ex ['class', 'Bar', ':', ':', 'Foo'] -> ['class', 'Bar::Foo'] + try: + new_nameStack = [] + for name in nameStack: + if len(new_nameStack) == 0: + new_nameStack.append(name) + elif name == ":" and new_nameStack[-1].endswith(":"): + new_nameStack[-1] += name + elif new_nameStack[-1].endswith("::"): + new_nameStack[-2] += new_nameStack[-1] + name + del new_nameStack[-1] + else: + new_nameStack.append(name) + trace_print("Convert from namestack\n %s\nto\n%s"%(nameStack, new_nameStack)) + nameStack = new_nameStack + except: pass + + # Handle final specifier + self["final"] = False + try: + final_index = nameStack.index("final") + # Dont trip up the rest of the logic + del nameStack[final_index] + self["final"] = True + trace_print("final") + except: pass + + self["name"] = nameStack[1] + self["line_number"] = detect_lineno(nameStack[0]) + + #Handle template classes + if len(nameStack) > 3 and nameStack[2].startswith("<"): + open_template_count = 0 + param_separator = 0 + found_first = False + i = 0 + for elm in nameStack: + if '<' in elm : + open_template_count += 1 + found_first = True + elif '>' in elm: + open_template_count -= 1 + if found_first and open_template_count == 0: + self["name"] = "".join(nameStack[1:i + 1]) + break; + i += 1 + elif ":" in nameStack: + self['name'] = nameStack[ nameStack.index(':') - 1 ] + + inheritList = [] + + if nameStack.count(':') == 1: + nameStack = nameStack[nameStack.index(":") + 1:] + while len(nameStack): + tmpStack = [] + tmpInheritClass = {"access":"private", "virtual": False} + if "," in nameStack: + tmpStack = nameStack[:nameStack.index(",")] + nameStack = nameStack[nameStack.index(",") + 1:] + else: + tmpStack = nameStack + nameStack = [] + + # Convert template classes to one name in the last index + for i in range(0, len(tmpStack)): + if '<' in tmpStack[i]: + tmpStack2 = tmpStack[:i-1] + tmpStack2.append("".join(tmpStack[i-1:])) + tmpStack = tmpStack2 + break + if len(tmpStack) == 0: + break; + elif len(tmpStack) == 1: + tmpInheritClass["class"] = tmpStack[0] + elif len(tmpStack) == 2: + tmpInheritClass["access"] = tmpStack[0] + tmpInheritClass["class"] = tmpStack[1] + elif len(tmpStack) == 3 and "virtual" in tmpStack: + tmpInheritClass["access"] = tmpStack[1] if tmpStack[1] != "virtual" else tmpStack[0] + tmpInheritClass["class"] = tmpStack[2] + tmpInheritClass["virtual"] = True + else: + warning_print( "Warning: can not parse inheriting class %s"%(" ".join(tmpStack))) + if '>' in tmpStack: pass # allow skip templates for now + else: raise NotImplemented + + if 'class' in tmpInheritClass: inheritList.append(tmpInheritClass) + + elif nameStack.count(':') == 2: self['parent'] = self['name']; self['name'] = nameStack[-1] + + elif nameStack.count(':') > 2 and nameStack[0] in ("class", "struct"): + tmpStack = nameStack[nameStack.index(":") + 1:] + + superTmpStack = [[]] + for tok in tmpStack: + if tok == ',': + superTmpStack.append([]) + else: + superTmpStack[-1].append(tok) + + for tmpStack in superTmpStack: + tmpInheritClass = {"access":"private"} + + if len(tmpStack) and tmpStack[0] in supportedAccessSpecifier: + tmpInheritClass["access"] = tmpStack[0] + tmpStack = tmpStack[1:] + + inheritNSStack = [] + while len(tmpStack) > 3: + if tmpStack[0] == ':': break; + if tmpStack[1] != ':': break; + if tmpStack[2] != ':': break; + inheritNSStack.append(tmpStack[0]) + tmpStack = tmpStack[3:] + if len(tmpStack) == 1 and tmpStack[0] != ':': + inheritNSStack.append(tmpStack[0]) + tmpInheritClass["class"] = "::".join(inheritNSStack) + inheritList.append(tmpInheritClass) + + self['inherits'] = inheritList + + if curTemplate: + self["template"] = curTemplate + trace_print("Setting template to '%s'"%self["template"]) + + methodAccessSpecificList = {} + propertyAccessSpecificList = {} + enumAccessSpecificList = {} + structAccessSpecificList = {} + typedefAccessSpecificList = {} + forwardAccessSpecificList = {} + + for accessSpecifier in supportedAccessSpecifier: + methodAccessSpecificList[accessSpecifier] = [] + propertyAccessSpecificList[accessSpecifier] = [] + enumAccessSpecificList[accessSpecifier] = [] + structAccessSpecificList[accessSpecifier] = [] + typedefAccessSpecificList[accessSpecifier] = [] + forwardAccessSpecificList[accessSpecifier] = [] + + self['methods'] = methodAccessSpecificList + self['properties'] = propertyAccessSpecificList + self['enums'] = enumAccessSpecificList + self['structs'] = structAccessSpecificList + self['typedefs'] = typedefAccessSpecificList + self['forward_declares'] = forwardAccessSpecificList + + + def show(self): + """Convert class to a string""" + namespace_prefix = "" + if self["namespace"]: namespace_prefix = self["namespace"] + "::" + rtn = "%s %s"%(self["declaration_method"], namespace_prefix + self["name"]) + if self["final"]: rtn += " final" + if self['abstract']: rtn += ' (abstract)\n' + else: rtn += '\n' + + if 'doxygen' in list(self.keys()): rtn += self["doxygen"] + '\n' + if 'parent' in list(self.keys()) and self['parent']: rtn += 'parent class: ' + self['parent'] + '\n' + + if "inherits" in list(self.keys()): + rtn += " Inherits: " + for inheritClass in self["inherits"]: + if inheritClass["virtual"]: rtn += "virtual " + rtn += "%s %s, "%(inheritClass["access"], inheritClass["class"]) + rtn += "\n" + rtn += " {\n" + for accessSpecifier in supportedAccessSpecifier: + rtn += " %s\n"%(accessSpecifier) + #Enums + if (len(self["enums"][accessSpecifier])): + rtn += " \n" + for enum in self["enums"][accessSpecifier]: + rtn += " %s\n"%(repr(enum)) + #Properties + if (len(self["properties"][accessSpecifier])): + rtn += " \n" + for property in self["properties"][accessSpecifier]: + rtn += " %s\n"%(repr(property)) + #Methods + if (len(self["methods"][accessSpecifier])): + rtn += " \n" + for method in self["methods"][accessSpecifier]: + rtn += "\t\t" + method.show() + '\n' + rtn += " }\n" + print(rtn) + + def __str__(self): + """Convert class to a string""" + namespace_prefix = "" + if self["namespace"]: namespace_prefix = self["namespace"] + "::" + rtn = "%s %s"%(self["declaration_method"], namespace_prefix + self["name"]) + if self["final"]: rtn += " final" + if self['abstract']: rtn += ' (abstract)\n' + else: rtn += '\n' + + if 'doxygen' in list(self.keys()): rtn += self["doxygen"] + '\n' + if 'parent' in list(self.keys()) and self['parent']: rtn += 'parent class: ' + self['parent'] + '\n' + + if "inherits" in list(self.keys()) and len(self["inherits"]): + rtn += "Inherits: " + for inheritClass in self["inherits"]: + if inheritClass.get("virtual", False): rtn += "virtual " + rtn += "%s %s, "%(inheritClass["access"], inheritClass["class"]) + rtn += "\n" + rtn += "{\n" + for accessSpecifier in supportedAccessSpecifier: + rtn += "%s\n"%(accessSpecifier) + #Enums + if (len(self["enums"][accessSpecifier])): + rtn += " // Enums\n" + for enum in self["enums"][accessSpecifier]: + rtn += " %s\n"%(repr(enum)) + #Properties + if (len(self["properties"][accessSpecifier])): + rtn += " // Properties\n" + for property in self["properties"][accessSpecifier]: + rtn += " %s\n"%(repr(property)) + #Methods + if (len(self["methods"][accessSpecifier])): + rtn += " // Methods\n" + for method in self["methods"][accessSpecifier]: + rtn += " %s\n"%(repr(method)) + rtn += "}\n" + return rtn + + +class CppUnion( CppClass ): + """Takes a name stack and turns it into a union + + Contains the following Keys: + self['name'] - Name of the union + self['doxygen'] - Doxygen comments associated with the union if they exist + self['members'] - List of members the union has + + An example of how this could look is as follows: + #self = + { + 'name': "" + 'members': [] + } + """ + + def __init__(self, nameStack): + CppClass.__init__(self, nameStack, None) + self["name"] = "union " + self["name"] + self["members"] = self["properties"]["public"] + + def transform_to_union_keys(self): + print("union keys: %s"%list(self.keys())) + for key in ['inherits', 'parent', 'abstract', 'namespace', 'typedefs', 'methods']: + del self[key] + + def show(self): + """Convert class to a string""" + print(self) + + + def __str__(self): + """Convert class to a string""" + namespace_prefix = "" + if self["namespace"]: namespace_prefix = self["namespace"] + "::" + rtn = "%s %s"%(self["declaration_method"], namespace_prefix + self["name"]) + if self['abstract']: rtn += ' (abstract)\n' + else: rtn += '\n' + + if 'doxygen' in list(self.keys()): rtn += self["doxygen"] + '\n' + if 'parent' in list(self.keys()) and self['parent']: rtn += 'parent class: ' + self['parent'] + '\n' + + rtn += "{\n" + for member in self["members"]: + rtn += " %s\n"%(repr(member)) + rtn += "}\n" + return rtn + + + +class _CppMethod( dict ): + def _params_helper1( self, stack ): + # deal with "throw" keyword + if 'throw' in stack: stack = stack[ : stack.index('throw') ] + + ## remove GCC keyword __attribute__(...) and preserve returns ## + cleaned = [] + hit = False; hitOpen = 0; hitClose = 0 + for a in stack: + if a == '__attribute__': hit = True + if hit: + if a == '(': hitOpen += 1 + elif a == ')': hitClose += 1 + if a==')' and hitOpen == hitClose: + hit = False + else: + cleaned.append( a ) + stack = cleaned + + # also deal with attribute((const)) function prefix # + # TODO this needs to be better # + if len(stack) > 5: + a = ''.join(stack) + if a.startswith('((__const__))'): stack = stack[ 5 : ] + elif a.startswith('__attribute__((__const__))'): stack = stack[ 6 : ] + + stack = stack[stack.index('(') + 1: ] + if not stack: return [] + if len(stack)>=3 and stack[0]==')' and stack[1]==':': # is this always a constructor? + self['constructor'] = True + return [] + + stack.reverse(); _end_ = stack.index(')'); stack.reverse() + stack = stack[ : len(stack)-(_end_+1) ] + if '(' not in stack: return stack # safe to return, no defaults that init a class + + # transforms ['someclass', '(', '0', '0', '0', ')'] into "someclass(0,0,0)'" + r = []; hit=False + for a in stack: + if a == '(': hit=True + elif a == ')': hit=False + if hit or a == ')': r[-1] = r[-1] + a + else: r.append( a ) + return r + + def _params_helper2( self, params ): + for p in params: + p['method'] = self # save reference in variable to parent method + if '::' in p['type']: + ns = p['type'].split('::')[0] + if ns not in Resolver.NAMESPACES and ns in Resolver.CLASSES: + p['type'] = self['namespace'] + p['type'] + else: p['namespace'] = self[ 'namespace' ] + +class CppMethod( _CppMethod ): + """Takes a name stack and turns it into a method + + Contains the following Keys: + self['rtnType'] - Return type of the method (ex. "int") + self['name'] - Name of the method (ex. "getSize") + self['doxygen'] - Doxygen comments associated with the method if they exist + self['parameters'] - List of CppVariables + """ + def show(self): + r = ['method name: %s (%s)' %(self['name'],self['debug']) ] + if self['returns']: r.append( 'returns: %s'%self['returns'] ) + if self['parameters']: r.append( 'number arguments: %s' %len(self['parameters'])) + if self['pure_virtual']: r.append( 'pure virtual: %s'%self['pure_virtual'] ) + if self['constructor']: r.append( 'constructor' ) + if self['destructor']: r.append( 'destructor' ) + return '\n\t\t '.join( r ) + + def __init__(self, nameStack, curClass, methinfo, curTemplate): + debug_print( "Method: %s"%nameStack ) + debug_print( "Template: %s"%curTemplate ) + global doxygenCommentCache + if len(doxygenCommentCache): + self["doxygen"] = doxygenCommentCache + doxygenCommentCache = "" + if "operator" in nameStack: + self["rtnType"] = " ".join(nameStack[:nameStack.index('operator')]) + self["name"] = "".join(nameStack[nameStack.index('operator'):nameStack.index('(')]) + else: + self["rtnType"] = " ".join(nameStack[:nameStack.index('(') - 1]) + self["name"] = " ".join(nameStack[nameStack.index('(') - 1:nameStack.index('(')]) + if self["rtnType"].startswith("virtual"): + self["rtnType"] = self["rtnType"][len("virtual"):].strip() + if len(self["rtnType"]) == 0 or self["name"] == curClass: + self["rtnType"] = "void" + + self["rtnType"] = self["rtnType"].replace(' : : ', '::' ) + self["rtnType"] = self["rtnType"].replace(" <","<") + self["rtnType"] = self["rtnType"].replace(" >",">").replace(">>", "> >").replace(">>", "> >") + self["rtnType"] = self["rtnType"].replace(" ,",",") + + for spec in ["const", "final", "override"]: + self[spec] = False + for i in reversed(nameStack): + if i == spec: + self[spec] = True + break + elif i == ")": + break + + self.update( methinfo ) + self["line_number"] = detect_lineno(nameStack[0]) + + #Filter out initializer lists used in constructors + try: + paren_depth_counter = 0 + for i in range(0, len(nameStack)): + elm = nameStack[i] + if elm == "(": + paren_depth_counter += 1 + if elm == ")": + paren_depth_counter -=1 + if paren_depth_counter == 0 and nameStack[i+1] == ':': + debug_print("Stripping out initializer list") + nameStack = nameStack[:i+1] + break + except: pass + + paramsStack = self._params_helper1( nameStack ) + + debug_print( "curTemplate: %s"%curTemplate) + if curTemplate: + self["template"] = curTemplate + debug_print( "SET self['template'] to `%s`"%self["template"]) + + params = [] + #See if there is a doxygen comment for the variable + doxyVarDesc = {} + + if "doxygen" in self: + doxyLines = self["doxygen"].split("\n") + lastParamDesc = "" + for doxyLine in doxyLines: + if " @param " in doxyLine or " \param " in doxyLine: + try: + #Strip out the param + doxyLine = doxyLine[doxyLine.find("param ") + 6:] + (var, desc) = doxyLine.split(" ", 1) + doxyVarDesc[var] = desc.strip() + lastParamDesc = var + except: pass + elif " @return " in doxyLine or " \return " in doxyLine: + lastParamDesc = "" + # not handled for now + elif lastParamDesc: + try: + doxyLine = doxyLine.strip() + if " " not in doxyLine: + lastParamDesc = "" + continue + doxyLine = doxyLine[doxyLine.find(" ") + 1:] + doxyVarDesc[lastParamDesc] += " " + doxyLine + except: pass + + #Create the variable now + while (len(paramsStack)): + # Find commas that are not nexted in <>'s like template types + open_template_count = 0 + param_separator = 0 + i = 0 + for elm in paramsStack: + if '<' in elm : + open_template_count += 1 + elif '>' in elm: + open_template_count -= 1 + elif elm == ',' and open_template_count == 0: + param_separator = i + break + i += 1 + + if param_separator: + param = CppVariable(paramsStack[0:param_separator], doxyVarDesc=doxyVarDesc) + if len(list(param.keys())): params.append(param) + paramsStack = paramsStack[param_separator + 1:] + else: + param = CppVariable(paramsStack, doxyVarDesc=doxyVarDesc) + if len(list(param.keys())): params.append(param) + break + + + self["parameters"] = params + self._params_helper2( params ) # mods params inplace + + def __str__(self): + filter_keys = ("parent", "defined", "operator", "returns_reference") + cpy = dict((k,v) for (k,v) in list(self.items()) if k not in filter_keys) + return "%s"%cpy + + +class _CppVariable(dict): + def _name_stack_helper( self, stack ): + stack = list(stack) + if '=' not in stack: # TODO refactor me + # check for array[n] and deal with funny array syntax: "int myvar:99" + array = [] + while stack and stack[-1].isdigit(): array.append( stack.pop() ) + if array: array.reverse(); self['array'] = int(''.join(array)) + if stack and stack[-1].endswith(':'): stack[-1] = stack[-1][:-1] + + while stack and not stack[-1]: stack.pop() # can be empty + return stack + + def init(self): + #assert self['name'] # allow unnamed variables, methods like this: "void func(void);" + a = [] + self['aliases'] = []; self['parent'] = None; self['typedef'] = None + for key in 'constant reference pointer static typedefs class fundamental unresolved'.split(): + self[ key ] = 0 + for b in self['type'].split(): + if b == '__const__': b = 'const' + a.append( b ) + self['type'] = ' '.join( a ) + + +class CppVariable( _CppVariable ): + """Takes a name stack and turns it into a method + + Contains the following Keys: + self['type'] - Type for the variable (ex. "const string &") + self['name'] - Name of the variable (ex. "numItems") + self['namespace'] - Namespace containing the enum + self['desc'] - Description of the variable if part of a method (optional) + self['doxygen'] - Doxygen comments associated with the method if they exist + self['defaultValue'] - Default value of the variable, this key will only + exist if there is a default value + self['extern'] - True if its an extern, false if not + """ + Vars = [] + def __init__(self, nameStack, **kwargs): + debug_print("trace %s"%nameStack) + if len(nameStack) and nameStack[0] == "extern": + self['extern'] = True + del nameStack[0] + else: + self['extern'] = False + + _stack_ = nameStack + if "[" in nameStack: #strip off array informatin + arrayStack = nameStack[nameStack.index("["):] + if nameStack.count("[") > 1: + debug_print("Multi dimensional array") + debug_print("arrayStack=%s"%arrayStack) + nums = filter(lambda x: x.isdigit(), arrayStack) + # Calculate size by multiplying all dimensions + p = 1 + for n in nums: + p *= int(n) + #Multi dimensional array + self["array_size"] = p + self["multi_dimensional_array"] = 1 + self["multi_dimensional_array_size"] = "x".join(nums) + else: + debug_print("Array") + if len(arrayStack) == 3: + self["array_size"] = arrayStack[1] + nameStack = nameStack[:nameStack.index("[")] + self["array"] = 1 + else: + self["array"] = 0 + nameStack = self._name_stack_helper( nameStack ) + global doxygenCommentCache + if len(doxygenCommentCache): + self["doxygen"] = doxygenCommentCache + doxygenCommentCache = "" + + debug_print( "Variable: %s"%nameStack ) + + self["line_number"] = detect_lineno(nameStack[0]) + self["function_pointer"] = 0 + + if (len(nameStack) < 2): # +++ + if len(nameStack) == 1: self['type'] = nameStack[0]; self['name'] = '' + else: error_print(_stack_); assert 0 + + elif is_function_pointer_stack(nameStack): #function pointer + self["type"] = " ".join(nameStack[:nameStack.index("(") + 2] + nameStack[nameStack.index(")") :]) + self["name"] = " ".join(nameStack[nameStack.index("(") + 2 : nameStack.index(")")]) + self["function_pointer"] = 1 + + elif ("=" in nameStack): + self["type"] = " ".join(nameStack[:nameStack.index("=") - 1]) + self["name"] = nameStack[nameStack.index("=") - 1] + self["defaultValue"] = " ".join(nameStack[nameStack.index("=") + 1:]) # deprecate camelCase in dicts + self['default'] = " ".join(nameStack[nameStack.index("=") + 1:]) + + elif is_fundamental(nameStack[-1]) or nameStack[-1] in ['>', '<', ':', '.'] or nameStack[-2] == ':': + #Un named parameter + self["type"] = " ".join(nameStack) + self["name"] = "" + + else: # common case + self["type"] = " ".join(nameStack[:-1]) + self["name"] = nameStack[-1] + + self["type"] = self["type"].replace(" :",":") + self["type"] = self["type"].replace(": ",":") + self["type"] = self["type"].replace(" <","<") + self["type"] = self["type"].replace(" >",">").replace(">>", "> >").replace(">>", "> >") + self["type"] = self["type"].replace(" ,",",") + #Optional doxygen description + try: + self["desc"] = kwargs["doxyVarDesc"][self["name"]] + except: pass + + self.init() + CppVariable.Vars.append( self ) # save and resolve later + + def __str__(self): + keys_white_list = ['constant','name','reference','type','static','pointer','desc', 'line_number', 'extern'] + cpy = dict((k,v) for (k,v) in list(self.items()) if k in keys_white_list) + if "array_size" in self: cpy["array_size"] = self["array_size"] + return "%s"%cpy + +class _CppEnum(dict): + def resolve_enum_values( self, values ): + """Evaluates the values list of dictionaries passed in and figures out what the enum value + for each enum is editing in place: + + Example: + From: [{'name': 'ORANGE'}, + {'name': 'RED'}, + {'name': 'GREEN', 'value': '8'}] + To: [{'name': 'ORANGE', 'value': 0}, + {'name': 'RED', 'value': 1}, + {'name': 'GREEN', 'value': 8}] + """ + t = int; i = 0 + names = [ v['name'] for v in values ] + for v in values: + if 'value' in v: + a = v['value'].strip() + # Remove single quotes from single quoted chars (unless part of some expression + if len(a) == 3 and a[0] == "'" and a[2] == "'": + a = v['value'] = a[1] + if a.lower().startswith("0x"): + try: + i = a = int(a , 16) + except:pass + elif a.isdigit(): + i = a = int( a ) + elif a in names: + for other in values: + if other['name'] == a: + v['value'] = other['value'] + break + + elif '"' in a or "'" in a: t = str # only if there are quotes it this a string enum + else: + try: + a = i = ord(a) + except: pass + #Allow access of what is in the file pre-convert if converted + if v['value'] != str(a): + v['raw_value'] = v['value'] + v['value'] = a + else: v['value'] = i + try: + v['value'] = v['value'].replace(" < < ", " << ").replace(" >> ", " >> ") + except: pass + i += 1 + return t + +class CppEnum(_CppEnum): + """Takes a name stack and turns it into an Enum + + Contains the following Keys: + self['name'] - Name of the enum (ex. "ItemState") + self['namespace'] - Namespace containing the enum + self['values'] - List of values where the values are a dictionary of the + form {"name": name of the key (ex. "PARSING_HEADER"), + "value": Specified value of the enum, this key will only exist + if a value for a given enum value was defined + } + """ + def __init__(self, nameStack): + global doxygenCommentCache + if len(doxygenCommentCache): + self["doxygen"] = doxygenCommentCache + doxygenCommentCache = "" + if len(nameStack) > 1 and nameStack[0] == "enum" and nameStack[1] == "class": + self["enum_class"] = True + nameStack.pop(1) + if len(nameStack) == 3 and nameStack[0] == "enum": + warning_print("Created enum as just name/value") + self["name"] = nameStack[1] + self["instances"]=[nameStack[2]] + if len(nameStack) > 2 and nameStack[0] == "enum" and nameStack[2] == ":": + # c++11 type specifier + if nameStack.count("{") > 0: + self["cpp_type"] = nameStack[3 : nameStack.index("{")] + del nameStack[2 : nameStack.index("{")] + else: + self["cpp_type"] = nameStack[3:] + del nameStack[2:] + if len(nameStack) == 2 and nameStack[0] == "enum": + self["name"] = nameStack[1] + self["type"] = int + return + elif len(nameStack) < 4 or "{" not in nameStack or "}" not in nameStack: + #Not enough stuff for an enum + warning_print("Bad enum") + return + valueList = [] + self["line_number"] = detect_lineno(nameStack[0]) + #Figure out what values it has + valueStack = nameStack[nameStack.index('{') + 1: nameStack.index('}')] + while len(valueStack): + tmpStack = [] + if "," in valueStack: + tmpStack = valueStack[:valueStack.index(",")] + valueStack = valueStack[valueStack.index(",") + 1:] + else: + tmpStack = valueStack + valueStack = [] + d = {} + if len(tmpStack) == 1: d["name"] = tmpStack[0] + elif len(tmpStack) >= 3 and tmpStack[1] == "=": + d["name"] = tmpStack[0]; d["value"] = " ".join(tmpStack[2:]) + elif len(tmpStack) == 2 and tmpStack[1] == "=": + debug_print( "WARN-enum: parser missed value for %s"%tmpStack[0] ) + d["name"] = tmpStack[0] + + if d: valueList.append( d ) + + if len(valueList): + self['type'] = self.resolve_enum_values( valueList ) # returns int for standard enum + self["values"] = valueList + else: + warning_print( 'WARN-enum: empty enum %s'%nameStack ) + return + #Figure out if it has a name + preBraceStack = nameStack[:nameStack.index("{")] + postBraceStack = nameStack[nameStack.index("}") + 1:] + self["typedef"] = False + if (len(preBraceStack) == 2 and "typedef" not in nameStack): + self["name"] = preBraceStack[1] + elif len(postBraceStack) and "typedef" in nameStack: + self["name"] = " ".join(postBraceStack) + self["typedef"] = True + else: warning_print( 'WARN-enum: nameless enum %s'%nameStack ) + #See if there are instances of this + if "typedef" not in nameStack and len(postBraceStack): + self["instances"] = [] + for var in postBraceStack: + if "," in var: + continue + self["instances"].append(var) + self["namespace"] = "" + + +class CppStruct(dict): + Structs = [] + def __init__(self, nameStack): + if len(nameStack) >= 2: self['type'] = nameStack[1] + else: self['type'] = None + self['fields'] = [] + self.Structs.append( self ) + global curLine + self["line_number"] = curLine + +C99_NONSTANDARD = { + 'int8' : 'signed char', + 'int16' : 'short int', + 'int32' : 'int', + 'int64' : 'int64_t', # this can be: long int (64bit), or long long int (32bit) + 'uint' : 'unsigned int', + 'uint8' : 'unsigned char', + 'uint16' : 'unsigned short int', + 'uint32' : 'unsigned int', + 'uint64' : 'uint64_t', # depends on host bits +} + + +def standardize_fundamental( s ): + if s in C99_NONSTANDARD: return C99_NONSTANDARD[ s ] + else: return s + + +class Resolver(object): + C_FUNDAMENTAL = 'size_t unsigned signed bool char wchar short int float double long void'.split() + C_FUNDAMENTAL += 'struct union enum'.split() + + + SubTypedefs = {} # TODO deprecate? + NAMESPACES = [] + CLASSES = {} + STRUCTS = {} + + def initextra(self): + self.typedefs = {} + self.typedefs_order = [] + self.classes_order = [] + self.structs = Resolver.STRUCTS + self.structs_order = [] + self.namespaces = Resolver.NAMESPACES # save all namespaces + self.curStruct = None + self.stack = [] # full name stack, good idea to keep both stacks? (simple stack and full stack) + self._classes_brace_level = {} # class name : level + self._structs_brace_level = {} # struct type : level + self._method_body = None + self._forward_decls = [] + self._template_typenames = [] # template + + def current_namespace(self): return self.cur_namespace(True) + + def cur_namespace(self, add_double_colon=False): + rtn = "" + i = 0 + while i < len(self.nameSpaces): + rtn += self.nameSpaces[i] + if add_double_colon or i < len(self.nameSpaces) - 1: rtn += "::" + i+=1 + return rtn + + + def guess_ctypes_type( self, string ): + pointers = string.count('*') + string = string.replace('*','') + + a = string.split() + if 'unsigned' in a: u = 'u' + else: u = '' + if 'long' in a and 'double' in a: b = 'longdouble' # there is no ctypes.c_ulongdouble (this is a 64bit float?) + elif a.count('long') == 2 and 'int' in a: b = '%sint64' %u + elif a.count('long') == 2: b = '%slonglong' %u + elif 'long' in a: b = '%slong' %u + elif 'double' in a: b = 'double' # no udouble in ctypes + elif 'short' in a: b = '%sshort' %u + elif 'char' in a: b = '%schar' %u + elif 'wchar' in a: b = 'wchar' + elif 'bool' in a: b = 'bool' + elif 'float' in a: b = 'float' + + elif 'int' in a: b = '%sint' %u + elif 'int8' in a: b = 'int8' + elif 'int16' in a: b = 'int16' + elif 'int32' in a: b = 'int32' + elif 'int64' in a: b = 'int64' + + elif 'uint' in a: b = 'uint' + elif 'uint8' in a: b = 'uint8' + elif 'uint16' in a: b = 'uint16' + elif 'uint32' in a: b = 'uint32' + elif 'uint64' in a: b = 'uint64' + + elif 'size_t' in a: b = 'size_t' + elif 'void' in a: b = 'void_p' + + elif string in 'struct union'.split(): b = 'void_p' # what should be done here? don't trust struct, it could be a class, no need to expose via ctypes + else: b = 'void_p' + + if not pointers: return 'ctypes.c_%s' %b + else: + x = '' + for i in range(pointers): x += 'ctypes.POINTER(' + x += 'ctypes.c_%s' %b + x += ')' * pointers + return x + + def resolve_type( self, string, result ): # recursive + ''' + keeps track of useful things like: how many pointers, number of typedefs, is fundamental or a class, etc... + ''' + ## be careful with templates, what is inside can be a pointer but the overall type is not a pointer + ## these come before a template + s = string.split('<')[0] + result[ 'constant' ] += s.split().count('const') + result[ 'static' ] += s.split().count('static') + result[ 'mutable' ] = 'mutable' in s.split() + + ## these come after a template + s = string.split('>')[-1] + result[ 'pointer' ] += s.count('*') + result[ 'reference' ] += s.count('&') + + + x = string; alias = False + for a in '* & const static mutable'.split(): x = x.replace(a,'') + for y in x.split(): + if y not in self.C_FUNDAMENTAL: alias = y; break + + #if alias == 'class': + # result['class'] = result['name'] # forward decl of class + # result['forward_decl'] = True + if alias == '__extension__': result['fundamental_extension'] = True + elif alias: + result['aliases'].append( alias ) + if alias in C99_NONSTANDARD: + result['type'] = C99_NONSTANDARD[ alias ] + result['typedef'] = alias + result['typedefs'] += 1 + elif alias in self.typedefs: + result['typedefs'] += 1 + result['typedef'] = alias + self.resolve_type( self.typedefs[alias], result ) + elif alias in self.classes: + klass = self.classes[alias]; result['fundamental'] = False + result['class'] = klass + result['unresolved'] = False + else: result['unresolved'] = True + else: + result['fundamental'] = True + result['unresolved'] = False + + + def finalize_vars(self): + for s in CppStruct.Structs: # vars within structs can be ignored if they do not resolve + for var in s['fields']: var['parent'] = s['type'] + #for c in self.classes.values(): + # for var in c.get_all_properties(): var['parent'] = c['name'] + + ## RESOLVE ## + for var in CppVariable.Vars: + self.resolve_type( var['type'], var ) + #if 'method' in var and var['method']['name'] == '_notifyCurrentCamera': print(var); assert 0 + + # then find concrete type and best guess ctypes type # + for var in CppVariable.Vars: + if not var['aliases']: #var['fundamental']: + var['ctypes_type'] = self.guess_ctypes_type( var['type'] ) + else: + var['unresolved'] = False # below may test to True + if var['class']: + var['ctypes_type'] = 'ctypes.c_void_p' + else: + assert var['aliases'] + tag = var['aliases'][0] + + klass = None + nestedEnum = None + nestedStruct = None + nestedTypedef = None + if 'method' in var and 'parent' in list(var['method'].keys()): + klass = var['method']['parent'] + if tag in var['method']['parent']._public_enums: + nestedEnum = var['method']['parent']._public_enums[ tag ] + elif tag in var['method']['parent']._public_structs: + nestedStruct = var['method']['parent']._public_structs[ tag ] + elif tag in var['method']['parent']._public_typedefs: + nestedTypedef = var['method']['parent']._public_typedefs[ tag ] + + + if '<' in tag: # should also contain '>' + var['template'] = tag # do not resolve templates + var['ctypes_type'] = 'ctypes.c_void_p' + var['unresolved'] = True + + elif nestedEnum: + enum = nestedEnum + if enum['type'] is int: + var['ctypes_type'] = 'ctypes.c_int' + var['raw_type'] = 'int' + + elif enum['type'] is str: + var['ctypes_type'] = 'ctypes.c_char_p' + var['raw_type'] = 'char*' + + var['enum'] = var['method']['path'] + '::' + enum['name'] + var['fundamental'] = True + + elif nestedStruct: + var['ctypes_type'] = 'ctypes.c_void_p' + var['raw_type'] = var['method']['path'] + '::' + nestedStruct['type'] + var['fundamental'] = False + + elif nestedTypedef: + var['fundamental'] = is_fundamental( nestedTypedef ) + if not var['fundamental']: + var['raw_type'] = var['method']['path'] + '::' + tag + + else: + _tag = tag + if '::' in tag and tag.split('::')[0] in self.namespaces: tag = tag.split('::')[-1] + con = self.concrete_typedef( _tag ) + if con: + var['concrete_type'] = con + var['ctypes_type'] = self.guess_ctypes_type( var['concrete_type'] ) + + elif tag in self.structs: + trace_print( 'STRUCT', var ) + var['struct'] = tag + var['ctypes_type'] = 'ctypes.c_void_p' + var['raw_type'] = self.structs[tag]['namespace'] + '::' + tag + + elif tag in self._forward_decls: + var['forward_declared'] = tag + var['ctypes_type'] = 'ctypes.c_void_p' + + elif tag in self.global_enums: + enum = self.global_enums[ tag ] + if enum['type'] is int: + var['ctypes_type'] = 'ctypes.c_int' + var['raw_type'] = 'int' + elif enum['type'] is str: + var['ctypes_type'] = 'ctypes.c_char_p' + var['raw_type'] = 'char*' + var['enum'] = enum['namespace'] + enum['name'] + var['fundamental'] = True + + + elif var['parent']: + warning_print( 'WARN unresolved %s'%_tag) + var['ctypes_type'] = 'ctypes.c_void_p' + var['unresolved'] = True + + + elif tag.count('::')==1: + trace_print( 'trying to find nested something in', tag ) + a = tag.split('::')[0] + b = tag.split('::')[-1] + if a in self.classes: # a::b is most likely something nested in a class + klass = self.classes[ a ] + if b in klass._public_enums: + trace_print( '...found nested enum', b ) + enum = klass._public_enums[ b ] + if enum['type'] is int: + var['ctypes_type'] = 'ctypes.c_int' + var['raw_type'] = 'int' + elif enum['type'] is str: + var['ctypes_type'] = 'ctypes.c_char_p' + var['raw_type'] = 'char*' + try: + if 'method' in var: var['enum'] = var['method']['path'] + '::' + enum['name'] + else: # class property + var['unresolved'] = True + except: + var['unresolved'] = True + + var['fundamental'] = True + + else: var['unresolved'] = True # TODO klass._public_xxx + + elif a in self.namespaces: # a::b can also be a nested namespace + if b in self.global_enums: + enum = self.global_enums[ b ] + trace_print(enum) + trace_print(var) + assert 0 + + elif b in self.global_enums: # falling back, this is a big ugly + enum = self.global_enums[ b ] + assert a in enum['namespace'].split('::') + if enum['type'] is int: + var['ctypes_type'] = 'ctypes.c_int' + var['raw_type'] = 'int' + elif enum['type'] is str: + var['ctypes_type'] = 'ctypes.c_char_p' + var['raw_type'] = 'char*' + var['fundamental'] = True + + else: # boost::gets::crazy + trace_print('NAMESPACES', self.namespaces) + trace_print( a, b ) + trace_print( '---- boost gets crazy ----' ) + var['ctypes_type'] = 'ctypes.c_void_p' + var['unresolved'] = True + + + elif 'namespace' in var and self.concrete_typedef(var['namespace']+tag): + #print( 'TRYING WITH NS', var['namespace'] ) + con = self.concrete_typedef( var['namespace']+tag ) + if con: + var['typedef'] = var['namespace']+tag + var['type'] = con + if 'struct' in con.split(): + var['raw_type'] = var['typedef'] + var['ctypes_type'] = 'ctypes.c_void_p' + else: + self.resolve_type( var['type'], var ) + var['ctypes_type'] = self.guess_ctypes_type( var['type'] ) + + elif '::' in var: + var['ctypes_type'] = 'ctypes.c_void_p' + var['unresolved'] = True + + elif tag in self.SubTypedefs: # TODO remove SubTypedefs + if 'property_of_class' in var or 'property_of_struct' in var: + trace_print( 'class:', self.SubTypedefs[ tag ], 'tag:', tag ) + var['typedef'] = self.SubTypedefs[ tag ] # class name + var['ctypes_type'] = 'ctypes.c_void_p' + else: + trace_print( "WARN-this should almost never happen!" ) + trace_print( var ); trace_print('-'*80) + var['unresolved'] = True + + elif tag in self._template_typenames: + var['typename'] = tag + var['ctypes_type'] = 'ctypes.c_void_p' + var['unresolved'] = True # TODO, how to deal with templates? + + elif tag.startswith('_'): # assume starting with underscore is not important for wrapping + warning_print( 'WARN unresolved %s'%_tag) + var['ctypes_type'] = 'ctypes.c_void_p' + var['unresolved'] = True + + else: + trace_print( 'WARN: unknown type', var ) + assert 'property_of_class' in var or 'property_of_struct' # only allow this case + var['unresolved'] = True + + + ## if not resolved and is a method param, not going to wrap these methods ## + if var['unresolved'] and 'method' in var: var['method']['unresolved_parameters'] = True + + + # create stripped raw_type # + p = '* & const static mutable'.split() # +++ new July7: "mutable" + for var in CppVariable.Vars: + if 'raw_type' not in var: + raw = [] + for x in var['type'].split(): + if x not in p: raw.append( x ) + var['raw_type'] = ' '.join( raw ) + + #if 'AutoConstantEntry' in var['raw_type']: print(var); assert 0 + if var['class']: + if '::' not in var['raw_type']: + if not var['class']['parent']: + var['raw_type'] = var['class']['namespace'] + '::' + var['raw_type'] + elif var['class']['parent'] in self.classes: + parent = self.classes[ var['class']['parent'] ] + var['raw_type'] = parent['namespace'] + '::' + var['class']['name'] + '::' + var['raw_type'] + else: + var['unresolved'] = True + + elif '::' in var['raw_type'] and var['raw_type'].split('::')[0] not in self.namespaces: + var['raw_type'] = var['class']['namespace'] + '::' + var['raw_type'] + else: + var['unresolved'] = True + + elif 'forward_declared' in var and 'namespace' in var: + if '::' not in var['raw_type']: + var['raw_type'] = var['namespace'] + var['raw_type'] + elif '::' in var['raw_type'] and var['raw_type'].split('::')[0] in self.namespaces: + pass + else: trace_print('-'*80); trace_print(var); raise NotImplemented + + + ## need full name space for classes in raw type ## + if var['raw_type'].startswith( '::' ): + #print(var) + #print('NAMESPACE', var['class']['namespace']) + #print( 'PARENT NS', var['class']['parent']['namespace'] ) + #assert 0 + var['unresolved'] = True + if 'method' in var: var['method']['unresolved_parameters'] = True + #var['raw_type'] = var['raw_type'][2:] + + # Take care of #defines and #pragmas etc + trace_print("Processing precomp_macro_buf: %s"%self._precomp_macro_buf) + for m in self._precomp_macro_buf: + macro = m.replace("\\n", "\n") + try: + if macro.lower().startswith("#define"): + trace_print("Adding #define %s"%macro) + self.defines.append(re.split("[\t ]+", macro, 1)[1].strip()) + elif macro.lower().startswith("#pragma"): + trace_print("Adding #pragma %s"%macro) + self.pragmas.append(re.split("[\t ]+", macro, 1)[1].strip()) + elif macro.lower().startswith("#include"): + trace_print("Adding #include %s"%macro) + self.includes.append(re.split("[\t ]+", macro, 1)[1].strip()) + else: + debug_print("Cant detect what to do with precomp macro '%s'"%macro) + except: pass + self._precomp_macro_buf = None + + + def concrete_typedef( self, key ): + if key not in self.typedefs: + #print( 'FAILED typedef', key ) + return None + while key in self.typedefs: + prev = key + key = self.typedefs[ key ] + if '<' in key or '>' in key: return prev # stop at template + if key.startswith('std::'): return key # stop at std lib + return key + + +class _CppHeader( Resolver ): + def finalize(self): + self.finalize_vars() + # finalize classes and method returns types + for cls in list(self.classes.values()): + for meth in cls.get_all_methods(): + if meth['pure_virtual']: cls['abstract'] = True + + if not meth['returns_fundamental'] and meth['returns'] in C99_NONSTANDARD: + meth['returns'] = C99_NONSTANDARD[meth['returns']] + meth['returns_fundamental'] = True + + elif not meth['returns_fundamental']: # describe the return type + con = None + if cls['namespace'] and '::' not in meth['returns']: + con = self.concrete_typedef( cls['namespace'] + '::' + meth['returns'] ) + else: con = self.concrete_typedef( meth['returns'] ) + + + if con: + meth['returns_concrete'] = con + meth['returns_fundamental'] = is_fundamental( con ) + + elif meth['returns'] in self.classes: + trace_print( 'meth returns class:', meth['returns'] ) + meth['returns_class'] = True + + elif meth['returns'] in self.SubTypedefs: + meth['returns_class'] = True + meth['returns_nested'] = self.SubTypedefs[ meth['returns'] ] + + elif meth['returns'] in cls._public_enums: + enum = cls._public_enums[ meth['returns'] ] + meth['returns_enum'] = enum['type'] + meth['returns_fundamental'] = True + if enum['type'] == int: meth['returns'] = 'int' + else: meth['returns'] = 'char*' + + elif meth['returns'] in self.global_enums: + enum = self.global_enums[ meth['returns'] ] + meth['returns_enum'] = enum['type'] + meth['returns_fundamental'] = True + if enum['type'] == int: meth['returns'] = 'int' + else: meth['returns'] = 'char*' + + elif meth['returns'].count('::')==1: + trace_print( meth ) + a,b = meth['returns'].split('::') + if a in self.namespaces: + if b in self.classes: + klass = self.classes[ b ] + meth['returns_class'] = a + '::' + b + elif '<' in b and '>' in b: + warning_print( 'WARN-can not return template: %s'%b ) + meth['returns_unknown'] = True + elif b in self.global_enums: + enum = self.global_enums[ b ] + meth['returns_enum'] = enum['type'] + meth['returns_fundamental'] = True + if enum['type'] == int: meth['returns'] = 'int' + else: meth['returns'] = 'char*' + + else: trace_print( a, b); trace_print( meth); meth['returns_unknown'] = True # +++ + + elif a in self.classes: + klass = self.classes[ a ] + if b in klass._public_enums: + trace_print( '...found nested enum', b ) + enum = klass._public_enums[ b ] + meth['returns_enum'] = enum['type'] + meth['returns_fundamental'] = True + if enum['type'] == int: meth['returns'] = 'int' + else: meth['returns'] = 'char*' + + elif b in klass._public_forward_declares: + meth['returns_class'] = True + + elif b in klass._public_typedefs: + typedef = klass._public_typedefs[ b ] + meth['returns_fundamental'] = is_fundamental( typedef ) + + else: + trace_print( meth ) # should be a nested class, TODO fix me. + meth['returns_unknown'] = True + + elif '::' in meth['returns']: + trace_print('TODO namespace or extra nested return:', meth) + meth['returns_unknown'] = True + else: + trace_print( 'WARN: UNKNOWN RETURN', meth['name'], meth['returns']) + meth['returns_unknown'] = True + + if meth["returns"].startswith(": : "): + meth["returns"] = meth["returns"].replace(": : ", "::") + + for cls in list(self.classes.values()): + methnames = cls.get_all_method_names() + pvm = cls.get_all_pure_virtual_methods() + + for d in cls['inherits']: + c = d['class'] + a = d['access'] # do not depend on this to be 'public' + trace_print( 'PARENT CLASS:', c ) + if c not in self.classes: trace_print('WARN: parent class not found') + if c in self.classes and self.classes[c]['abstract']: + p = self.classes[ c ] + for meth in p.get_all_methods(): #p["methods"]["public"]: + trace_print( '\t\tmeth', meth['name'], 'pure virtual', meth['pure_virtual'] ) + if meth['pure_virtual'] and meth['name'] not in methnames: cls['abstract'] = True; break + + + + + + def evaluate_struct_stack(self): + """Create a Struct out of the name stack (but not its parts)""" + #print( 'eval struct stack', self.nameStack ) + #if self.braceDepth != len(self.nameSpaces): return + struct = CppStruct(self.nameStack) + struct["namespace"] = self.cur_namespace() + self.structs[ struct['type'] ] = struct + self.structs_order.append( struct ) + if self.curClass: + struct['parent'] = self.curClass + klass = self.classes[ self.curClass ] + klass['structs'][self.curAccessSpecifier].append( struct ) + if self.curAccessSpecifier == 'public': klass._public_structs[ struct['type'] ] = struct + self.curStruct = struct + self._structs_brace_level[ struct['type'] ] = self.braceDepth + + + def parse_method_type( self, stack ): + trace_print( 'meth type info', stack ) + if stack[0] in ':;' and stack[1] != ':': stack = stack[1:] + info = { + 'debug': ' '.join(stack).replace(' : : ', '::' ).replace(' < ', '<' ).replace(' > ', '> ' ).replace(" >",">").replace(">>", "> >").replace(">>", "> >"), + 'class':None, + 'namespace':self.cur_namespace(add_double_colon=True), + } + + for tag in 'defined pure_virtual operator constructor destructor extern template virtual static explicit inline friend returns returns_pointer returns_fundamental returns_class'.split(): info[tag]=False + header = stack[ : stack.index('(') ] + header = ' '.join( header ) + header = header.replace(' : : ', '::' ) + header = header.replace(' < ', '<' ) + header = header.replace(' > ', '> ' ) + header = header.strip() + + if '{' in stack: + info['defined'] = True + self._method_body = self.braceDepth + 1 + trace_print( 'NEW METHOD WITH BODY', self.braceDepth ) + elif stack[-1] == ';': + info['defined'] = False + self._method_body = None # not a great idea to be clearing here + else: assert 0 + + if len(stack) > 3 and stack[-1] == ';' and stack[-2] == '0' and stack[-3] == '=': + info['pure_virtual'] = True + + r = header.split() + name = None + if 'operator' in stack: # rare case op overload defined outside of class + op = stack[ stack.index('operator')+1 : stack.index('(') ] + op = ''.join(op) + if not op: + if " ".join(['operator', '(', ')', '(']) in " ".join(stack): + op = "()" + else: + trace_print( 'Error parsing operator') + return None + + info['operator'] = op + name = 'operator' + op + a = stack[ : stack.index('operator') ] + + elif r: + name = r[-1] + a = r[ : -1 ] # strip name + + if name is None: return None + #if name.startswith('~'): name = name[1:] + + while a and a[0] == '}': # strip - can have multiple } } + a = a[1:] + + + if '::' in name: + #klass,name = name.split('::') # methods can be defined outside of class + klass = name[ : name.rindex('::') ] + name = name.split('::')[-1] + info['class'] = klass + if klass in self.classes and not self.curClass: + #Class function defined outside the class + return None + # info['name'] = name + #else: info['name'] = name + + if name.startswith('~'): + info['destructor'] = True + name = name[1:] + elif not a or (name == self.curClass and len(self.curClass)): + info['constructor'] = True + + info['name'] = name + + for tag in 'extern virtual static explicit inline friend'.split(): + if tag in a: info[ tag ] = True; a.remove( tag ) # inplace + if 'template' in a: + a.remove('template') + b = ' '.join( a ) + if '>' in b: + info['template'] = b[ : b.index('>')+1 ] + info['returns'] = b[ b.index('>')+1 : ] # find return type, could be incorrect... TODO + if '' + if typname not in self._template_typenames: self._template_typenames.append( typname ) + else: info['returns'] = ' '.join( a ) + else: info['returns'] = ' '.join( a ) + info['returns'] = info['returns'].replace(' <', '<').strip() + + ## be careful with templates, do not count pointers inside template + info['returns_pointer'] = info['returns'].split('>')[-1].count('*') + if info['returns_pointer']: info['returns'] = info['returns'].replace('*','').strip() + + info['returns_reference'] = '&' in info['returns'] + if info['returns']: info['returns'] = info['returns'].replace('&','').strip() + + a = [] + for b in info['returns'].split(): + if b == '__const__': info['returns_const'] = True + elif b == 'const': info['returns_const'] = True + else: a.append( b ) + info['returns'] = ' '.join( a ) + + info['returns_fundamental'] = is_fundamental( info['returns'] ) + return info + + def evaluate_method_stack(self): + """Create a method out of the name stack""" + + if self.curStruct: + trace_print( 'WARN - struct contains methods - skipping' ) + trace_print( self.stack ) + assert 0 + + info = self.parse_method_type( self.stack ) + if info: + if info[ 'class' ] and info['class'] in self.classes: # case where methods are defined outside of class + newMethod = CppMethod(self.nameStack, info['name'], info, self.curTemplate) + klass = self.classes[ info['class'] ] + klass[ 'methods' ][ 'public' ].append( newMethod ) + newMethod['parent'] = klass + if klass['namespace']: newMethod['path'] = klass['namespace'] + '::' + klass['name'] + else: newMethod['path'] = klass['name'] + + elif self.curClass: # normal case + newMethod = CppMethod(self.nameStack, self.curClass, info, self.curTemplate) + klass = self.classes[self.curClass] + klass['methods'][self.curAccessSpecifier].append(newMethod) + newMethod['parent'] = klass + if klass['namespace']: newMethod['path'] = klass['namespace'] + '::' + klass['name'] + else: newMethod['path'] = klass['name'] + else: #non class functions + debug_print("FREE FUNCTION") + newMethod = CppMethod(self.nameStack, None, info, self.curTemplate) + self.functions.append(newMethod) + global parseHistory + parseHistory.append({"braceDepth": self.braceDepth, "item_type": "method", "item": newMethod}) + else: + trace_print( 'free function?', self.nameStack ) + + self.stack = [] + + def _parse_typedef( self, stack, namespace='' ): + if not stack or 'typedef' not in stack: return + stack = list( stack ) # copy just to be safe + if stack[-1] == ';': stack.pop() + + while stack and stack[-1].isdigit(): stack.pop() # throw away array size for now + + idx = stack.index('typedef') + if stack[-1] == "]": + try: + name = namespace + "".join(stack[-4:]) + # Strip off the array part so the rest of the parsing is better + stack = stack[:-3] + except: + name = namespace + stack[-1] + else: + name = namespace + stack[-1] + s = '' + for a in stack[idx+1:-1]: + if a == '{': break + if not s or s[-1] in ':<>' or a in ':<>': s += a # keep compact + else: s += ' ' + a # spacing + + r = {'name':name, 'raw':s, 'type':s} + if not is_fundamental(s): + if 'struct' in s.split(): pass # TODO is this right? "struct ns::something" + elif '::' not in s: s = namespace + s # only add the current name space if no namespace given + r['type'] = s + if s: return r + + + def evaluate_typedef(self): + ns = self.cur_namespace(add_double_colon=True) + res = self._parse_typedef( self.stack, ns ) + if res: + name = res['name'] + self.typedefs[ name ] = res['type'] + if name not in self.typedefs_order: self.typedefs_order.append( name ) + + + def evaluate_property_stack(self): + """Create a Property out of the name stack""" + global parseHistory + assert self.stack[-1] == ';' + debug_print( "trace" ) + if self.nameStack[0] == 'typedef': + if self.curClass: + typedef = self._parse_typedef( self.stack ) + name = typedef['name'] + klass = self.classes[ self.curClass ] + klass[ 'typedefs' ][ self.curAccessSpecifier ].append( name ) + if self.curAccessSpecifier == 'public': klass._public_typedefs[ name ] = typedef['type'] + Resolver.SubTypedefs[ name ] = self.curClass + else: assert 0 + elif self.curStruct or self.curClass: + if len(self.nameStack) == 1: + #See if we can de anonymize the type + filteredParseHistory = [h for h in parseHistory if h["braceDepth"] == self.braceDepth] + if len(filteredParseHistory) and filteredParseHistory[-1]["item_type"] == "class": + self.nameStack.insert(0, filteredParseHistory[-1]["item"]["name"]) + debug_print("DEANONYMOIZING %s to type '%s'"%(self.nameStack[1], self.nameStack[0])) + if "," in self.nameStack: #Maybe we have a variable list + #Figure out what part is the variable separator but remember templates of function pointer + #First find left most comma outside of a > and ) + leftMostComma = 0; + for i in range(0, len(self.nameStack)): + name = self.nameStack[i] + if name in (">", ")"): leftMostComma = 0 + if leftMostComma == 0 and name == ",": leftMostComma = i + # Is it really a list of variables? + if leftMostComma != 0: + trace_print("Multiple variables for namestack in %s. Separating processing"%self.nameStack) + orig_nameStack = self.nameStack[:] + orig_stack = self.stack[:] + + type_nameStack = orig_nameStack[:leftMostComma-1] + for name in orig_nameStack[leftMostComma - 1::2]: + self.nameStack = type_nameStack + [name] + self.stack = orig_stack[:] # Not maintained for mucking, but this path it doesnt matter + self.evaluate_property_stack() + return + + newVar = CppVariable(self.nameStack) + newVar['namespace'] = self.current_namespace() + if self.curStruct: + self.curStruct[ 'fields' ].append( newVar ) + newVar['property_of_struct'] = self.curStruct + elif self.curClass: + klass = self.classes[self.curClass] + klass["properties"][self.curAccessSpecifier].append(newVar) + newVar['property_of_class'] = klass['name'] + parseHistory.append({"braceDepth": self.braceDepth, "item_type": "variable", "item": newVar}) + else: + debug_print( "Found Global variable" ) + newVar = CppVariable(self.nameStack) + self.variables.append(newVar) + + self.stack = [] # CLEAR STACK + + def evaluate_class_stack(self): + """Create a Class out of the name stack (but not its parts)""" + #dont support sub classes today + #print( 'eval class stack', self.nameStack ) + parent = self.curClass + if self.braceDepth > len( self.nameSpaces) and parent: + trace_print( 'HIT NESTED SUBCLASS' ) + self.accessSpecifierStack.append(self.curAccessSpecifier) + elif self.braceDepth != len(self.nameSpaces): + error_print( 'ERROR: WRONG BRACE DEPTH' ) + return + + # When dealing with typedefed structs, get rid of typedef keyword to handle later on + if self.nameStack[0] == "typedef": + del self.nameStack[0] + if len(self.nameStack) == 1: + self.anon_struct_counter += 1 + # We cant handle more than 1 anonymous struct, so name them uniquely + self.nameStack.append(""%self.anon_struct_counter) + + if self.nameStack[0] == "class": + self.curAccessSpecifier = 'private' + else:#struct + self.curAccessSpecifier = 'public' + debug_print("curAccessSpecifier changed/defaulted to %s"%self.curAccessSpecifier) + if self.nameStack[0] == "union": + newClass = CppUnion(self.nameStack) + if newClass['name'] == 'union ': + self.anon_union_counter = [self.braceDepth, 2] + else: + self.anon_union_counter = [self.braceDepth, 1] + trace_print( 'NEW UNION', newClass['name'] ) + else: + newClass = CppClass(self.nameStack, self.curTemplate) + trace_print( 'NEW CLASS', newClass['name'] ) + newClass["declaration_method"] = self.nameStack[0] + self.classes_order.append( newClass ) # good idea to save ordering + self.stack = [] # fixes if class declared with ';' in closing brace + if parent: + newClass["namespace"] = self.classes[ parent ]['namespace'] + '::' + parent + newClass['parent'] = parent + self.classes[ parent ]['nested_classes'].append( newClass ) + ## supports nested classes with the same name ## + self.curClass = key = parent+'::'+newClass['name'] + self._classes_brace_level[ key ] = self.braceDepth + + elif newClass['parent']: # nested class defined outside of parent. A::B {...} + parent = newClass['parent'] + newClass["namespace"] = self.classes[ parent ]['namespace'] + '::' + parent + self.classes[ parent ]['nested_classes'].append( newClass ) + ## supports nested classes with the same name ## + self.curClass = key = parent+'::'+newClass['name'] + self._classes_brace_level[ key ] = self.braceDepth + + else: + newClass["namespace"] = self.cur_namespace() + key = newClass['name'] + self.curClass = newClass["name"] + self._classes_brace_level[ newClass['name'] ] = self.braceDepth + + if not key.endswith("::") and not key.endswith(" ") and len(key) != 0: + if key in self.classes: + trace_print( 'ERROR name collision:', key ) + self.classes[key].show() + trace_print('-'*80) + newClass.show() + assert key not in self.classes # namespace collision + self.classes[ key ] = newClass + global parseHistory + parseHistory.append({"braceDepth": self.braceDepth, "item_type": "class", "item": newClass}) + + + def evalute_forward_decl(self): + trace_print( 'FORWARD DECL', self.nameStack ) + assert self.nameStack[0] in ('class', 'struct') + name = self.nameStack[-1] + if self.curClass: + klass = self.classes[ self.curClass ] + klass['forward_declares'][self.curAccessSpecifier].append( name ) + if self.curAccessSpecifier == 'public': klass._public_forward_declares.append( name ) + else: self._forward_decls.append( name ) + +class CppHeader( _CppHeader ): + """Parsed C++ class header + + Variables produced: + self.classes - Dictionary of classes found in a given header file where the + key is the name of the class + """ + IGNORE_NAMES = '__extension__'.split() + + def show(self): + for className in list(self.classes.keys()):self.classes[className].show() + + def __init__(self, headerFileName, argType="file", **kwargs): + """Create the parsed C++ header file parse tree + + headerFileName - Name of the file to parse OR actual file contents (depends on argType) + argType - Indicates how to interpret headerFileName as a file string or file name + kwargs - Supports the following keywords + """ + ## reset global state ## + global doxygenCommentCache + doxygenCommentCache = "" + CppVariable.Vars = [] + CppStruct.Structs = [] + + if (argType == "file"): + self.headerFileName = os.path.expandvars(headerFileName) + self.mainClass = os.path.split(self.headerFileName)[1][:-2] + headerFileStr = "" + elif argType == "string": + self.headerFileName = "" + self.mainClass = "???" + headerFileStr = headerFileName + else: + raise Exception("Arg type must be either file or string") + self.curClass = "" + + # nested classes have parent::nested, but no extra namespace, + # this keeps the API compatible, TODO proper namespace for everything. + Resolver.CLASSES = {} + self.classes = Resolver.CLASSES + #Functions that are not part of a class + self.functions = [] + + self.pragmas = [] + self.defines = [] + self.includes = [] + self._precomp_macro_buf = [] #for internal purposes, will end up filling out pragmras and defines at the end + + self.enums = [] + self.variables = [] + self.global_enums = {} + self.nameStack = [] + self.nameSpaces = [] + self.curAccessSpecifier = 'private' # private is default + self.curTemplate = None + self.accessSpecifierStack = [] + self.accessSpecifierScratch = [] + debug_print("curAccessSpecifier changed/defaulted to %s"%self.curAccessSpecifier) + self.initextra() + # Old namestacks for a given level + self.nameStackHistory = [] + self.anon_struct_counter = 0 + self.anon_union_counter = [-1, 0] + self.templateRegistry = [] + + if (len(self.headerFileName)): + fd = open(self.headerFileName) + headerFileStr = "".join(fd.readlines()) + fd.close() + + # Make sure supportedAccessSpecifier are sane + for i in range(0, len(supportedAccessSpecifier)): + if " " not in supportedAccessSpecifier[i]: continue + supportedAccessSpecifier[i] = re.sub("[ ]+", " ", supportedAccessSpecifier[i]).strip() + + # Strip out template declarations + templateSectionsToSliceOut = [] + try: + for m in re.finditer("template[\t ]*<[^>]*>", headerFileStr): + start = m.start() + # Search for the final '>' which may or may not be caught in the case of nexted <>'s + for i in range(start, len(headerFileStr)): + if headerFileStr[i] == '<': + firstBracket = i + break + ltgtStackCount = 1 + #Now look for fianl '>' + for i in range(firstBracket + 1, len(headerFileStr)): + if headerFileStr[i] == '<': + ltgtStackCount += 1 + elif headerFileStr[i] == '>': + ltgtStackCount -= 1 + if ltgtStackCount == 0: + end = i + break + templateSectionsToSliceOut.append((start, end)) + + # Now strip out all instances of the template + templateSectionsToSliceOut.reverse() + for tslice in templateSectionsToSliceOut: + # Replace the template symbol with a single symbol + template_symbol="CppHeaderParser_template_%d"%len(self.templateRegistry) + self.templateRegistry.append(headerFileStr[tslice[0]: tslice[1]+1]) + newlines = headerFileStr[tslice[0]: tslice[1]].count("\n") * "\n" #Keep line numbers the same + headerFileStr = headerFileStr[:tslice[0]] + newlines + " " + template_symbol + " " + headerFileStr[tslice[1] + 1:] + except: + pass + + # Change multi line #defines and expressions to single lines maintaining line nubmers + # Based from http://stackoverflow.com/questions/2424458/regular-expression-to-match-cs-multiline-preprocessor-statements + matches = re.findall(r'(?m)^(?:.*\\\r?\n)+.*$', headerFileStr) + is_define = re.compile(r'[ \t\v]*#[Dd][Ee][Ff][Ii][Nn][Ee]') + for m in matches: + #Keep the newlines so that linecount doesnt break + num_newlines = len([a for a in m if a=="\n"]) + if is_define.match(m): + new_m = m.replace("\n", "\\n") + else: + # Just expression taking up multiple lines, make it take 1 line for easier parsing + new_m = m.replace("\\\n", " ") + if (num_newlines > 0): + new_m += "\n"*(num_newlines) + headerFileStr = headerFileStr.replace(m, new_m) + + #Filter out Extern "C" statements. These are order dependent + matches = re.findall(re.compile(r'extern[\t ]+"[Cc]"[\t \n\r]*{', re.DOTALL), headerFileStr) + for m in matches: + #Keep the newlines so that linecount doesnt break + num_newlines = len([a for a in m if a=="\n"]) + headerFileStr = headerFileStr.replace(m, "\n" * num_newlines) + headerFileStr = re.sub(r'extern[ ]+"[Cc]"[ ]*', "", headerFileStr) + + #Filter out any ignore symbols that end with "()" to account for #define magic functions + for ignore in ignoreSymbols: + if not ignore.endswith("()"): continue + while True: + locStart = headerFileStr.find(ignore[:-1]) + if locStart == -1: + break; + locEnd = None + #Now walk till we find the last paren and account for sub parens + parenCount = 1 + inQuotes = False + for i in range(locStart + len(ignore) - 1, len(headerFileStr)): + c = headerFileStr[i] + if not inQuotes: + if c == "(": + parenCount += 1 + elif c == ")": + parenCount -= 1 + elif c == '"': + inQuotes = True + if parenCount == 0: + locEnd = i + 1 + break; + else: + if c == '"' and headerFileStr[i-1] != '\\': + inQuotes = False + + if locEnd: + #Strip it out but keep the linecount the same so line numbers are right + match_str = headerFileStr[locStart:locEnd] + debug_print("Striping out '%s'"%match_str) + num_newlines = len([a for a in match_str if a=="\n"]) + headerFileStr = headerFileStr.replace(headerFileStr[locStart:locEnd], "\n"*num_newlines) + + self.braceDepth = 0 + lex.lex() + lex.input(headerFileStr) + global curLine + global curChar + curLine = 0 + curChar = 0 + try: + while True: + tok = lex.token() + if not tok: break + if self.anon_union_counter[0] == self.braceDepth and self.anon_union_counter[1]: + self.anon_union_counter[1] -= 1 + tok.value = TagStr(tok.value, lineno=tok.lineno) + #debug_print("TOK: %s"%tok) + if tok.type == 'NAME' and tok.value in self.IGNORE_NAMES: continue + if tok.type != 'TEMPLATE_NAME': + self.stack.append( tok.value ) + curLine = tok.lineno + curChar = tok.lexpos + if (tok.type in ('PRECOMP_MACRO', 'PRECOMP_MACRO_CONT')): + debug_print("PRECOMP: %s"%tok) + self._precomp_macro_buf.append(tok.value) + self.stack = [] + self.nameStack = [] + continue + if tok.type == 'TEMPLATE_NAME': + try: + templateId = int(tok.value.replace("CppHeaderParser_template_","")) + self.curTemplate = self.templateRegistry[templateId] + except: pass + if (tok.type == 'OPEN_BRACE'): + if len(self.nameStack) >= 2 and is_namespace(self.nameStack): # namespace {} with no name used in boost, this sets default? + if self.nameStack[1] == "__IGNORED_NAMESPACE__CppHeaderParser__":#Used in filtering extern "C" + self.nameStack[1] = "" + self.nameSpaces.append(self.nameStack[1]) + ns = self.cur_namespace(); self.stack = [] + if ns not in self.namespaces: self.namespaces.append( ns ) + # Detect special condition of macro magic before class declaration so we + # can filter it out + if 'class' in self.nameStack and self.nameStack[0] != 'class' and self.nameStack[0] != 'enum': + classLocationNS = self.nameStack.index("class") + classLocationS = self.stack.index("class") + if "(" not in self.nameStack[classLocationNS:]: + debug_print("keyword 'class' found in unexpected location in nameStack, must be following #define magic. Process that before moving on") + origNameStack = self.nameStack + origStack = self.stack + #Process first part of stack which is probably #define macro magic and may cause issues + self.nameStack = self.nameStack[:classLocationNS] + self.stack = self.stack[:classLocationS] + try: + self.evaluate_stack() + except: + debug_print("Error processing #define magic... Oh well") + #Process rest of stack + self.nameStack = origNameStack[classLocationNS:] + self.stack = origStack[classLocationS:] + + + if len(self.nameStack) and not is_enum_namestack(self.nameStack): + self.evaluate_stack() + else: + self.nameStack.append(tok.value) + if self.stack and self.stack[0] == 'class': self.stack = [] + self.braceDepth += 1 + + elif (tok.type == 'CLOSE_BRACE'): + if self.braceDepth == 0: + continue + if (self.braceDepth == len(self.nameSpaces)): + tmp = self.nameSpaces.pop() + self.stack = [] # clear stack when namespace ends? + if len(self.nameStack) and is_enum_namestack(self.nameStack): + self.nameStack.append(tok.value) + elif self.braceDepth < 10: + self.evaluate_stack() + else: + self.nameStack = [] + self.braceDepth -= 1 + #self.stack = []; print 'BRACE DEPTH', self.braceDepth, 'NS', len(self.nameSpaces) + if self.curClass: debug_print( 'CURBD %s'%self._classes_brace_level[ self.curClass ] ) + + if (self.braceDepth == 0) or (self.curClass and self._classes_brace_level[self.curClass]==self.braceDepth): + trace_print( 'END OF CLASS DEF' ) + if self.accessSpecifierStack: + self.curAccessSpecifier = self.accessSpecifierStack[-1] + self.accessSpecifierStack = self.accessSpecifierStack[:-1] + if self.curClass and self.classes[ self.curClass ]['parent']: self.curClass = self.classes[ self.curClass ]['parent'] + else: self.curClass = ""; #self.curStruct = None + self.stack = [] + + #if self.curStruct: self.curStruct = None + if self.braceDepth == 0 or (self.curStruct and self._structs_brace_level[self.curStruct['type']]==self.braceDepth): + trace_print( 'END OF STRUCT DEF' ) + self.curStruct = None + + if self._method_body and (self.braceDepth + 1) <= self._method_body: + self._method_body = None; self.stack = []; self.nameStack = []; trace_print( 'FORCE CLEAR METHBODY' ) + + if (tok.type == 'OPEN_PAREN'): + self.nameStack.append(tok.value) + elif (tok.type == 'CLOSE_PAREN'): + self.nameStack.append(tok.value) + elif (tok.type == 'OPEN_SQUARE_BRACKET'): + self.nameStack.append(tok.value) + elif (tok.type == 'CLOSE_SQUARE_BRACKET'): + self.nameStack.append(tok.value) + elif (tok.type == 'TAB'): pass + elif (tok.type == 'EQUALS'): + self.nameStack.append(tok.value) + elif (tok.type == 'COMMA'): + self.nameStack.append(tok.value) + elif (tok.type == 'BACKSLASH'): + self.nameStack.append(tok.value) + elif (tok.type == 'DIVIDE'): + self.nameStack.append(tok.value) + elif (tok.type == 'PIPE'): + self.nameStack.append(tok.value) + elif (tok.type == 'PERCENT'): + self.nameStack.append(tok.value) + elif (tok.type == 'CARET'): + self.nameStack.append(tok.value) + elif (tok.type == 'EXCLAMATION'): + self.nameStack.append(tok.value) + elif (tok.type == 'SQUOTE'): pass + elif (tok.type == 'NUMBER' or tok.type == 'FLOAT_NUMBER'): + self.nameStack.append(tok.value) + elif (tok.type == 'MINUS'): + self.nameStack.append(tok.value) + elif (tok.type == 'PLUS'): + self.nameStack.append(tok.value) + elif (tok.type == 'STRING_LITERAL'): + self.nameStack.append(tok.value) + elif (tok.type == 'NAME' or tok.type == 'AMPERSTAND' or tok.type == 'ASTERISK' or tok.type == 'CHAR_LITERAL'): + if tok.value in ignoreSymbols: + debug_print("Ignore symbol %s"%tok.value) + elif (tok.value == 'class'): + self.nameStack.append(tok.value) + elif tok.value in supportedAccessSpecifier: + if len(self.nameStack) and self.nameStack[0] in ("class", "struct", "union"): + self.nameStack.append(tok.value) + elif self.braceDepth == len(self.nameSpaces) + 1 or self.braceDepth == (len(self.nameSpaces) + len(self.curClass.split("::"))): + self.curAccessSpecifier = tok.value; + self.accessSpecifierScratch.append(tok.value) + debug_print("curAccessSpecifier updated to %s"%self.curAccessSpecifier) + self.stack = [] + else: + self.nameStack.append(tok.value) + if self.anon_union_counter[0] == self.braceDepth: + self.anon_union_counter = [-1, 0] + elif (tok.type == 'COLON'): + #Dont want colon to be first in stack + if len(self.nameStack) == 0: + self.accessSpecifierScratch = [] + continue + + # Handle situation where access specifiers can be multi words such as "public slots" + jns = " ".join(self.accessSpecifierScratch + self.nameStack) + if jns in supportedAccessSpecifier: + self.curAccessSpecifier = jns; + debug_print("curAccessSpecifier updated to %s"%self.curAccessSpecifier) + self.stack = [] + self.nameStack = [] + else: + self.nameStack.append(tok.value) + self.accessSpecifierScratch = [] + + elif (tok.type == 'SEMI_COLON'): + if self.anon_union_counter[0] == self.braceDepth and self.anon_union_counter[1]: + debug_print("Creating anonymous union") + #Force the processing of an anonymous union + saved_namestack = self.nameStack[:] + saved_stack = self.stack[:] + self.nameStack = [""] + self.stack = self.nameStack + [";"] + self.nameStack = self.nameStack[0:1] + debug_print("pre eval anon stack") + self.evaluate_stack( tok.type ) + debug_print("post eval anon stack") + self.nameStack = saved_namestack + self.stack = saved_stack + self.anon_union_counter = [-1, 0]; + + + if (self.braceDepth < 10): self.evaluate_stack( tok.type ) + self.stack = [] + self.nameStack = [] + + except: + if (debug): raise + raise CppParseError("Not able to parse %s on line %d evaluating \"%s\"\nError around: %s" + % (self.headerFileName, tok.lineno, tok.value, " ".join(self.nameStack))) + + self.finalize() + global parseHistory + parseHistory = [] + # Delete some temporary variables + for key in ["_precomp_macro_buf", "nameStack", "nameSpaces", "curAccessSpecifier", "accessSpecifierStack", + "accessSpecifierScratch", "nameStackHistory", "anon_struct_counter", "anon_union_counter", + "_classes_brace_level", "_forward_decls", "stack", "mainClass", "curStruct", "_template_typenames", + "_method_body", "braceDepth", "_structs_brace_level", "typedefs_order", "curTemplate", "templateRegistry"]: + del self.__dict__[key] + + + def evaluate_stack(self, token=None): + """Evaluates the current name stack""" + global doxygenCommentCache + + self.nameStack = filter_out_attribute_keyword(self.nameStack) + self.stack = filter_out_attribute_keyword(self.stack) + nameStackCopy = self.nameStack[:] + + debug_print( "Evaluating stack %s\n BraceDepth: %s (called from %d)" %(self.nameStack,self.braceDepth, inspect.currentframe().f_back.f_lineno)) + + #Handle special case of overloading operator () + if "operator()(" in "".join(self.nameStack): + operator_index = self.nameStack.index("operator") + self.nameStack.pop(operator_index + 2) + self.nameStack.pop(operator_index + 1) + self.nameStack[operator_index] = "operator()" + + if (len(self.curClass)): + debug_print( "%s (%s) "%(self.curClass, self.curAccessSpecifier)) + else: + debug_print( " (%s) "%self.curAccessSpecifier) + + #Filter special case of array with casting in it + try: + bracePos = self.nameStack.index("[") + parenPos = self.nameStack.index("(") + if bracePos == parenPos - 1: + endParen = self.nameStack.index(")") + self.nameStack = self.nameStack[:bracePos + 1] + self.nameStack[endParen + 1:] + debug_print("Filtered namestack to=%s"%self.nameStack) + except: pass + + #if 'typedef' in self.nameStack: self.evaluate_typedef() # allows nested typedefs, probably a bad idea + if (not self.curClass and 'typedef' in self.nameStack and + (('struct' not in self.nameStack and 'union' not in self.nameStack) or self.stack[-1] == ";") and + not is_enum_namestack(self.nameStack)): + trace_print('STACK', self.stack) + self.evaluate_typedef() + return + + elif (len(self.nameStack) == 0): + debug_print( "trace" ) + debug_print( "(Empty Stack)" ) + return + elif (self.nameStack[0] == "namespace"): + #Taken care of outside of here + pass + elif len(self.nameStack) == 2 and self.nameStack[0] == "friend":#friend class declaration + pass + elif len(self.nameStack) >= 2 and self.nameStack[0] == 'using' and self.nameStack[1] == 'namespace': pass # TODO + + elif is_enum_namestack(self.nameStack): + debug_print( "trace" ) + self.evaluate_enum_stack() + + elif self._method_body and (self.braceDepth + 1) > self._method_body: trace_print( 'INSIDE METHOD DEF' ) + elif is_method_namestack(self.stack) and not self.curStruct and '(' in self.nameStack: + debug_print( "trace" ) + if self.braceDepth > 0: + if "{" in self.stack and self.stack[0] != '{' and self.stack[-1] == ';' and self.braceDepth == 1: + #Special case of a method defined outside a class that has a body + pass + else: + self.evaluate_method_stack() + else: + #Free function + self.evaluate_method_stack() + elif (len(self.nameStack) == 1 and len(self.nameStackHistory) > self.braceDepth + and (self.nameStackHistory[self.braceDepth][0][0:2] == ["typedef", "struct"] or + self.nameStackHistory[self.braceDepth][0][0:2] == ["typedef", "union"])): + # Look for the name of a typedef struct: struct typedef {...] StructName; or unions to get renamed + debug_print("found the naming of a union") + type_name_to_rename = self.nameStackHistory[self.braceDepth][1] + new_name = self.nameStack[0] + type_to_rename = self.classes[type_name_to_rename] + type_to_rename["name"] = self.nameStack[0] + #Now re install it in its new location + self.classes[new_name] = type_to_rename + if new_name != type_name_to_rename: + del self.classes[type_name_to_rename] + elif is_property_namestack(self.nameStack) and self.stack[-1] == ';': + debug_print( "trace" ) + if self.nameStack[0] in ('class', 'struct') and len(self.stack) == 3: self.evalute_forward_decl() + elif len(self.nameStack) >= 2 and (self.nameStack[0]=='friend' and self.nameStack[1]=='class'): pass + else: self.evaluate_property_stack() # catches class props and structs in a namespace + + elif self.nameStack[0] in ("class", "struct", "union") or self.nameStack[0] == 'typedef' and self.nameStack[1] in ('struct', 'union'): + #Parsing a union can reuse much of the class parsing + debug_print( "trace" ) + self.evaluate_class_stack() + + elif not self.curClass: + debug_print( "trace" ) + if is_enum_namestack(self.nameStack): self.evaluate_enum_stack() + elif self.curStruct and self.stack[-1] == ';': self.evaluate_property_stack() # this catches fields of global structs + self.nameStack = [] + doxygenCommentCache = "" + elif (self.braceDepth < 1): + debug_print( "trace" ) + #Ignore global stuff for now + debug_print( "Global stuff: %s"%self.nameStack ) + self.nameStack = [] + doxygenCommentCache = "" + elif (self.braceDepth > len(self.nameSpaces) + 1): + debug_print( "trace" ) + self.nameStack = [] + doxygenCommentCache = "" + + try: + self.nameStackHistory[self.braceDepth] = (nameStackCopy, self.curClass) + except: + self.nameStackHistory.append((nameStackCopy, self.curClass)) + self.nameStack = [] # its a little confusing to have some if/else above return and others not, and then clearning the nameStack down here + doxygenCommentCache = "" + self.curTemplate = None + + + def evaluate_enum_stack(self): + """Create an Enum out of the name stack""" + debug_print( "evaluating enum" ) + newEnum = CppEnum(self.nameStack) + if len(list(newEnum.keys())): + if len(self.curClass): + newEnum["namespace"] = self.cur_namespace(False) + klass = self.classes[self.curClass] + klass["enums"][self.curAccessSpecifier].append(newEnum) + if self.curAccessSpecifier == 'public' and 'name' in newEnum: klass._public_enums[ newEnum['name'] ] = newEnum + else: + newEnum["namespace"] = self.cur_namespace(True) + self.enums.append(newEnum) + if 'name' in newEnum and newEnum['name']: self.global_enums[ newEnum['name'] ] = newEnum + + #This enum has instances, turn them into properties + if "instances" in newEnum: + instanceType = "enum" + if "name" in newEnum: + instanceType = newEnum["name"] + for instance in newEnum["instances"]: + self.nameStack = [instanceType, instance] + self.evaluate_property_stack() + del newEnum["instances"] + + def strip_parent_keys(self): + """Strip all parent (and method) keys to prevent loops""" + obj_queue = [self] + while len(obj_queue): + obj = obj_queue.pop() + trace_print("pop %s type %s"%(obj, type(obj))) + try: + if "parent" in obj.keys(): + del obj["parent"] + trace_print("Stripped parent from %s"%obj.keys()) + except: pass + try: + if "method" in obj.keys(): + del obj["method"] + trace_print("Stripped method from %s"%obj.keys()) + except: pass + # Figure out what sub types are one of ours + try: + if not hasattr(obj, 'keys'): + obj = obj.__dict__ + for k in obj.keys(): + trace_print("-Try key %s"%(k)) + trace_print("-type %s"%(type(obj[k]))) + if k in ["nameStackHistory", "parent", "_public_typedefs"]: continue + if type(obj[k]) == list: + for i in obj[k]: + trace_print("push l %s"%i) + obj_queue.append(i) + elif type(obj[k]) == dict: + if len(obj): + trace_print("push d %s"%obj[k]) + obj_queue.append(obj[k]) + elif type(obj[k]) == type(type(0)): + if type(obj[k]) == int: + obj[k] = "int" + elif type(obj[k]) == str: + obj[k] = "string" + else: + obj[k] = "???" + trace_print("next key\n") + except: + trace_print("Exception") + + def toJSON(self, indent=4): + """Converts a parsed structure to JSON""" + import json + self.strip_parent_keys() + try: + del self.__dict__["classes_order"] + except: pass + return json.dumps(self.__dict__, indent=indent) + + + def __repr__(self): + rtn = { + "classes": self.classes, + "functions": self.functions, + "enums": self.enums, + "variables": self.variables, + } + return repr(rtn) + + def __str__(self): + rtn = "" + for className in list(self.classes.keys()): + rtn += "%s\n"%self.classes[className] + if self.functions: + rtn += "// functions\n" + for f in self.functions: + rtn += "%s\n"%f + if self.variables: + rtn += "// variables\n" + for f in self.variables: + rtn += "%s\n"%f + if self.enums: + rtn += "// enums\n" + for f in self.enums: + rtn += "%s\n"%f + return rtn diff --git a/tools/cppheaderparser/__init__.py b/tools/cppheaderparser/__init__.py new file mode 100644 index 0000000..024da04 --- /dev/null +++ b/tools/cppheaderparser/__init__.py @@ -0,0 +1,6 @@ +# CppHeaderParser package +# Author: Jashua Cloutier (contact via sourceforge username:senexcanis) + +from .CppHeaderParser import * + +#__all__ = ['CppHeaderParser'] diff --git a/tools/process_headers.py b/tools/process_headers.py new file mode 100644 index 0000000..70f89de --- /dev/null +++ b/tools/process_headers.py @@ -0,0 +1,218 @@ +import cppheaderparser +from pprint import pprint +import datetime +import re +import os + +symbol_list = [] +wrapper_name_counter = {} + +out_file = None + +def output(text): + print(text) + if out_file is not None: + out_file.write(text) + out_file.write("\n") + +def get_method_path(method): + method_path = method["path"] + if method_path.startswith("::"): + method_path = method_path[2:] + return method_path + +def get_method_wrapper_name(method_path, method_name): + name = "_" + method_path.replace("::", "_") + "_" + method_name + if name in wrapper_name_counter: + wrapper_name_counter[name] += 1 + name = name + str(wrapper_name_counter[name]) + else: + wrapper_name_counter[name] = 1 + return name + +def get_mangled_class_name(class_name): + sp = class_name.split("::") + ret = "" + for p in sp: + ret += str(len(p)) + p + return ret + +PRIMITIVE_TYPES = { + "char": "c", + "signed char": "c", + "unsigned char": "h", + "short": "s", + "signed short": "s", + "unsigned short": "t", + "int": "i", + "signed int": "i", + "unsigned int": "j", + "long": "l", + "signed long": "l", + "unsigned long": "m", + "long long": "x", + "unsigned long long": "y", + "bool": "b", + "float": "f", + "double": "d", +} + +def expand_cpp_default_templates(type_name): + ret = re.sub(r"(std::unique_ptr\s*)<([\w:]*)>", r"\1<\2,std::default_delete<\2>>", type_name) + return ret + +def get_mangled_type_name(type_name, substitutions): + type_name = expand_cpp_default_templates(type_name) + print(type_name) + + sp = re.findall(r"((unsigned\s*|signed\s*|long\s*|short\s*|[\w:]+)+|[*&<>,])", type_name) + ret = [] + last_type_start = [] + last_type_start.append(0) + for p in sp: + if type(p) is tuple: + p = p[0] + if p == "<": + ret.append("I") + last_type_start.append(len(ret)) + elif p == ">": + ret.append("E") + last_type_start.pop() + elif p == ",": + last_type_start[-1] = len(ret) + elif p == "const": + ret.insert(last_type_start[-1], "K") + elif p == "&" and ret[last_type_start[-1]] == "R": + ret[last_type_start[-1]] = "O" + elif p == "&": + ret.insert(last_type_start[-1], "R") + elif p == "*": + ret.insert(last_type_start[-1], "P") + else: + if p in PRIMITIVE_TYPES: + ret.append(PRIMITIVE_TYPES[p]) + continue + if p in substitutions: + subId = substitutions.index(p) + if subId > 0: + ret.append("S" + str(subId - 1) + "_") + else: + ret.append("S_") + continue + np = p.split("::") + if (np[0] == "std" or np[0] == "mcpe") and np[1] == "string": + ret.append("Ss") + continue + substitutions.append(p) + f = True + for pp in np: + if f: + f = False + if pp == "std": + ret.append("St") + continue + ret.append(str(len(pp)) + pp) + return ''.join(ret) + +def get_mangled_method(method): + ret = "_ZN" + if method["const"]: + ret += "K" + ret += get_mangled_type_name(get_method_path(method), []) + if method["constructor"]: + ret += "C2" + else: + ret += str(len(method["name"])) + method["name"] + ret += "E" + if len(method["parameters"]) == 0: + ret += "v" + else: + substitutions = [] + substitutions.append(get_method_path(method)) + for param in method["parameters"]: + ret += get_mangled_type_name(param["type"], substitutions) + return ret + +def process_header(file): + print("Processing file " + file) + cpp_header = cppheaderparser.CppHeader(file) + + for class_name in cpp_header.classes: + print("Processing class " + class_name) + class_data = cpp_header.classes[class_name] + # pprint(class_data) + for method_vis in class_data["methods"]: + for method in class_data["methods"][method_vis]: + if method["defined"] or method["pure_virtual"]: + continue + + method_path = get_method_path(method) + wrapper_name = get_method_wrapper_name(method_path, method["name"]) + mangled_name = get_mangled_method(method) + + params_str = "" + params_with_names = "" + params_for_call = "" + param_no = 1 + #if not method["static"]: + # params_str = method_path + "*" + # if method["const"]: + # params_str = method_path + " const*" + # params_for_call = "this" + for param in method["parameters"]: + if len(params_str) > 0: + params_str += ", " + params_for_call += ", " + if len(params_with_names) > 0: + params_with_names += ", " + params_str += param["type"] + params_with_names += param["type"] + " p" + str(param_no) + if param["type"].startswith("std::unique_ptr"): + params_for_call += "std::move(p" + str(param_no) + ")" + else: + params_for_call += "p" + str(param_no) + param_no += 1 + ret_type = method["rtnType"] + if ret_type.startswith("static "): + ret_type = ret_type[len("static "):] + if method["static"]: + output("static " + ret_type + " (*" + wrapper_name + ")(" + params_str + ");"); + else: + output("static " + ret_type + " (" + method_path + "::*" + wrapper_name + ")(" + params_str + ")" + (" const" if method["const"] else "") + ";"); + output((ret_type + " " if not method["constructor"] else "") + method_path + "::" + method["name"] + "(" + params_with_names + ")" + (" const" if method["const"] else "") + " {"); + has_return = ret_type != "void" and ret_type != "" + if method["static"]: + output(" " + ("return " if has_return else "") + wrapper_name + "(" + params_for_call + ");"); + else: + output(" " + ("return " if has_return else "") + "(this->*" + wrapper_name + ")(" + params_for_call + ");"); + output("}"); + symbol_list.append({ + "name": wrapper_name, + "symbol": mangled_name + }) + +def generate_init_func(): + output("void minecraft_symbols_init(void* handle) {"); + for symbol in symbol_list: + output(" ((void*&) " + symbol["name"] + ") = hybris_dlsym(handle, \"" + symbol["symbol"] + "\");") + output("}") + +out_file = open("../src/minecraft/symbols.cpp", "w") +output("// This file was automatically generated using tools/process_headers.py") +output("// Generated on " + datetime.datetime.utcnow().strftime("%a %b %d %Y %H:%M:%S UTC")) +output("") +output("#include ") +output("") +header_dir = "../src/minecraft/" +for file in os.listdir(header_dir): + file_path = os.path.join(header_dir, file) + if not os.path.isfile(file_path) or not file.endswith(".h"): + continue + if file == "symbols.h" or file == "string.h": + continue + output("#include \"" + file + "\""); + process_header(file_path); + output("") +generate_init_func() +out_file.close() +