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 #endif
100 }
102 FILE *Inkscape::IO::fopen_utf8name( char const *utf8name, char const *mode )
103 {
104 static gint counter = 0;
105 FILE* fp = NULL;
107 DEBUG_MESSAGE( dumpOne, "entering fopen_utf8name( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
109 #ifndef WIN32
110 DEBUG_MESSAGE( dumpOne, " STEP 0 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
111 gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL );
112 if ( filename )
113 {
114 DEBUG_MESSAGE( dumpOne, " STEP 1 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
115 fp = std::fopen(filename, mode);
116 DEBUG_MESSAGE( dumpOne, " STEP 2 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
117 g_free(filename);
118 DEBUG_MESSAGE( dumpOne, " STEP 3 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
119 filename = 0;
120 }
121 #else
122 Glib::ustring how( mode );
123 how.append("b");
124 DEBUG_MESSAGE( dumpOne, " calling is_os_wide() ( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
126 fp = g_fopen(utf8name, how.c_str());
127 #endif
129 DEBUG_MESSAGE( dumpOne, "leaving fopen_utf8name( '%s', '%s' )[%d]", utf8name, mode, (counter++) );
131 return fp;
132 }
135 int Inkscape::IO::mkdir_utf8name( char const *utf8name )
136 {
137 static gint counter = 0;
138 int retval = -1;
140 DEBUG_MESSAGE( dumpMk, "entering mkdir_utf8name( '%s' )[%d]", utf8name, (counter++) );
142 #ifndef WIN32
143 DEBUG_MESSAGE( dumpMk, " STEP 0 ( '%s' )[%d]", utf8name, (counter++) );
144 gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL );
145 if ( filename )
146 {
147 DEBUG_MESSAGE( dumpMk, " STEP 1 ( '%s' )[%d]", utf8name, (counter++) );
148 retval = ::mkdir(filename, S_IRWXU | S_IRGRP | S_IXGRP);
149 DEBUG_MESSAGE( dumpMk, " STEP 2 ( '%s' )[%d]", utf8name, (counter++) );
150 g_free(filename);
151 DEBUG_MESSAGE( dumpMk, " STEP 3 ( '%s' )[%d]", utf8name, (counter++) );
152 filename = 0;
153 }
154 #else
155 DEBUG_MESSAGE( dumpMk, " calling is_os_wide() ( '%s' )[%d]", utf8name, (counter++) );
157 // Mode should be ingnored inside of glib on the way in
158 retval = g_mkdir( utf8name, 0 );
159 #endif
161 DEBUG_MESSAGE( dumpMk, "leaving mkdir_utf8name( '%s' )[%d]", utf8name, (counter++) );
163 return retval;
164 }
166 bool Inkscape::IO::file_test( char const *utf8name, GFileTest test )
167 {
168 bool exists = false;
170 if ( utf8name ) {
171 gchar *filename = NULL;
172 if (utf8name && !g_utf8_validate(utf8name, -1, NULL)) {
173 /* FIXME: Trying to guess whether or not a filename is already in utf8 is unreliable.
174 If any callers pass non-utf8 data (e.g. using g_get_home_dir), then change caller to
175 use simple g_file_test. Then add g_return_val_if_fail(g_utf_validate(...), false)
176 to beginning of this function. */
177 filename = g_strdup(utf8name);
178 // Looks like g_get_home_dir isn't safe.
179 //g_warning("invalid UTF-8 detected internally. HUNT IT DOWN AND KILL IT!!!");
180 } else {
181 filename = g_filename_from_utf8 ( utf8name, -1, NULL, NULL, NULL );
182 }
183 if ( filename ) {
184 exists = g_file_test (filename, test);
185 g_free(filename);
186 filename = NULL;
187 } else {
188 g_warning( "Unable to convert filename in IO:file_test" );
189 }
190 }
192 return exists;
193 }
195 /** Wrapper around g_dir_open, but taking a utf8name as first argument. */
196 GDir *
197 Inkscape::IO::dir_open(gchar const *const utf8name, guint const flags, GError **const error)
198 {
199 gchar *const opsys_name = g_filename_from_utf8(utf8name, -1, NULL, NULL, error);
200 if (opsys_name) {
201 GDir *ret = g_dir_open(opsys_name, flags, error);
202 g_free(opsys_name);
203 return ret;
204 } else {
205 return NULL;
206 }
207 }
209 /**
210 * Like g_dir_read_name, but returns a utf8name (which must be freed, unlike g_dir_read_name).
211 *
212 * N.B. Skips over any dir entries that fail to convert to utf8.
213 */
214 gchar *
215 Inkscape::IO::dir_read_utf8name(GDir *dir)
216 {
217 for (;;) {
218 gchar const *const opsys_name = g_dir_read_name(dir);
219 if (!opsys_name) {
220 return NULL;
221 }
222 gchar *utf8_name = g_filename_to_utf8(opsys_name, -1, NULL, NULL, NULL);
223 if (utf8_name) {
224 return utf8_name;
225 }
226 }
227 }
230 gchar* Inkscape::IO::locale_to_utf8_fallback( const gchar *opsysstring,
231 gssize len,
232 gsize *bytes_read,
233 gsize *bytes_written,
234 GError **error )
235 {
236 gchar *result = NULL;
237 if ( opsysstring ) {
238 gchar *newFileName = g_locale_to_utf8( opsysstring, len, bytes_read, bytes_written, error );
239 if ( newFileName ) {
240 if ( !g_utf8_validate(newFileName, -1, NULL) ) {
241 g_warning( "input filename did not yield UTF-8" );
242 g_free( newFileName );
243 } else {
244 result = newFileName;
245 }
246 newFileName = 0;
247 } else if ( g_utf8_validate(opsysstring, -1, NULL) ) {
248 // This *might* be a case that we want
249 // g_warning( "input failed filename->utf8, fell back to original" );
250 // TODO handle cases when len >= 0
251 result = g_strdup( opsysstring );
252 } else {
253 gchar const *charset = 0;
254 g_get_charset(&charset);
255 g_warning( "input filename conversion failed for file with locale charset '%s'", charset );
256 }
257 }
258 return result;
259 }
262 gchar* Inkscape::IO::sanitizeString( gchar const * str )
263 {
264 gchar *result = NULL;
265 if ( str ) {
266 if ( g_utf8_validate(str, -1, NULL) ) {
267 result = g_strdup(str);
268 } else {
269 guchar scratch[8];
270 Glib::ustring buf;
271 guchar const *ptr = (guchar const*)str;
272 while ( *ptr )
273 {
274 if ( *ptr == '\\' )
275 {
276 buf.append("\\\\");
277 } else if ( *ptr < 0x80 ) {
278 buf += (char)(*ptr);
279 } else {
280 g_snprintf((gchar*)scratch, sizeof(scratch), "\\x%02x", *ptr);
281 buf.append((const char*)scratch);
282 }
283 ptr++;
284 }
285 result = g_strdup(buf.c_str());
286 }
287 }
288 return result;
289 }
291 /*
292 Local Variables:
293 mode:c++
294 c-file-style:"stroustrup"
295 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
296 indent-tabs-mode:nil
297 fill-column:99
298 End:
299 */
300 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :