diff options
Diffstat (limited to '')
-rw-r--r-- | src/io/sys.cpp | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/src/io/sys.cpp b/src/io/sys.cpp new file mode 100644 index 0000000..ee1956f --- /dev/null +++ b/src/io/sys.cpp @@ -0,0 +1,361 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * System abstraction utility routines + * + * Authors: + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2004-2005 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + + +#include <fstream> +#ifdef _WIN32 +#include <fcntl.h> +#include <io.h> +#endif + +#include <glib.h> +#include <glib/gstdio.h> +#include <glibmm/ustring.h> +#include <gtk/gtk.h> + +#include "preferences.h" +#include "sys.h" + +//#define INK_DUMP_FILENAME_CONV 1 +#undef INK_DUMP_FILENAME_CONV + +//#define INK_DUMP_FOPEN 1 +#undef INK_DUMP_FOPEN + +void dump_str(gchar const *str, gchar const *prefix); +void dump_ustr(Glib::ustring const &ustr); + +extern guint update_in_progress; + + +void Inkscape::IO::dump_fopen_call( char const *utf8name, char const *id ) +{ +#ifdef INK_DUMP_FOPEN + Glib::ustring str; + for ( int i = 0; utf8name[i]; i++ ) + { + if ( utf8name[i] == '\\' ) + { + str += "\\\\"; + } + else if ( (utf8name[i] >= 0x20) && ((0x0ff & utf8name[i]) <= 0x7f) ) + { + str += utf8name[i]; + } + else + { + gchar tmp[32]; + g_snprintf( tmp, sizeof(tmp), "\\x%02x", (0x0ff & utf8name[i]) ); + str += tmp; + } + } + g_message( "fopen call %s for [%s]", id, str.data() ); +#else + (void)utf8name; + (void)id; +#endif +} + +FILE *Inkscape::IO::fopen_utf8name( char const *utf8name, char const *mode ) +{ + FILE* fp = nullptr; + + if (Glib::ustring( utf8name ) == Glib::ustring("-")) { + // user requests to use pipes + + Glib::ustring how( mode ); + if ( how.find("w") != Glib::ustring::npos ) { +#ifdef _WIN32 + setmode(fileno(stdout), O_BINARY); +#endif + return stdout; + } else { + return stdin; + } + } + + gchar *filename = g_filename_from_utf8( utf8name, -1, nullptr, nullptr, nullptr ); + if ( filename ) + { + // ensure we open the file in binary mode (not needed in POSIX but doesn't hurt either) + Glib::ustring how( mode ); + if ( how.find("b") == Glib::ustring::npos ) + { + how.append("b"); + } + // when opening a file for writing: create parent directories if they don't exist already + if ( how.find("w") != Glib::ustring::npos ) + { + gchar *dirname = g_path_get_dirname(utf8name); + if (g_mkdir_with_parents(dirname, 0777)) { + g_warning("Could not create directory '%s'", dirname); + } + g_free(dirname); + } + fp = g_fopen(filename, how.c_str()); + g_free(filename); + filename = nullptr; + } + return fp; +} + + +int Inkscape::IO::mkdir_utf8name( char const *utf8name ) +{ + int retval = -1; + gchar *filename = g_filename_from_utf8( utf8name, -1, nullptr, nullptr, nullptr ); + if ( filename ) + { + retval = g_mkdir(filename, S_IRWXU | S_IRGRP | S_IXGRP); // The mode argument is ignored on Windows. + g_free(filename); + filename = nullptr; + } + return retval; +} + +bool Inkscape::IO::file_test( char const *utf8name, GFileTest test ) +{ + bool exists = false; + + // in case the file to check is a pipe it doesn't need to exist + if (g_strcmp0(utf8name, "-") == 0 && G_FILE_TEST_IS_REGULAR) + return true; + + if ( utf8name ) { + gchar *filename = nullptr; + if (utf8name && !g_utf8_validate(utf8name, -1, nullptr)) { + /* FIXME: Trying to guess whether or not a filename is already in utf8 is unreliable. + If any callers pass non-utf8 data (e.g. using g_get_home_dir), then change caller to + use simple g_file_test. Then add g_return_val_if_fail(g_utf_validate(...), false) + to beginning of this function. */ + filename = g_strdup(utf8name); + // Looks like g_get_home_dir isn't safe. + //g_warning("invalid UTF-8 detected internally. HUNT IT DOWN AND KILL IT!!!"); + } else { + filename = g_filename_from_utf8 ( utf8name, -1, nullptr, nullptr, nullptr ); + } + if ( filename ) { + exists = g_file_test (filename, test); + g_free(filename); + filename = nullptr; + } else { + g_warning( "Unable to convert filename in IO:file_test" ); + } + } + + return exists; +} + +bool Inkscape::IO::file_is_writable( char const *utf8name) +{ + bool success = true; + + if ( utf8name) { + gchar *filename = nullptr; + if (utf8name && !g_utf8_validate(utf8name, -1, nullptr)) { + /* FIXME: Trying to guess whether or not a filename is already in utf8 is unreliable. + If any callers pass non-utf8 data (e.g. using g_get_home_dir), then change caller to + use simple g_file_test. Then add g_return_val_if_fail(g_utf_validate(...), false) + to beginning of this function. */ + filename = g_strdup(utf8name); + // Looks like g_get_home_dir isn't safe. + //g_warning("invalid UTF-8 detected internally. HUNT IT DOWN AND KILL IT!!!"); + } else { + filename = g_filename_from_utf8 ( utf8name, -1, nullptr, nullptr, nullptr ); + } + if ( filename ) { + GStatBuf st; + if (g_file_test (filename, G_FILE_TEST_EXISTS)){ + if (g_lstat (filename, &st) == 0) { + success = ((st.st_mode & S_IWRITE) != 0); + } + } + g_free(filename); + filename = nullptr; + } else { + g_warning( "Unable to convert filename in IO:file_test" ); + } + } + + return success; +} + +/**Checks if directory of file exists, useful + * because inkscape doesn't create directories.*/ +bool Inkscape::IO::file_directory_exists( char const *utf8name ){ + bool exists = true; + + if ( utf8name) { + gchar *filename = nullptr; + if (utf8name && !g_utf8_validate(utf8name, -1, nullptr)) { + /* FIXME: Trying to guess whether or not a filename is already in utf8 is unreliable. + If any callers pass non-utf8 data (e.g. using g_get_home_dir), then change caller to + use simple g_file_test. Then add g_return_val_if_fail(g_utf_validate(...), false) + to beginning of this function. */ + filename = g_strdup(utf8name); + // Looks like g_get_home_dir isn't safe. + //g_warning("invalid UTF-8 detected internally. HUNT IT DOWN AND KILL IT!!!"); + } else { + filename = g_filename_from_utf8 ( utf8name, -1, nullptr, nullptr, nullptr ); + } + if ( filename ) { + gchar *dirname = g_path_get_dirname(filename); + exists = Inkscape::IO::file_test( dirname, G_FILE_TEST_EXISTS); + g_free(filename); + g_free(dirname); + filename = nullptr; + dirname = nullptr; + } else { + g_warning( "Unable to convert filename in IO:file_test" ); + } + } + + return exists; + +} + +/** Wrapper around g_dir_open, but taking a utf8name as first argument. */ +GDir * +Inkscape::IO::dir_open(gchar const *const utf8name, guint const flags, GError **const error) +{ + gchar *const opsys_name = g_filename_from_utf8(utf8name, -1, nullptr, nullptr, error); + if (opsys_name) { + GDir *ret = g_dir_open(opsys_name, flags, error); + g_free(opsys_name); + return ret; + } else { + return nullptr; + } +} + +/** + * Like g_dir_read_name, but returns a utf8name (which must be freed, unlike g_dir_read_name). + * + * N.B. Skips over any dir entries that fail to convert to utf8. + */ +gchar * +Inkscape::IO::dir_read_utf8name(GDir *dir) +{ + for (;;) { + gchar const *const opsys_name = g_dir_read_name(dir); + if (!opsys_name) { + return nullptr; + } + gchar *utf8_name = g_filename_to_utf8(opsys_name, -1, nullptr, nullptr, nullptr); + if (utf8_name) { + return utf8_name; + } + } +} + + +gchar* Inkscape::IO::locale_to_utf8_fallback( const gchar *opsysstring, + gssize len, + gsize *bytes_read, + gsize *bytes_written, + GError **error ) +{ + gchar *result = nullptr; + if ( opsysstring ) { + gchar *newFileName = g_locale_to_utf8( opsysstring, len, bytes_read, bytes_written, error ); + if ( newFileName ) { + if ( !g_utf8_validate(newFileName, -1, nullptr) ) { + g_warning( "input filename did not yield UTF-8" ); + g_free( newFileName ); + } else { + result = newFileName; + } + newFileName = nullptr; + } else if ( g_utf8_validate(opsysstring, -1, nullptr) ) { + // This *might* be a case that we want + // g_warning( "input failed filename->utf8, fell back to original" ); + // TODO handle cases when len >= 0 + result = g_strdup( opsysstring ); + } else { + gchar const *charset = nullptr; + g_get_charset(&charset); + g_warning( "input filename conversion failed for file with locale charset '%s'", charset ); + } + } + return result; +} + +void +Inkscape::IO::spawn_async_with_pipes( const std::string& working_directory, + const Glib::ArrayHandle<std::string>& argv, + Glib::SpawnFlags flags, + const sigc::slot<void>& child_setup, + Glib::Pid* child_pid, + int* standard_input, + int* standard_output, + int* standard_error) +{ + Glib::spawn_async_with_pipes(working_directory, + argv, + flags, + child_setup, + child_pid, + standard_input, + standard_output, + standard_error); +} + + +gchar* Inkscape::IO::sanitizeString( gchar const * str ) +{ + gchar *result = nullptr; + if ( str ) { + if ( g_utf8_validate(str, -1, nullptr) ) { + result = g_strdup(str); + } else { + guchar scratch[8]; + Glib::ustring buf; + guchar const *ptr = (guchar const*)str; + while ( *ptr ) + { + if ( *ptr == '\\' ) + { + buf.append("\\\\"); + } else if ( *ptr < 0x80 ) { + buf += (char)(*ptr); + } else { + g_snprintf((gchar*)scratch, sizeof(scratch), "\\x%02x", *ptr); + buf.append((const char*)scratch); + } + ptr++; + } + result = g_strdup(buf.c_str()); + } + } + return result; +} + +/* + * Returns the file extension of a path/filename + */ +Glib::ustring Inkscape::IO::get_file_extension(Glib::ustring path) +{ + Glib::ustring::size_type period_location = path.find_last_of("."); + return path.substr(period_location); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : |