/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Random portability stuff See comments in porting.h */ #include "porting.h" #if defined(__FreeBSD__) #include #include #elif defined(_WIN32) #include #include #include #endif #if !defined(_WIN32) #include #include #endif #if defined(__hpux) #define _PSTAT64 #include #endif #if !defined(_WIN32) && !defined(__APPLE__) && \ !defined(__ANDROID__) && !defined(SERVER) #define XORG_USED #endif #ifdef XORG_USED #include #include #endif #include "config.h" #include "debug.h" #include "filesys.h" #include "log.h" #include "util/string.h" #include "settings.h" #include namespace porting { /* Signal handler (grabs Ctrl-C on POSIX systems) */ bool g_killed = false; bool * signal_handler_killstatus(void) { return &g_killed; } #if !defined(_WIN32) // POSIX #include void signal_handler(int sig) { if (!g_killed) { if (sig == SIGINT) { dstream << "INFO: signal_handler(): " << "Ctrl-C pressed, shutting down." << std::endl; } else if (sig == SIGTERM) { dstream << "INFO: signal_handler(): " << "got SIGTERM, shutting down." << std::endl; } // Comment out for less clutter when testing scripts /*dstream << "INFO: sigint_handler(): " << "Printing debug stacks" << std::endl; debug_stacks_print();*/ g_killed = true; } else { (void)signal(sig, SIG_DFL); } } void signal_handler_init(void) { (void)signal(SIGINT, signal_handler); (void)signal(SIGTERM, signal_handler); } #else // _WIN32 #include BOOL WINAPI event_handler(DWORD sig) { switch (sig) { case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: if (!g_killed) { dstream << "INFO: event_handler(): " << "Ctrl+C, Close Event, Logoff Event or Shutdown Event," " shutting down." << std::endl; g_killed = true; } else { (void)signal(SIGINT, SIG_DFL); } break; case CTRL_BREAK_EVENT: break; } return TRUE; } void signal_handler_init(void) { SetConsoleCtrlHandler((PHANDLER_ROUTINE)event_handler, TRUE); } #endif /* Path mangler */ // Default to RUN_IN_PLACE style relative paths std::string path_share = ".."; std::string path_user = ".."; std::string path_locale = path_share + DIR_DELIM + "locale"; std::string path_cache = path_user + DIR_DELIM + "cache"; std::string getDataPath(const char *subpath) { return path_share + DIR_DELIM + subpath; } void pathRemoveFile(char *path, char delim) { // Remove filename and path delimiter int i; for(i = strlen(path)-1; i>=0; i--) { if(path[i] == delim) break; } path[i] = 0; } bool detectMSVCBuildDir(const std::string &path) { const char *ends[] = { "bin\\Release", "bin\\MinSizeRel", "bin\\RelWithDebInfo", "bin\\Debug", "bin\\Build", NULL }; return (removeStringEnd(path, ends) != ""); } std::string get_sysinfo() { #ifdef _WIN32 OSVERSIONINFO osvi; std::ostringstream oss; std::string tmp; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); tmp = osvi.szCSDVersion; std::replace(tmp.begin(), tmp.end(), ' ', '_'); oss << "Windows/" << osvi.dwMajorVersion << "." << osvi.dwMinorVersion; if (osvi.szCSDVersion[0]) oss << "-" << tmp; oss << " "; #ifdef _WIN64 oss << "x86_64"; #else BOOL is64 = FALSE; if (IsWow64Process(GetCurrentProcess(), &is64) && is64) oss << "x86_64"; // 32-bit app on 64-bit OS else oss << "x86"; #endif return oss.str(); #else struct utsname osinfo; uname(&osinfo); return std::string(osinfo.sysname) + "/" + osinfo.release + " " + osinfo.machine; #endif } bool getCurrentWorkingDir(char *buf, size_t len) { #ifdef _WIN32 DWORD ret = GetCurrentDirectory(len, buf); return (ret != 0) && (ret <= len); #else return getcwd(buf, len); #endif } bool getExecPathFromProcfs(char *buf, size_t buflen) { #ifndef _WIN32 buflen--; ssize_t len; if ((len = readlink("/proc/self/exe", buf, buflen)) == -1 && (len = readlink("/proc/curproc/file", buf, buflen)) == -1 && (len = readlink("/proc/curproc/exe", buf, buflen)) == -1) return false; buf[len] = '\0'; return true; #else return false; #endif } //// Windows #if defined(_WIN32) bool getCurrentExecPath(char *buf, size_t len) { DWORD written = GetModuleFileNameA(NULL, buf, len); if (written == 0 || written == len) return false; return true; } //// Linux #elif defined(__linux__) bool getCurrentExecPath(char *buf, size_t len) { if (!getExecPathFromProcfs(buf, len)) return false; return true; } //// Mac OS X, Darwin #elif defined(__APPLE__) bool getCurrentExecPath(char *buf, size_t len) { uint32_t lenb = (uint32_t)len; if (_NSGetExecutablePath(buf, &lenb) == -1) return false; return true; } //// FreeBSD, NetBSD, DragonFlyBSD #elif defined(__FreeBSD__) || defined(__Ne/* Minetest-c55 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef CONTENT_MAPNODE_HEADER #define CONTENT_MAPNODE_HEADER #include "mapnode.h" void content_mapnode_init(); extern content_t trans_table_19[21][2]; MapNode mapnode_translate_from_internal(MapNode n_from, u8 version); MapNode mapnode_translate_to_internal(MapNode n_from, u8 version); /* Node content type IDs Ranges: */ // 0x000...0x07f (0...127): param2 is fully usable // 126 and 127 are reserved. // Use these sparingly, only when the extra space in param2 might be needed. // Add a space when there is unused space between numbers. #define CONTENT_STONE 0 #define CONTENT_WATER 2 #define CONTENT_TORCH 3 #define CONTENT_WATERSOURCE 9 #define CONTENT_SIGN_WALL 14 #define CONTENT_CHEST 15 #define CONTENT_FURNACE 16 #define CONTENT_LOCKABLE_CHEST 17 #define CONTENT_FENCE 21 #define CONTENT_RAIL 30 #define CONTENT_LADDER 31 #define CONTENT_LAVA 32 #define CONTENT_LAVASOURCE 33 // 0x800...0xfff (2048...4095): higher 4 bytes of param2 are not usable #define CONTENT_GRASS 0x800 //1 #define CONTENT_TREE 0x801 //4 #define CONTENT_LEAVES 0x802 //5 #define CONTENT_GRASS_FOOTSTEPS 0x803 //6 #define CONTENT_MESE 0x804 //7 #define CONTENT_MUD 0x805 //8 // Pretty much useless, clouds won't be drawn this way #define CONTENT_CLOUD 0x806 //10 #define CONTENT_COALSTONE 0x807 //11 #define CONTENT_WOOD 0x808 //12 #define CONTENT_SAND 0x809 //13 #define CONTENT_COBBLE 0x80a //18 #define CONTENT_STEEL 0x80b //19 #define CONTENT_GLASS 0x80c //20 #define CONTENT_MOSSYCOBBLE 0x80d //22 #define CONTENT_GRAVEL 0x80e //23 #define CONTENT_SANDSTONE 0x80f //24 #define CONTENT_CACTUS 0x810 //25 #define CONTENT_BRICK 0x811 //26 #define CONTENT_CLAY 0x812 //27 #define CONTENT_PAPYRUS 0x813 //28 #define CONTENT_BOOKSHELF 0x814 //29 #define CONTENT_JUNGLETREE 0x815 #define CONTENT_JUNGLEGRASS 0x816 #define CONTENT_NC 0x817 #define CONTENT_NC_RB 0x818 #define CONTENT_APPLE 0x819 #define CONTENT_SAPLING 0x820 #endif locale directory " << STATIC_LOCALEDIR << std::endl; } else { path_locale = getDataPath("locale"); if (fs::PathExists(path_locale)) { found_localedir = true; infostream << "Using in-place locale directory " << path_locale << " even though a static one was provided " << "(RUN_IN_PLACE or CUSTOM_LOCALEDIR)." << std::endl; } } # else path_locale = getDataPath("locale"); if (fs::PathExists(path_locale)) { found_localedir = true; } # endif if (!found_localedir) { warningstream << "Couldn't find a locale directory!" << std::endl; } #endif // USE_GETTEXT } void setXorgClassHint(const video::SExposedVideoData &video_data, const std::string &name) { #ifdef XORG_USED if (video_data.OpenGLLinux.X11Display == NULL) return; XClassHint *classhint = XAllocClassHint(); classhint->res_name = (char *)name.c_str(); classhint->res_class = (char *)name.c_str(); XSetClassHint((Display *)video_data.OpenGLLinux.X11Display, video_data.OpenGLLinux.X11Window, classhint); XFree(classhint); #endif } bool setXorgWindowIcon(IrrlichtDevice *device) { #ifdef XORG_USED # if RUN_IN_PLACE return setXorgWindowIconFromPath(device, path_share + "/misc/" PROJECT_NAME "-xorg-icon-128.png"); # else // We have semi-support for reading in-place data if we are // compiled with RUN_IN_PLACE. Don't break with this and // also try the path_share location. return setXorgWindowIconFromPath(device, ICON_DIR "/hicolor/128x128/apps/" PROJECT_NAME ".png") || setXorgWindowIconFromPath(device, path_share + "/misc/" PROJECT_NAME "-xorg-icon-128.png"); # endif #else return false; #endif } bool setXorgWindowIconFromPath(IrrlichtDevice *device, const std::string &icon_file) { #ifdef XORG_USED video::IVideoDriver *v_driver = device->getVideoDriver(); video::IImageLoader *image_loader = NULL; u32 cnt = v_driver->getImageLoaderCount(); for (u32 i = 0; i < cnt; i++) { if (v_driver->getImageLoader(i)->isALoadableFileExtension(icon_file.c_str())) { image_loader = v_driver->getImageLoader(i); break; } } if (!image_loader) { warningstream << "Could not find image loader for file '" << icon_file << "'" << std::endl; return false; } io::IReadFile *icon_f = device->getFileSystem()->createAndOpenFile(icon_file.c_str()); if (!icon_f) { warningstream << "Could not load icon file '" << icon_file << "'" << std::endl; return false; } video::IImage *img = image_loader->loadImage(icon_f); if (!img) { warningstream << "Could not load icon file '" << icon_file << "'" << std::endl; icon_f->drop(); return false; } u32 height = img->getDimension().Height; u32 width = img->getDimension().Width; size_t icon_buffer_len = 2 + height * width; long *icon_buffer = new long[icon_buffer_len]; icon_buffer[0] = width; icon_buffer[1] = height; for (u32 x = 0; x < width; x++) { for (u32 y = 0; y < height; y++) { video::SColor col = img->getPixel(x, y); long pixel_val = 0; pixel_val |= (u8)col.getAlpha() << 24; pixel_val |= (u8)col.getRed() << 16; pixel_val |= (u8)col.getGreen() << 8; pixel_val |= (u8)col.getBlue(); icon_buffer[2 + x + y * width] = pixel_val; } } img->drop(); icon_f->drop(); const video::SExposedVideoData &video_data = v_driver->getExposedVideoData(); Display *x11_dpl = (Display *)video_data.OpenGLLinux.X11Display; if (x11_dpl == NULL) { warningstream << "Could not find x11 display for setting its icon." << std::endl; delete [] icon_buffer; return false; } Window x11_win = (Window)video_data.OpenGLLinux.X11Window; Atom net_wm_icon = XInternAtom(x11_dpl, "_NET_WM_ICON", False); Atom cardinal = XInternAtom(x11_dpl, "CARDINAL", False); XChangeProperty(x11_dpl, x11_win, net_wm_icon, cardinal, 32, PropModeReplace, (const unsigned char *)icon_buffer, icon_buffer_len); delete [] icon_buffer; #endif return true; } //// //// Video/Display Information (Client-only) //// #ifndef SERVER static irr::IrrlichtDevice *device; void initIrrlicht(irr::IrrlichtDevice *device_) { device = device_; } v2u32 getWindowSize() { return device->getVideoDriver()->getScreenSize(); } std::vector > getSupportedVideoModes() { IrrlichtDevice *nulldevice = createDevice(video::EDT_NULL); sanity_check(nulldevice != NULL); std::vector > mlist; video::IVideoModeList *modelist = nulldevice->getVideoModeList(); u32 num_modes = modelist->getVideoModeCount(); for (u32 i = 0; i != num_modes; i++) { core::dimension2d mode_res = modelist->getVideoModeResolution(i); s32 mode_depth = modelist->getVideoModeDepth(i); mlist.push_back(core::vector3d(mode_res.Width, mode_res.Height, mode_depth)); } nulldevice->drop(); return mlist; } std::vector getSupportedVideoDrivers() { std::vector drivers; for (int i = 0; i != irr::video::EDT_COUNT; i++) { if (irr::IrrlichtDevice::isDriverSupported((irr::video::E_DRIVER_TYPE)i)) drivers.push_back((irr::video::E_DRIVER_TYPE)i); } return drivers; } const char *getVideoDriverName(irr::video::E_DRIVER_TYPE type) { static const char *driver_ids[] = { "null", "software", "burningsvideo", "direct3d8", "direct3d9", "opengl", "ogles1", "ogles2", }; return driver_ids[type]; } const char *getVideoDriverFriendlyName(irr::video::E_DRIVER_TYPE type) { static const char *driver_names[] = { "NULL Driver", "Software Renderer", "Burning's Video", "Direct3D 8", "Direct3D 9", "OpenGL", "OpenGL ES1", "OpenGL ES2", }; return driver_names[type]; } # ifndef __ANDROID__ # ifdef XORG_USED static float calcDisplayDensity() { const char *current_display = getenv("DISPLAY"); if (current_display != NULL) { Display *x11display = XOpenDisplay(current_display); if (x11display != NULL) { /* try x direct */ float dpi_height = floor(DisplayHeight(x11display, 0) / (DisplayHeightMM(x11display, 0) * 0.039370) + 0.5); float dpi_width = floor(DisplayWidth(x11display, 0) / (DisplayWidthMM(x11display, 0) * 0.039370) + 0.5); XCloseDisplay(x11display); return std::max(dpi_height,dpi_width) / 96.0; } } /* return manually specified dpi */ return g_settings->getFloat("screen_dpi")/96.0; } float getDisplayDensity() { static float cached_display_density = calcDisplayDensity(); return cached_display_density; } # else // XORG_USED float getDisplayDensity() { return g_settings->getFloat("screen_dpi")/96.0; } # endif // XORG_USED v2u32 getDisplaySize() { IrrlichtDevice *nulldevice = createDevice(video::EDT_NULL); core::dimension2d deskres = nulldevice->getVideoModeList()->getDesktopResolution(); nulldevice -> drop(); return deskres; } # endif // __ANDROID__ #endif // SERVER //// //// OS-specific Secure Random //// #ifdef WIN32 bool secure_rand_fill_buf(void *buf, size_t len) { HCRYPTPROV wctx; if (!CryptAcquireContext(&wctx, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return false; CryptGenRandom(wctx, len, (BYTE *)buf); CryptReleaseContext(wctx, 0); return true; } #else bool secure_rand_fill_buf(void *buf, size_t len) { // N.B. This function checks *only* for /dev/urandom, because on most // common OSes it is non-blocking, whereas /dev/random is blocking, and it // is exceptionally uncommon for there to be a situation where /dev/random // exists but /dev/urandom does not. This guesswork is necessary since // random devices are not covered by any POSIX standard... FILE *fp = fopen("/dev/urandom", "rb"); if (!fp) return false; bool success = fread(buf, len, 1, fp) == 1; fclose(fp); return success; } #endif } //namespace porting