2 /*
3 * System abstraction utility routines
4 *
5 * Authors:
6 * Jon A. Cruz <jon@joncruz.org>
7 *
8 * Copyright (C) 2004-2005 Authors
9 *
10 * Released under GNU GPL, read the file 'COPYING' for more information
11 */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
18 #include <glib/gutils.h>
19 #if GLIB_CHECK_VERSION(2,6,0)
20 #include <glib/gstdio.h>
21 #endif
22 #include <glibmm/ustring.h>
23 #include <gtk/gtkmessagedialog.h>
25 #include "prefs-utils.h"
26 #include "sys.h"
28 #ifdef WIN32
30 // For now to get at is_os_wide().
31 #include "extension/internal/win32.h"
32 using Inkscape::Extension::Internal::PrintWin32;
34 #endif
36 //#define INK_DUMP_FILENAME_CONV 1
37 #undef INK_DUMP_FILENAME_CONV
39 //#define INK_DUMP_FOPEN 1
40 #undef INK_DUMP_FOPEN
42 void dump_str(gchar const *str, gchar const *prefix);
43 void dump_ustr(Glib::ustring const &ustr);
45 extern guint update_in_progress;
48 #define DEBUG_MESSAGE(key, ...) \
49 {\
50 gint dump = prefs_get_int_attribute_limited("options.bulia", #key, 0, 0, 1);\
51 gint dumpD = prefs_get_int_attribute_limited("options.bulia", #key"D", 0, 0, 1);\
52 gint dumpD2 = prefs_get_int_attribute_limited("options.bulia", #key"D2", 0, 0, 1);\
53 dumpD &= ( (update_in_progress == 0) || dumpD2 );\
54 if ( dump )\
55 {\
56 g_message( __VA_ARGS__ );\
57 \
58 }\
59 if ( dumpD )\
60 {\
61 GtkWidget *dialog = gtk_message_dialog_new(NULL,\
62 GTK_DIALOG_DESTROY_WITH_PARENT, \
63 GTK_MESSAGE_INFO, \
64 GTK_BUTTONS_OK, \
65 __VA_ARGS__ \
66 );\
67 g_signal_connect_swapped(dialog, "response",\
68 G_CALLBACK(gtk_widget_destroy), \
69 dialog); \
70 gtk_widget_show_all( dialog );\
71 }\
72 }
77 void Inkscape::IO::dump_fopen_call( char const *utf8name, char const *id )
78 {
79 #ifdef INK_DUMP_FOPEN
80 Glib::ustring str;
81 for ( int i = 0; utf8name[i]; i++ )
82 {
83 if ( utf8name[i] == '\\' )
84 {
85 str += "\\\\";
86 }
87 else if ( (utf8name[i] >= 0x20) && ((0x0ff & utf8name[i]) <= 0x7f) )
88 {
89 str += utf8name[i];
90 }
91 else
92 {
93 gchar tmp[32];
94 g_snprintf( tmp, sizeof(tmp), "\\x%02x", (0x0ff & utf8name[i]) );
95 str += tmp;
96 }
97 }
98 g_message( "fopen call %s for [%s]", id, str.data() );
99 #else
100 (void)utf8name;
101 (void)id;
102 #endif
103 }
105 FILE *Inkscape::IO::fopen_utf8name( char const *utf8name, char const *mode )
106 {
107 static gint counter = 0;
108 FILE* fp = NULL;
110 DEBUG_MESSAGE( dumpOne, "entering fopen_utf8name( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
112 #ifndef WIN32
113 DEBUG_MESSAGE( dumpOne, " STEP 0 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
114 gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL );
115 if ( filename )
116 {
117 DEBUG_MESSAGE( dumpOne, " STEP 1 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
118 fp = std::fopen(filename, mode);
119 DEBUG_MESSAGE( dumpOne, " STEP 2 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
120 g_free(filename);
121 DEBUG_MESSAGE( dumpOne, " STEP 3 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
122 filename = 0;
123 }
124 #else
125 Glib::ustring how( mode );
126 how.append("b");
127 DEBUG_MESSAGE( dumpOne, " calling is_os_wide() ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
129 fp = g_fopen(utf8name, how.c_str());
130 #endif
132 DEBUG_MESSAGE( dumpOne, "leaving fopen_utf8name( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
134 return fp;
135 }
138 int Inkscape::IO::mkdir_utf8name( char const *utf8name )
139 {
140 static gint counter = 0;
141 int retval = -1;
143 DEBUG_MESSAGE( dumpMk, "entering mkdir_utf8name( '%s' )[%d]", utf8name, (counter++) );
145 #ifndef WIN32
146 DEBUG_MESSAGE( dumpMk, " STEP 0 ( '%s' )[%d]", utf8name, (counter++) );
147 gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL );
148 if ( filename )
149 {
150 DEBUG_MESSAGE( dumpMk, " STEP 1 ( '%s' )[%d]", utf8name, (counter++) );
151 retval = ::mkdir(filename, S_IRWXU | S_IRGRP | S_IXGRP);
152 DEBUG_MESSAGE( dumpMk, " STEP 2 ( '%s' )[%d]", utf8name, (counter++) );
153 g_free(filename);
154 DEBUG_MESSAGE( dumpMk, " STEP 3 ( '%s' )[%d]", utf8name, (counter++) );
155 filename = 0;
156 }
157 #else
158 DEBUG_MESSAGE( dumpMk, " calling is_os_wide() ( '%s' )[%d]", utf8name, (counter++) );
160 // Mode should be ingnored inside of glib on the way in
161 retval = g_mkdir( utf8name, 0 );
162 #endif
164 DEBUG_MESSAGE( dumpMk, "leaving mkdir_utf8name( '%s' )[%d]", utf8name, (counter++) );
166 return retval;
167 }
169 bool Inkscape::IO::file_test( char const *utf8name, GFileTest test )
170 {
171 bool exists = false;
173 if ( utf8name ) {
174 gchar *filename = NULL;
175 if (utf8name && !g_utf8_validate(utf8name, -1, NULL)) {
176 /* FIXME: Trying to guess whether or not a filename is already in utf8 is unreliable.
177 If any callers pass non-utf8 data (e.g. using g_get_home_dir), then change caller to
178 use simple g_file_test. Then add g_return_val_if_fail(g_utf_validate(...), false)
179 to beginning of this function. */
180 filename = g_strdup(utf8name);
181 // Looks like g_get_home_dir isn't safe.
182 //g_warning("invalid UTF-8 detected internally. HUNT IT DOWN AND KILL IT!!!");
183 } else {
184 filename = g_filename_from_utf8 ( utf8name, -1, NULL, NULL, NULL );
185 }
186 if ( filename ) {
187 exists = g_file_test (filename, test);
188 g_free(filename);
189 filename = NULL;
190 } else {
191 g_warning( "Unable to convert filename in IO:file_test" );
192 }
193 }
195 return exists;
196 }
198 /** Wrapper around g_dir_open, but taking a utf8name as first argument. */
199 GDir *
200 Inkscape::IO::dir_open(gchar const *const utf8name, guint const flags, GError **const error)
201 {
202 gchar *const opsys_name = g_filename_from_utf8(utf8name, -1, NULL, NULL, error);
203 if (opsys_name) {
204 GDir *ret = g_dir_open(opsys_name, flags, error);
205 g_free(opsys_name);
206 return ret;
207 } else {
208 return NULL;
209 }
210 }
212 /**
213 * Like g_dir_read_name, but returns a utf8name (which must be freed, unlike g_dir_read_name).
214 *
215 * N.B. Skips over any dir entries that fail to convert to utf8.
216 */
217 gchar *
218 Inkscape::IO::dir_read_utf8name(GDir *dir)
219 {
220 for (;;) {
221 gchar const *const opsys_name = g_dir_read_name(dir);
222 if (!opsys_name) {
223 return NULL;
224 }
225 gchar *utf8_name = g_filename_to_utf8(opsys_name, -1, NULL, NULL, NULL);
226 if (utf8_name) {
227 return utf8_name;
228 }
229 }
230 }
233 gchar* Inkscape::IO::locale_to_utf8_fallback( const gchar *opsysstring,
234 gssize len,
235 gsize *bytes_read,
236 gsize *bytes_written,
237 GError **error )
238 {
239 gchar *result = NULL;
240 if ( opsysstring ) {
241 gchar *newFileName = g_locale_to_utf8( opsysstring, len, bytes_read, bytes_written, error );
242 if ( newFileName ) {
243 if ( !g_utf8_validate(newFileName, -1, NULL) ) {
244 g_warning( "input filename did not yield UTF-8" );
245 g_free( newFileName );
246 } else {
247 result = newFileName;
248 }
249 newFileName = 0;
250 } else if ( g_utf8_validate(opsysstring, -1, NULL) ) {
251 // This *might* be a case that we want
252 // g_warning( "input failed filename->utf8, fell back to original" );
253 // TODO handle cases when len >= 0
254 result = g_strdup( opsysstring );
255 } else {
256 gchar const *charset = 0;
257 g_get_charset(&charset);
258 g_warning( "input filename conversion failed for file with locale charset '%s'", charset );
259 }
260 }
261 return result;
262 }
265 gchar* Inkscape::IO::sanitizeString( gchar const * str )
266 {
267 gchar *result = NULL;
268 if ( str ) {
269 if ( g_utf8_validate(str, -1, NULL) ) {
270 result = g_strdup(str);
271 } else {
272 guchar scratch[8];
273 Glib::ustring buf;
274 guchar const *ptr = (guchar const*)str;
275 while ( *ptr )
276 {
277 if ( *ptr == '\\' )
278 {
279 buf.append("\\\\");
280 } else if ( *ptr < 0x80 ) {
281 buf += (char)(*ptr);
282 } else {
283 g_snprintf((gchar*)scratch, sizeof(scratch), "\\x%02x", *ptr);
284 buf.append((const char*)scratch);
285 }
286 ptr++;
287 }
288 result = g_strdup(buf.c_str());
289 }
290 }
291 return result;
292 }
294 /*
295 Local Variables:
296 mode:c++
297 c-file-style:"stroustrup"
298 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
299 indent-tabs-mode:nil
300 fill-column:99
301 End:
302 */
303 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :