Index: simutrans/trunk/dataobj/height_map_loader.cc =================================================================== --- simutrans/trunk/dataobj/height_map_loader.cc (revision 8300) +++ simutrans/trunk/dataobj/height_map_loader.cc (working copy) @@ -7,6 +7,7 @@ #include "environment.h" #include "height_map_loader.h" #include "../simio.h" +#include "../simsys.h" height_map_loader_t::height_map_loader_t(bool new_format): @@ -18,7 +19,7 @@ // read height data from bmp or ppm files bool height_map_loader_t::get_height_data_from_file( const char *filename, sint8 groundwater, sint8 *&hfield, sint16 &ww, sint16 &hh, bool update_only_values ) { - if (FILE* const file = fopen(filename, "rb")) { + if (FILE* const file = dr_fopen(filename, "rb")) { char id[3]; // parsing the header of this mixed file format is nottrivial ... id[0] = fgetc(file); Index: simutrans/trunk/dataobj/loadsave.cc =================================================================== --- simutrans/trunk/dataobj/loadsave.cc (revision 8300) +++ simutrans/trunk/dataobj/loadsave.cc (working copy) @@ -272,10 +272,9 @@ close(); last_error = FILE_ERROR_OK; // no error - const char *filename = dr_utf8_to_system_filename( filename_utf8 ); version = 0; mode = zipped; - fd->fp = fopen( filename, "rb"); + fd->fp = dr_fopen(filename_utf8, "rb"); if( fd->fp==NULL ) { // most likely not existing last_error = FILE_ERROR_NOT_EXISTING; @@ -317,7 +316,7 @@ if( mode!=bzip2 ) { fclose(fd->fp); // and now with zlib ... - fd->gzfp = gzopen(filename, "rb"); + fd->gzfp = dr_gzopen(filename_utf8, "rb"); if(fd->gzfp==NULL) { return false; last_error = FILE_ERROR_GZ_CORRUPT; @@ -407,7 +406,7 @@ if(*pak_extension==0) { strcpy( pak_extension, "(unknown)" ); } - this->filename = filename; + this->filename = filename_utf8; return true; } @@ -418,18 +417,17 @@ last_error = FILE_ERROR_OK; // no error close(); - const char *filename = dr_utf8_to_system_filename( filename_utf8, true ); if( is_zipped() ) { // using zlib - fd->gzfp = gzopen(filename, "wb"); + fd->gzfp = dr_gzopen(filename_utf8, "wb"); } else if( mode==binary ) { // no compression - fd->fp = fopen(filename, "wb"); + fd->fp = dr_fopen(filename_utf8, "wb"); } else if( is_bzip2() ) { // XML or bzip ... - fd->fp = fopen(filename, "wb"); + fd->fp = dr_fopen(filename_utf8, "wb"); // the additional magic for bzip2 fd->bse = BZ_OK+1; fd->bzfp = NULL; @@ -443,7 +441,7 @@ else { // uncompressed xml should be here ... assert( mode==xml ); - fd->fp = fopen(filename, "wb"); + fd->fp = dr_fopen(filename_utf8, "wb"); } // check whether we could open the file @@ -488,7 +486,7 @@ ident = 1; } - this->filename = filename; + this->filename = filename_utf8; return true; } Index: simutrans/trunk/dataobj/scenario.cc =================================================================== --- simutrans/trunk/dataobj/scenario.cc (revision 8300) +++ simutrans/trunk/dataobj/scenario.cc (working copy) @@ -1,3 +1,4 @@ +#include "../simsys.h" #include "../simconst.h" #include "../simtypes.h" #include "../simdebug.h" @@ -721,7 +722,7 @@ } std::string path = scenario_path.c_str(); // try user language - std::string wanted_file = path + translator::get_lang()->iso + "/" + filename; + std::string wanted_file = path + translator::get_lang()->iso + PATH_SEPARATOR + filename; const plainstring& cached = cached_text_files.get(wanted_file.c_str()); if (cached != NULL) { @@ -729,14 +730,14 @@ return cached; } // not cached: try to read file - FILE* file = fopen(wanted_file.c_str(), "rb"); + FILE* file = dr_fopen(wanted_file.c_str(), "rb"); if (file == NULL) { // try English - file = fopen((path + "en/" + filename).c_str(), "rb"); + file = dr_fopen((path + "en" + PATH_SEPARATOR + filename).c_str(), "rb"); } if (file == NULL) { // try scenario directory - file = fopen((path + filename).c_str(), "rb"); + file = dr_fopen((path + filename).c_str(), "rb"); } plainstring text = ""; Index: simutrans/trunk/descriptor/reader/obj_reader.cc =================================================================== --- simutrans/trunk/descriptor/reader/obj_reader.cc (revision 8300) +++ simutrans/trunk/descriptor/reader/obj_reader.cc (working copy) @@ -74,7 +74,7 @@ if(name.at(name.size() - 1) != '/') { // very old style ... (I think unused by now) - if (FILE* const listfp = fopen(name.c_str(), "r")) { + if (FILE* const listfp = dr_fopen(name.c_str(), "r")) { while(!feof(listfp)) { char buf[256]; @@ -161,7 +161,7 @@ // Hajo: added trace DBG_DEBUG("obj_reader_t::read_file()", "filename='%s'", name); - if (FILE* const fp = fopen(name, "rb")) { + if (FILE* const fp = dr_fopen(name, "rb")) { sint32 n = 0; // This is the normal header reading code Index: simutrans/trunk/display/font.cc =================================================================== --- simutrans/trunk/display/font.cc (revision 8300) +++ simutrans/trunk/display/font.cc (working copy) @@ -1,6 +1,7 @@ #include #include #include +#include "../simsys.h" #include "../simtypes.h" #include "../simmem.h" #include "../simdebug.h" @@ -361,7 +362,7 @@ bool load_font(font_type* fnt, const char* fname) { - FILE* f = fopen(fname, "rb"); + FILE* f = dr_fopen(fname, "rb"); int c; #ifdef USE_FREETYPE Index: simutrans/trunk/gui/ai_selector.cc =================================================================== --- simutrans/trunk/gui/ai_selector.cc (revision 8300) +++ simutrans/trunk/gui/ai_selector.cc (working copy) @@ -4,6 +4,7 @@ */ #include "../simdebug.h" +#include "../simsys.h" #include "ai_selector.h" #include "messagebox.h" @@ -72,7 +73,7 @@ { char buf[1024]; sprintf( buf, "%s/ai.nut", filename ); - if (FILE* const f = fopen(buf, "r")) { + if (FILE* const f = dr_fopen(buf, "r")) { fclose(f); return true; } Index: simutrans/trunk/gui/gui_theme.cc =================================================================== --- simutrans/trunk/gui/gui_theme.cc (revision 8300) +++ simutrans/trunk/gui/gui_theme.cc (working copy) @@ -386,7 +386,7 @@ else if( char *s = strrchr( pathname, '\\' ) ) { *s = 0; } - chdir( pathname ); + dr_chdir( pathname ); obj_reader_t::read_file(buttonpak.c_str()); gui_theme_t::init_gui_from_images(); free(pathname); Index: simutrans/trunk/gui/help_frame.cc =================================================================== --- simutrans/trunk/gui/help_frame.cc (revision 8300) +++ simutrans/trunk/gui/help_frame.cc (working copy) @@ -189,21 +189,21 @@ // just loads a whole help file as one chunk static const char *load_text(char const* const filename ) { - std::string file_prefix("text/"); - std::string fullname = file_prefix + translator::get_lang()->iso + "/" + filename; - chdir(env_t::program_dir); + std::string file_prefix= std::string("text") + PATH_SEPARATOR; + std::string fullname = file_prefix + translator::get_lang()->iso + PATH_SEPARATOR + filename; + dr_chdir(env_t::program_dir); - FILE* file = fopen(fullname.c_str(), "rb"); + FILE* file = dr_fopen(fullname.c_str(), "rb"); if (!file) { //Check for the 'base' language(ie en from en_gb) - file = fopen((file_prefix + translator::get_lang()->iso_base + "/" + filename).c_str(), "rb"); + file = dr_fopen((file_prefix + translator::get_lang()->iso_base + PATH_SEPARATOR + filename).c_str(), "rb"); } if (!file) { // Hajo: check fallback english - file = fopen((file_prefix + "/en/" + filename).c_str(), "rb"); + file = dr_fopen((file_prefix + PATH_SEPARATOR + "en" + PATH_SEPARATOR + filename).c_str(), "rb"); } // go back to load/save dir - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); if(file) { fseek(file,0,SEEK_END); @@ -384,22 +384,22 @@ FILE *help_frame_t::has_helpfile( char const* const filename, int &mode ) { mode = native; - std::string file_prefix("text/"); - std::string fullname = file_prefix + translator::get_lang()->iso + "/" + filename; - chdir(env_t::program_dir); + std::string file_prefix = std::string("text") + PATH_SEPARATOR; + std::string fullname = file_prefix + translator::get_lang()->iso + PATH_SEPARATOR + filename; + dr_chdir(env_t::program_dir); - FILE* file = fopen(fullname.c_str(), "rb"); + FILE* file = dr_fopen(fullname.c_str(), "rb"); if( !file && strcmp(translator::get_lang()->iso,translator::get_lang()->iso_base) ) { //Check for the 'base' language(ie en from en_gb) - file = fopen( (file_prefix + translator::get_lang()->iso_base + "/" + filename).c_str(), "rb" ); + file = dr_fopen( (file_prefix + translator::get_lang()->iso_base + PATH_SEPARATOR + filename).c_str(), "rb" ); } if( !file ) { // Hajo: check fallback english - file = fopen((file_prefix + "en/" + filename).c_str(), "rb"); + file = dr_fopen((file_prefix + "en/" + filename).c_str(), "rb"); mode = english; } // go back to load/save dir - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); // success? if( !file ) { mode = missing; Index: simutrans/trunk/gui/loadsave_frame.cc =================================================================== --- simutrans/trunk/gui/loadsave_frame.cc (revision 8300) +++ simutrans/trunk/gui/loadsave_frame.cc (working copy) @@ -150,7 +150,7 @@ // get file information struct stat sb; - if(stat( dr_utf8_to_system_filename(fname), &sb)!=0) { + if(dr_stat(fname, &sb) != 0) { // file not found? return date; } Index: simutrans/trunk/gui/pakselector.cc =================================================================== --- simutrans/trunk/gui/pakselector.cc (revision 8300) +++ simutrans/trunk/gui/pakselector.cc (working copy) @@ -94,7 +94,7 @@ buf.printf("%s/ground.Outside.pak", filename); // if we can open the file, it is valid. - if (FILE* const f = fopen(buf, "r")) { + if (FILE* const f = dr_fopen(buf, "r")) { fclose(f); return true; } @@ -130,7 +130,7 @@ // if we can't change directory to /addon // Hide the addon button - if( chdir( path ) != 0 ) { + if( dr_chdir( path ) != 0 ) { i.del->set_visible(false); i.del->disable(); @@ -145,7 +145,7 @@ y += D_BUTTON_HEIGHT+D_FOCUS_OFFSET_V; } action_button_width += (D_H_SPACE<<1); - chdir( env_t::program_dir ); + dr_chdir( env_t::program_dir ); if(entries.get_count() > this->num_sections+1) { // empty path as more than one pakset is present, user has to choose Index: simutrans/trunk/gui/savegame_frame.cc =================================================================== --- simutrans/trunk/gui/savegame_frame.cc (revision 8300) +++ simutrans/trunk/gui/savegame_frame.cc (working copy) @@ -306,11 +306,11 @@ delete_button->set_size(scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT)); delete_button->set_text("X"); -#ifdef SIM_SYSTEM_TRASHBINAVAILABLE - delete_button->set_tooltip("Send this file to the system trash bin. SHIFT+CLICK to permanently delete."); -#else - delete_button->set_tooltip("Delete this file."); -#endif + if (dr_cantrash()) { + delete_button->set_tooltip("Send this file to the system trash bin. SHIFT+CLICK to permanently delete."); + } else { + delete_button->set_tooltip("Delete this file."); + } delete_button->add_listener(this); action_button->add_listener(this); @@ -565,23 +565,16 @@ * @retval false This function always return false to prevent the * dialogue from being closed. */ -bool savegame_frame_t::del_action(const char * fullpath) +bool savegame_frame_t::del_action(const char *fullpath) { -#ifdef SIM_SYSTEM_TRASHBINAVAILABLE - - if (event_get_last_control_shift()&1) { + if (!dr_cantrash() || event_get_last_control_shift() & 1) { // shift pressed, delete without trash bin - remove(fullpath); + dr_remove(fullpath); return false; } dr_movetotrash(fullpath); return false; - -#else - remove(fullpath); -#endif - return false; } Index: simutrans/trunk/gui/scenario_frame.cc =================================================================== --- simutrans/trunk/gui/scenario_frame.cc (revision 8300) +++ simutrans/trunk/gui/scenario_frame.cc (working copy) @@ -6,6 +6,7 @@ */ #include "../simdebug.h" +#include "../simsys.h" #include "scenario_frame.h" #include "scenario_info.h" @@ -81,7 +82,7 @@ { char buf[1024]; sprintf( buf, "%s/scenario.nut", filename ); - if (FILE* const f = fopen(buf, "r")) { + if (FILE* const f = dr_fopen(buf, "r")) { fclose(f); return true; } Index: simutrans/trunk/gui/settings_frame.cc =================================================================== --- simutrans/trunk/gui/settings_frame.cc (revision 8300) +++ simutrans/trunk/gui/settings_frame.cc (working copy) @@ -91,7 +91,7 @@ tabfile_t simuconf; env_t::init(); *sets = settings_t(); - chdir( env_t::program_dir ); + dr_chdir( env_t::program_dir ); if(simuconf.open("config/simuconf.tab")) { sint16 dummy16; string dummy_str; @@ -99,8 +99,8 @@ sets->parse_colours( simuconf ); } stadt_t::cityrules_init(env_t::objfilename); - chdir( env_t::program_dir ); - chdir( env_t::objfilename.c_str() ); + dr_chdir( env_t::program_dir ); + dr_chdir( env_t::objfilename.c_str() ); if(simuconf.open("config/simuconf.tab")) { sint16 dummy16; string dummy_str; @@ -107,7 +107,7 @@ sets->parse_simuconf( simuconf, dummy16, dummy16, dummy16, dummy_str ); sets->parse_colours( simuconf ); } - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); if(simuconf.open("simuconf.tab")) { sint16 dummy16; string dummy_str; @@ -127,7 +127,7 @@ else if( komp==&revert_to_last_save ) { // load settings of last generated map loadsave_t file; - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); if( file.rd_open("default.sve") ) { sets->rdwr(&file); file.close(); Index: simutrans/trunk/network/network_cmd_ingame.cc =================================================================== --- simutrans/trunk/network/network_cmd_ingame.cc (revision 8300) +++ simutrans/trunk/network/network_cmd_ingame.cc (working copy) @@ -87,7 +87,7 @@ gi.rdwr( &fd ); fd.close(); // get gameinfo size - FILE *fh = fopen( "serverinfo.sve", "rb" ); + FILE *fh = dr_fopen( "serverinfo.sve", "rb" ); fseek( fh, 0, SEEK_END ); nwgi.len = ftell( fh ); rewind( fh ); @@ -109,7 +109,7 @@ dbg->warning( "nwc_gameinfo_t::execute", "send of NWC_GAMEINFO failed" ); } fclose( fh ); - remove( "serverinfo.sve" ); + dr_remove("serverinfo.sve"); } socket_list_t::remove_client( s ); } @@ -682,7 +682,7 @@ } // transfer game, all clients need to sync (save, reload, and pause) // now save and send - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); if( !env_t::server ) { char fn[256]; sprintf( fn, "client%i-network.sve", network_get_client_id() ); Index: simutrans/trunk/network/network_file_transfer.cc =================================================================== --- simutrans/trunk/network/network_file_transfer.cc (revision 8300) +++ simutrans/trunk/network/network_file_transfer.cc (working copy) @@ -1,6 +1,7 @@ #include "network_file_transfer.h" #include "../simdebug.h" #include "../simloadingscreen.h" +#include "../simsys.h" #include #include @@ -18,7 +19,7 @@ char const* network_receive_file( SOCKET const s, char const* const save_as, sint32 const length, sint32 const timeout ) { // ok, we have a socket to connect - remove(save_as); + dr_remove(save_as); DBG_MESSAGE("network_receive_file", "File size %li", length ); @@ -30,7 +31,7 @@ // good place to show a progress bar char rbuf[4096]; sint32 length_read = 0; - if (FILE* const f = fopen(save_as, "wb")) { + if (FILE* const f = dr_fopen(save_as, "wb")) { while(length_read < length) { if( timeout > 0 ) { /** 10s for 4096 bytes: @@ -89,7 +90,9 @@ #include "../simworld.h" #include "../utils/simstring.h" +#include "../simsys.h" + // connect to address (cp), receive gameinfo, close const char *network_gameinfo(const char *cp, gameinfo_t *gi) { @@ -139,7 +142,7 @@ // some more insets, while things may have failed err = fd.get_last_error() == loadsave_t::FILE_ERROR_FUTURE_VERSION ? "Server version too new" : "Server busy"; } - remove( filename ); + dr_remove( filename ); socket_list_t::remove_client( my_client_socket ); } end: @@ -246,7 +249,7 @@ const char *network_send_file( uint32 client_id, const char *filename ) { - FILE *fp = fopen(filename,"rb"); + FILE *fp = dr_fopen(filename,"rb"); if (fp == NULL) { dbg->warning("network_send_file", "could not open file %s", filename); return "Could not open file"; Index: simutrans/trunk/script/api_function.cc =================================================================== --- simutrans/trunk/script/api_function.cc (revision 8300) +++ simutrans/trunk/script/api_function.cc (working copy) @@ -1,6 +1,8 @@ #include "api_function.h" #include +#include "../simsys.h" + #include "../dataobj/environment.h" /** @@ -24,7 +26,7 @@ } cbuffer_t buf; buf.printf("squirrel_types_%s.awk", suffix); - file = fopen(buf, "w"); + file = dr_fopen(buf, "w"); if (file) { fprintf(file, "# file used to generate doxygen documentation of squirrel API\n"); fprintf(file, "# needs to be copied to trunk/script/api\n"); Index: simutrans/trunk/siminteraction.cc =================================================================== --- simutrans/trunk/siminteraction.cc (revision 8300) +++ simutrans/trunk/siminteraction.cc (working copy) @@ -309,7 +309,7 @@ env_t::server_save_game_on_quit = false; // following code quite similar to nwc_sync_t::do_coomand - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); // first save password hashes char fn[256]; Index: simutrans/trunk/simmain.cc =================================================================== --- simutrans/trunk/simmain.cc (revision 8300) +++ simutrans/trunk/simmain.cc (working copy) @@ -79,12 +79,6 @@ #include "vehicle/simvehicle.h" #include "vehicle/simroadtraffic.h" -#ifdef _MSC_VER -// Replace deprecated getcwd. -#define getcwd _getcwd -#endif - - using std::string; /* diagnostic routine: @@ -469,14 +463,6 @@ return 0; } -#ifdef _WIN32 -#define PATHSEP "\\" -#else -#define PATHSEP "/" -#endif - const char* path_sep = PATHSEP; - - #ifdef __BEOS__ if (1) // since BeOS only supports relative paths ... #else @@ -484,21 +470,13 @@ if (gimme_arg(argc, argv, "-use_workdir", 0)) #endif { -#if defined _WIN32 - WCHAR bufferW[1024], bufferW2[1024]; - // save the current directories, which need more effort on windows - GetCurrentDirectoryW( lengthof(bufferW), bufferW ); - GetShortPathNameW( bufferW, bufferW2, lengthof(bufferW2) ); - WideCharToMultiByte( CP_UTF8, 0, bufferW2, -1, env_t::program_dir, lengthof(env_t::program_dir), NULL, NULL ); -#else // save the current directories - getcwd(env_t::program_dir, lengthof(env_t::program_dir)); -#endif - strcat( env_t::program_dir, path_sep ); + dr_getcwd(env_t::program_dir, lengthof(env_t::program_dir)); + strcat( env_t::program_dir, PATH_SEPARATOR ); } else { strcpy( env_t::program_dir, argv[0] ); - *(strrchr( env_t::program_dir, path_sep[0] )+1) = 0; + *(strrchr( env_t::program_dir, PATH_SEPARATOR[0] )+1) = 0; #ifdef __APPLE__ // change working directory from binary dir to bundle dir @@ -522,7 +500,7 @@ } #endif - chdir( env_t::program_dir ); + dr_chdir( env_t::program_dir ); } printf("Use work dir %s\n", env_t::program_dir); @@ -540,7 +518,7 @@ tabfile_t simuconf; char path_to_simuconf[24]; // was config/simuconf.tab - sprintf(path_to_simuconf, "config%csimuconf.tab", path_sep[0]); + sprintf(path_to_simuconf, "config%csimuconf.tab", PATH_SEPARATOR[0]); if(simuconf.open(path_to_simuconf)) { tabfileobj_t contents; simuconf.read(contents); @@ -558,7 +536,7 @@ // save in program directory env_t::user_dir = env_t::program_dir; } - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); #ifdef REVISION @@ -600,7 +578,7 @@ } } else if (gimme_arg(argc, argv, "-log", 0)) { - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); char temp_log_name[256]; const char *logname = "simu.log"; if( gimme_arg(argc, argv, "-server", 0) ) { @@ -625,7 +603,7 @@ if( file.get_version()>loadsave_t::int_version(SAVEGAME_VER_NR, NULL, NULL ) ) { // too new => remove it file.close(); - remove( "settings.xml" ); + dr_remove("settings.xml"); } else { found_settings = true; @@ -640,7 +618,7 @@ } // continue parsing ... - chdir( env_t::program_dir ); + dr_chdir( env_t::program_dir ); if( found_simuconf ) { if(simuconf.open(path_to_simuconf)) { printf("parse_simuconf() at config/simuconf.tab: "); @@ -822,36 +800,36 @@ // prepare skins first bool themes_ok = false; if( const char *themestr = gimme_arg(argc, argv, "-theme", 1) ) { - chdir( env_t::user_dir ); - chdir( "themes" ); + dr_chdir( env_t::user_dir ); + dr_chdir( "themes" ); themes_ok = gui_theme_t::themes_init(themestr); if( !themes_ok ) { - chdir( env_t::program_dir ); - chdir( "themes" ); + dr_chdir( env_t::program_dir ); + dr_chdir( "themes" ); themes_ok = gui_theme_t::themes_init(themestr); } } // next try the last used theme if( !themes_ok && env_t::default_theme.c_str()!=NULL ) { - chdir( env_t::user_dir ); - chdir( "themes" ); + dr_chdir( env_t::user_dir ); + dr_chdir( "themes" ); themes_ok = gui_theme_t::themes_init( env_t::default_theme ); if( !themes_ok ) { - chdir( env_t::program_dir ); - chdir( "themes" ); + dr_chdir( env_t::program_dir ); + dr_chdir( "themes" ); themes_ok = gui_theme_t::themes_init( env_t::default_theme ); } } // specified themes not found => try default themes if( !themes_ok ) { - chdir( env_t::program_dir ); - chdir( "themes" ); + dr_chdir( env_t::program_dir ); + dr_chdir( "themes" ); themes_ok = gui_theme_t::themes_init("themes.tab"); } if( !themes_ok ) { dbg->fatal( "simmain()", "No GUI themes found! Please re-install!" ); } - chdir( env_t::program_dir ); + dr_chdir( env_t::program_dir ); // The loading screen needs to be initialized show_pointer(1); @@ -889,7 +867,7 @@ buf.append( env_t::objfilename.c_str() ); buf.append("ground.Outside.pak"); - FILE* const f = fopen(buf, "r"); + FILE* const f = dr_fopen(buf, "r"); if( !f ) { dr_fatal_notify("*** No pak set found ***\n\nMost likely, you have no pak set installed.\nPlease download and install a pak set (graphics).\n"); simgraph_exit(); @@ -1019,7 +997,7 @@ // Hajo: simgraph init loads default fonts, now we need to load // the real fonts for the current language sprachengui_t::init_font_from_lang(); - chdir(env_t::program_dir); + dr_chdir(env_t::program_dir); dbg->important("Reading city configuration ..."); stadt_t::cityrules_init(env_t::objfilename); @@ -1035,12 +1013,12 @@ obj_reader_t::load(env_t::objfilename.c_str(), translator::translate("Loading paks ...") ); if( env_t::default_settings.get_with_private_paks() ) { // try to read addons from private directory - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); if(!obj_reader_t::load(("addons/" + env_t::objfilename).c_str(), translator::translate("Loading addon paks ..."))) { fprintf(stderr, "reading addon object data failed (disabling).\n"); env_t::default_settings.set_with_private_paks( false ); } - chdir( env_t::program_dir ); + dr_chdir( env_t::program_dir ); } obj_reader_t::finish_loading(); pakset_info_t::calculate_checksum(); @@ -1063,7 +1041,7 @@ if( gimme_arg(argc, argv, "-load", 0) != NULL ) { cbuffer_t buf; - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); /** * Added automatic adding of extension */ @@ -1081,7 +1059,7 @@ // recover last server game if( new_world && env_t::server ) { - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); loadsave_t file; static char servername[128]; sprintf( servername, "server%d-network.sve", env_t::server ); @@ -1106,9 +1084,9 @@ pak_name.append( env_t::objfilename ); pak_name.erase( pak_name.length()-1 ); pak_name.append( ".sve" ); - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); unlink( "temp-load.sve" ); - if( rename( pak_name.c_str(), "temp-load.sve" )==0 ) { + if( dr_rename(pak_name.c_str(), "temp-load.sve") == 0 ) { loadgame = "temp-load.sve"; new_world = false; } @@ -1117,11 +1095,11 @@ // still nothing to be loaded => search for demo games if( new_world ) { - chdir( env_t::program_dir ); + dr_chdir( env_t::program_dir ); char buffer[256]; sprintf(buffer, "%s%sdemo.sve", (const char*)env_t::program_dir, env_t::objfilename.c_str()); // access did not work! - if (FILE* const f = fopen(buffer, "rb")) { + if (FILE* const f = dr_fopen(buffer, "rb")) { // there is a demo game to load loadgame = buffer; fclose(f); @@ -1144,7 +1122,7 @@ } // now always writing in user dir (which points the the program dir in multiuser mode) - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); // init midi before loading sounds if( dr_init_midi() ) { @@ -1213,7 +1191,7 @@ env_t::server_admin_pw = ref_str; } - chdir(env_t::user_dir); + dr_chdir(env_t::user_dir); // reset random counter to true randomness setsimrand(dr_time(), dr_time()); @@ -1367,7 +1345,7 @@ intr_disable(); // save setting ... - chdir( env_t::user_dir ); + dr_chdir( env_t::user_dir ); if( file.wr_open("settings.xml",loadsave_t::xml,"settings only/",SAVEGAME_VER_NR) ) { env_t::rdwr(&file); env_t::default_settings.rdwr(&file); Index: simutrans/trunk/simsound.cc =================================================================== --- simutrans/trunk/simsound.cc (revision 8300) +++ simutrans/trunk/simsound.cc (working copy) @@ -160,10 +160,9 @@ int midi_init(const char *directory) { // read a list of soundfiles - char full_path[1024]; + std::string full_path = std::string(directory) + "music" + PATH_SEPARATOR + "music.tab"; - sprintf( full_path, "%smusic/music.tab", directory ); - if( FILE* const file = fopen(full_path, "rb") ) { + if( FILE* const file = dr_fopen(full_path.c_str(), "rb") ) { while(!feof(file)) { char buf[256]; char title[256]; @@ -178,9 +177,9 @@ } if( len > 1 ) { - sprintf( full_path, "%s%s", directory, buf ); - printf(" Reading MIDI file '%s' - %s", full_path, title); - max_midi = dr_load_midi(full_path); + full_path = std::string(directory) + buf; + printf(" Reading MIDI file '%s' - %s", full_path.c_str(), title); + max_midi = dr_load_midi(full_path.c_str()); if( max_midi >= 0 ) { len = strlen(title); Index: simutrans/trunk/simsys.cc =================================================================== --- simutrans/trunk/simsys.cc (revision 8300) +++ simutrans/trunk/simsys.cc (working copy) @@ -42,7 +42,70 @@ struct sys_event sys_event; +#ifdef _WIN32 +// Exception thrown when invalid Unicode characters are encountered. +const std::runtime_error INVALID_UNICODE_EXCEPTION(std::string("Invalid Unicode character encountered when preparing for conversion.")); + /** + * Utility class to handle conversion of UTF-8 to UTF-16 for use by Windows APIs. + * Constructs a UTF-16 view of the current contents of a UTF-8 C string. + */ +class U16View { +private: + LPCWSTR cu16str; +public: + /** + * Constructs a UTF-16 view of a UTF-8 C string. + */ + U16View(char const *const u8str) + { + // Convert UTF-8 to UTF-16. + int const size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8str, -1, NULL, 0); + if(size == 0) { + throw INVALID_UNICODE_EXCEPTION; + } + LPWSTR const u16str = new WCHAR[size]; + MultiByteToWideChar(CP_UTF8, 0, u8str, -1, u16str, size); + + cu16str = u16str; + } + + /** + * Copy constructor to allow safe movement. + * Should also have move constructor to allow efficient movement but that requires C++11. + */ + U16View(U16View const& from) + { + LPWSTR const u16str = new WCHAR[wcslen(cu16str) + 1]; + wcscpy(u16str, from.cu16str); + cu16str = u16str; + } + + ~U16View() + { + delete[] cu16str; + } + + /** + * Typecast operator to allow implicit use as a LPCWSTR. + */ + operator LPCWSTR() const + { + return cu16str; + } +}; +#endif + +// Platform specific path separators. +#ifdef _WIN32 +char const PATH_SEPARATOR[] = "\\"; +#else +char const PATH_SEPARATOR[] = "/"; +#endif + + + +/** * Get Mouse X-Position * @author Hj. Malthaner */ @@ -63,128 +126,230 @@ -void dr_mkdir(char const* const path) +int dr_mkdir(char const* const path) { -#if defined(_WIN32) && !defined(__CYGWIN__) - WCHAR pathW[MAX_PATH]; - MultiByteToWideChar( CP_UTF8, 0, path, -1, pathW, sizeof(pathW) ); - CreateDirectoryW( pathW, NULL ); +#ifdef _WIN32 + // Perform operation. + int const result = CreateDirectoryW(U16View(path), NULL) ? 0 : -1; + + // Translate error. + if(result != 0) { + DWORD const error = GetLastError(); + if(error == ERROR_ALREADY_EXISTS) { + _set_errno(EEXIST); + } else if(error == ERROR_PATH_NOT_FOUND) { + _set_errno(ENOENT); + } + } + + return result; #else - mkdir(path, 0777); + return mkdir(path, 0777); #endif } -#ifdef SIM_SYSTEM_TRASHBINAVAILABLE -bool dr_movetotrash(const char *path) { - // We just have a Windows implementation so far + +bool dr_movetotrash(const char *path) +{ #ifdef _WIN32 - SHFILEOPSTRUCTA FileOp; - - int len = strlen(path); - - char * wfilename = new char [len+2]; - - strcpy(wfilename, path); - - // Double \0 terminated string as required by the function. - wfilename[len+1]='\0'; - - ZeroMemory(&FileOp, sizeof(SHFILEOPSTRUCTA)); - + // Convert to full path name to allow use of recycle bin. + // Must be double null terminated for SHFILESTRUCT + U16View const wpath(path); + int const full_size = GetFullPathNameW(wpath, 0, NULL, NULL); + wchar_t *const full_wpath = new wchar_t[full_size + 1]; + GetFullPathNameW(wpath, full_size, full_wpath, NULL); + full_wpath[full_size] = L'\0'; + + // Initalize file operation structure. + SHFILEOPSTRUCTW FileOp; FileOp.hwnd = NULL; FileOp.wFunc = FO_DELETE; + FileOp.pFrom = full_wpath; + FileOp.pTo = NULL; FileOp.fFlags = FOF_ALLOWUNDO|FOF_NOCONFIRMATION; - FileOp.pFrom = wfilename; - FileOp.pTo = NULL; - int successful = SHFileOperationA(&FileOp); + // Perform operation. + int success = SHFileOperationW(&FileOp); - delete wfilename; + delete[] full_wpath; - return successful; + return success; +#else + return remove(path); #endif +} + + +bool dr_cantrash() +{ +#ifdef _WIN32 + return true; +#else + return false; +#endif } -#endif -// accecpt whatever encoding your filename has (assuming ANSI for windows) and returns the Unicode name -const char *dr_system_filename_to_uft8( const char *path_in ) + +int dr_remove(const char *path) { -#if defined _WIN32 - WCHAR bufferW[1024], bufferW2[1024]; - static char buffer[1024*3]; - MultiByteToWideChar( CP_UTF8, 0, path_in, -1, bufferW, lengthof(bufferW) ); - GetLongPathNameW( bufferW, bufferW2, lengthof(bufferW2) ); - WideCharToMultiByte( CP_UTF8, 0, bufferW2, -1, buffer, lengthof(buffer), NULL, NULL ); - return buffer; +#ifdef _WIN32 + // Perform operation. + bool success = DeleteFileW(U16View(path)); + + // Translate error. + if(!success) { + DWORD error = GetLastError(); + if(error == ERROR_FILE_NOT_FOUND) { + _set_errno(ENOENT); + } else if(error == ERROR_ACCESS_DENIED) { + _set_errno(EACCES); + } + } + + return success ? 0 : -1; +#else + return remove(path); #endif - return path_in; } -// accecpt utf8 and returns (on windows) an ANSI filename -const char *dr_utf8_to_system_filename( const char *path_in_utf8, bool create ) +int dr_rename(const char *existing_utf8, const char *new_utf8) { -#if defined _WIN32 - WCHAR bufferW[1024], bufferW2[1024]; - static char buffer[1024*3]; - MultiByteToWideChar( CP_UTF8, 0, path_in_utf8, -1, bufferW, lengthof(bufferW) ); - if( GetShortPathNameW( bufferW, bufferW2, lengthof(bufferW2) ) == 0 ) { - if( !create ) { - // file does not exist, return input path - return path_in_utf8; +#ifdef _WIN32 + // Perform operation. + bool success = MoveFileExW(U16View(existing_utf8), U16View(new_utf8), MOVEFILE_REPLACE_EXISTING); + + // Translate error. + if(!success) { + DWORD error = GetLastError(); + if (error == ERROR_FILE_NOT_FOUND) { + _set_errno(ENOENT); + } else if(error == ERROR_ACCESS_DENIED) { + _set_errno(EACCES); } - else { - CloseHandle( CreateFileW( bufferW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ) ); - GetShortPathNameW( bufferW, bufferW2, lengthof(bufferW2) ); + } + + return success ? 0 : -1; +#else + remove( new_utf8 ); + return rename( existing_utf8, new_utf8 ); +#endif +} + +int dr_chdir(const char *path) +{ +#ifdef _WIN32 + // Perform operation. + bool success = SetCurrentDirectoryW(U16View(path)); + + // Translate error. + if(!success) { + DWORD error = GetLastError(); + if (error == ERROR_FILE_NOT_FOUND) { + _set_errno(ENOENT); + } else if(error == ERROR_ACCESS_DENIED) { + _set_errno(EACCES); } } - WideCharToMultiByte( CP_UTF8, 0, bufferW2, -1, buffer, lengthof(buffer), NULL, NULL ); - return buffer; + + return success ? 0 : -1; +#else + return chdir(path); #endif - (void)create; - return path_in_utf8; } +char *dr_getcwd(char *buf, size_t size) +{ +#ifdef _WIN32 + DWORD wsize = GetCurrentDirectoryW(0, NULL); + WCHAR *const wpath = new WCHAR[wsize]; + DWORD success = GetCurrentDirectoryW(wsize, wpath); + // Translate error. + if(!success) { + delete[] wpath; + return NULL; + } -void dr_rename( const char *existing_utf8, const char *new_utf8 ) + // Convert UTF-16 to UTF-8. + int const convert_size = WideCharToMultiByte(CP_UTF8, 0, wpath, -1, buf, (int)size, NULL, NULL); + delete[] wpath; + if(convert_size == 0) { + return NULL; + } + + return buf; +#else + return getcwd(buf, size); +#endif +} + +FILE *dr_fopen (const char *filename, const char *mode) { -#if defined _WIN32 - WCHAR oldf[1024], newf[1024]; - MultiByteToWideChar( CP_UTF8, 0, existing_utf8, -1, oldf, lengthof(oldf) ); - MultiByteToWideChar( CP_UTF8, 0, new_utf8, -1, newf, lengthof(newf) ); - MoveFileExW( oldf, newf, MOVEFILE_REPLACE_EXISTING ); +#ifdef _WIN32 + // Perform operation. + return _wfopen(U16View(filename), U16View(mode)); #else - remove( new_utf8 ); - rename( existing_utf8, new_utf8 ); + return fopen(filename, mode); #endif } +gzFile dr_gzopen(const char *path, const char *mode) +{ +#ifdef _WIN32 + // Perform operation. + return gzopen_w(U16View(path), mode); +#else + return gzopen(path, mode); +#endif +} -char const* dr_query_homedir() +int dr_stat(const char *path, struct stat *buf) { - static char buffer[PATH_MAX+24]; +#ifdef _WIN32 + // Perform operation. + return _wstat64i32(U16View(path), (struct _stat64i32*)buf); +#else + return stat(path, buf); +#endif +} +char const *dr_query_homedir() +{ + static char buffer[PATH_MAX + 24]; + #if defined _WIN32 - WCHAR bufferW[PATH_MAX+24], bufferW2[PATH_MAX]; - if( SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, bufferW) ) { - DWORD len = PATH_MAX; + WCHAR whomedir[MAX_PATH]; + if(FAILED(SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, whomedir))) { + DWORD len = sizeof(whomedir); HKEY hHomeDir; - if( RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_READ, &hHomeDir) != ERROR_SUCCESS ) { - return 0; + if(RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_READ, &hHomeDir) != ERROR_SUCCESS) { + return NULL; } - RegQueryValueExW(hHomeDir, L"Personal", 0, 0, (LPBYTE)bufferW, &len); + LSTATUS status = RegQueryValueExW(hHomeDir, L"Personal", NULL, NULL, (LPBYTE)whomedir, &len); + RegCloseKey(hHomeDir); + if(status != ERROR_SUCCESS) { + return NULL; + } } - wcscat( bufferW, L"\\Simutrans" ); - CreateDirectoryW( bufferW, NULL ); - wcscat( bufferW, L"\\" ); - GetShortPathNameW( bufferW, bufferW2, lengthof(bufferW2) ); - WideCharToMultiByte( CP_UTF8, 0, bufferW2, -1, buffer, lengthof(buffer), NULL, NULL ); + // Convert UTF-16 to UTF-8. + int const convert_size = WideCharToMultiByte(CP_UTF8, 0, whomedir, -1, buffer, sizeof(buffer), NULL, NULL); + if(convert_size == 0) { + return NULL; + } + + // Append Sumutrans folder. + char const foldername[] = "Simutrans"; + if(lengthof(buffer) < strlen(buffer) + strlen(foldername) + 2 * strlen(PATH_SEPARATOR) + 1){ + return NULL; + } + strcat(buffer, PATH_SEPARATOR); + strcat(buffer, foldername); #elif defined __APPLE__ sprintf(buffer, "%s/Library/Simutrans", getenv("HOME")); #elif defined __HAIKU__ @@ -195,13 +360,10 @@ sprintf(buffer, "%s/simutrans", getenv("HOME")); #endif - // create directory and subdirectories -#ifndef _WIN32 dr_mkdir(buffer); - strcat(buffer, "/"); -#endif - chdir( buffer ); + strcat(buffer, PATH_SEPARATOR); + dr_chdir(buffer); dr_mkdir("maps"); dr_mkdir("save"); dr_mkdir("screenshots"); @@ -210,20 +372,29 @@ } -const char *dr_query_fontpath( const char *fontname ) +const char *dr_query_fontpath(const char *fontname) { -#if defined _WIN32 +#ifdef _WIN32 static char buffer[PATH_MAX]; + WCHAR fontdir[MAX_PATH]; + if(FAILED(SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, fontdir))) { + wcscpy(fontdir, L"C:\\Windows\\Fonts"); + } - if( SHGetFolderPathA(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, buffer) ) { - strcpy( buffer, "C:\\Windows\\Fonts" ); + // Convert UTF-16 to UTF-8. + int const convert_size = WideCharToMultiByte(CP_UTF8, 0, fontdir, -1, buffer, sizeof(buffer), NULL, NULL); + if(convert_size == 0) { + return fontname; } - strcat( buffer, "\\" ); - strcat( buffer, fontname ); + + // Prevent possible buffer overrun error. + if(lengthof(buffer) < strlen(buffer) + strlen(fontname) + strlen(PATH_SEPARATOR) + 1) { + return fontname; + } + + strcat(buffer, PATH_SEPARATOR); + strcat(buffer, fontname); return buffer; -#elif defined __APPLE__ - // not implemented yet - return fontname; #else // seems non-trivial to work on any system ... return fontname; Index: simutrans/trunk/simsys.h =================================================================== --- simutrans/trunk/simsys.h (revision 8300) +++ simutrans/trunk/simsys.h (working copy) @@ -9,6 +9,7 @@ #include #include "simtypes.h" +#include "zlib.h" // Provide chdir(). #if defined(_WIN32) && !defined(__CYGWIN__) @@ -17,10 +18,6 @@ # include #endif -#ifdef _WIN32 -#define SIM_SYSTEM_TRASHBINAVAILABLE -#endif - /* Variable for message processing */ /* Classes */ @@ -61,14 +58,7 @@ extern struct sys_event sys_event; -#ifdef SIM_SYSTEM_TRASHBINAVAILABLE -/** - * Moves the specified file to the system's trash bin. - * @param path Path to the file to delete. - * @return False on success. - */ -bool dr_movetotrash(const char *path); -#endif +extern char const PATH_SEPARATOR[]; // scale according to dpi setting bool dr_auto_scale(bool); @@ -89,17 +79,44 @@ // returns the locale; NULL if unknown const char *dr_get_locale_string(); -void dr_mkdir(char const* path); +// Functions the same as normal mkdir except path must be UTF-8 encoded and a default mode of 0777 is assumed. +int dr_mkdir(char const* path); -// accecpt whatever encoding your filename has (assuming ANSI for windows) and returns the Unicode name -const char *dr_system_filename_to_uft8( const char *path_in ); +/** + * Moves the specified file to the system's trash bin. + * If trash is not available on the platform, removes file. + * @param path UTF-8 path to the file to delete. + * @return False on success. + */ +bool dr_movetotrash(const char *path); -// accecpt utf8 and returns (on windows) an ANSI filename -const char *dr_utf8_to_system_filename( const char *path_in_utf8, bool create=false ); +/** + * Returns true if platform supports recycle bin, otherwise false. + * Used to control which UI tooltip is shown for deletion. + */ +bool dr_cantrash(); +// Functions the same as cstdio remove except path must be UTF-8 encoded. +int dr_remove(const char *path); + // rename a file and delete eventually existing file new_utf8 -void dr_rename( const char *existing_utf8, const char *new_utf8 ); +int dr_rename( const char *existing_utf8, const char *new_utf8 ); +// Functions the same as chdir except path must be UTF-8 encoded. +int dr_chdir(const char *path); + +// Functions the same as getcwd except path must be UTF-8 encoded. +char *dr_getcwd(char *buf, size_t size); + +// Functions the same as fopen except filename must be UTF-8 encoded. +FILE *dr_fopen(const char *filename, const char *mode); + +// Functions the same as gzopen except path must be UTF-8 encoded. +gzFile dr_gzopen(const char *path, const char *mode); + +// Functions the same as stat except path must be UTF-8 encoded. +int dr_stat(const char *path, struct stat *buf); + /* query home directory */ char const* dr_query_homedir(); Index: simutrans/trunk/simutrans/history.txt =================================================================== --- simutrans/trunk/simutrans/history.txt (revision 8300) +++ simutrans/trunk/simutrans/history.txt (working copy) @@ -10,6 +10,7 @@ offset (of pedestrian image relative to right tile boundary, 0..255, default 20, 0 = on the right edge of tile, 128 = on center line of tile FIX: corrected container UI component focus logic (fixes http://forum.simutrans.com/index.php?topic=17277) FIX: added redraw logic for field removal (fixes http://forum.simutrans.com/index.php?topic=17308) + FIX: added Unicode file path support for Windows builds. Release of 120.2.2: (r8163 on 31-3-2017): ADD: Name filter in depot window Index: simutrans/trunk/utils/log.cc =================================================================== --- simutrans/trunk/utils/log.cc (revision 8300) +++ simutrans/trunk/utils/log.cc (working copy) @@ -407,7 +407,7 @@ tee = NULL; #endif } else { - log = fopen(logfilename,"wb"); + log = dr_fopen(logfilename,"wb"); if(log == NULL) { fprintf(stderr,"log_t::log_t: can't open file '%s' for writing\n", logfilename);