1 /**
2 * Our base String stream classes. We implement these to
3 * be based on Glib::ustring
4 *
5 * Authors:
6 * Bob Jamison <rjamison@titan.com>
7 *
8 * Copyright (C) 2004 Inkscape.org
9 *
10 * Released under GNU GPL, read the file 'COPYING' for more information
11 */
14 #include "uristream.h"
15 #include "sys.h"
17 #ifdef WIN32
18 // For now to get at is_os_wide().
19 # include "extension/internal/win32.h"
20 using Inkscape::Extension::Internal::PrintWin32;
21 #endif
24 namespace Inkscape
25 {
26 namespace IO
27 {
29 /*
30 * URI scheme types
31 */
32 #define SCHEME_NONE 0
33 #define SCHEME_FILE 1
34 #define SCHEME_DATA 2
36 /*
37 * A temporary modification of Jon Cruz's portable fopen().
38 * Simplified a bit, since we will always use binary
39 */
41 #define FILE_READ 1
42 #define FILE_WRITE 2
44 static FILE *fopen_utf8name( char const *utf8name, int mode )
45 {
46 FILE *fp = NULL;
47 if (!utf8name)
48 {
49 return NULL;
50 }
51 if (mode!=FILE_READ && mode!=FILE_WRITE)
52 {
53 return NULL;
54 }
56 #ifndef WIN32
57 gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL );
58 if ( filename ) {
59 if (mode == FILE_READ)
60 fp = std::fopen(filename, "rb");
61 else
62 fp = std::fopen(filename, "wb");
63 g_free(filename);
64 }
65 #else
66 if ( PrintWin32::is_os_wide() ) {
67 gunichar2 *wideName = g_utf8_to_utf16( utf8name, -1, NULL, NULL, NULL );
68 if ( wideName ) {
69 if (mode == FILE_READ)
70 fp = _wfopen( (wchar_t*)wideName, L"rb" );
71 else
72 fp = _wfopen( (wchar_t*)wideName, L"wb" );
73 g_free( wideName );
74 } else {
75 gchar *safe = Inkscape::IO::sanitizeString(utf8name);
76 g_message("Unable to convert filename from UTF-8 to UTF-16 [%s]", safe);
77 g_free(safe);
78 }
79 } else {
80 gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL );
81 if ( filename ) {
82 if (mode == FILE_READ)
83 fp = std::fopen(filename, "rb");
84 else
85 fp = std::fopen(filename, "wb");
86 g_free(filename);
87 }
88 }
89 #endif
91 return fp;
92 }
96 //#########################################################################
97 //# U R I I N P U T S T R E A M / R E A D E R
98 //#########################################################################
101 /**
102 *
103 */
104 UriInputStream::UriInputStream(Inkscape::URI &source)
105 throw (StreamException): uri(source)
106 {
107 //get information from uri
108 char *schemestr = (char *) uri.getScheme();
109 scheme = SCHEME_FILE;
110 if (!schemestr || strncmp("file", schemestr, 4)==0)
111 scheme = SCHEME_FILE;
112 else if (strncmp("data", schemestr, 4)==0)
113 scheme = SCHEME_DATA;
114 //printf("in schemestr:'%s' scheme:'%d'\n", schemestr, scheme);
115 char *cpath = NULL;
117 switch (scheme) {
119 case SCHEME_FILE:
120 cpath = (char *) uri.toNativeFilename();
121 //printf("in cpath:'%s'\n", cpath);
122 inf = fopen_utf8name(cpath, FILE_READ);
123 //inf = fopen(cpath, "rb");
124 g_free(cpath);
125 if (!inf) {
126 Glib::ustring err = "UriInputStream cannot open file ";
127 err += cpath;
128 throw StreamException(err);
129 }
130 break;
132 case SCHEME_DATA:
133 data = (unsigned char *) uri.getPath();
134 //printf("in data:'%s'\n", data);
135 dataPos = 0;
136 dataLen = strlen((const char *)data);
137 break;
139 }
140 closed = false;
141 }
143 /**
144 *
145 */
146 UriInputStream::UriInputStream(FILE *source, Inkscape::URI &uri)
147 throw (StreamException): inf(source),
148 uri(uri)
149 {
150 scheme = SCHEME_FILE;
151 if (!inf) {
152 Glib::ustring err = "UriInputStream passed NULL";
153 throw StreamException(err);
154 }
155 closed = false;
156 }
158 /**
159 *
160 */
161 UriInputStream::~UriInputStream() throw(StreamException)
162 {
163 close();
164 }
166 /**
167 * Returns the number of bytes that can be read (or skipped over) from
168 * this input stream without blocking by the next caller of a method for
169 * this input stream.
170 */
171 int UriInputStream::available() throw(StreamException)
172 {
173 return 0;
174 }
177 /**
178 * Closes this input stream and releases any system resources
179 * associated with the stream.
180 */
181 void UriInputStream::close() throw(StreamException)
182 {
183 if (closed)
184 return;
186 switch (scheme) {
188 case SCHEME_FILE:
189 if (!inf)
190 return;
191 fflush(inf);
192 fclose(inf);
193 inf=NULL;
194 break;
196 case SCHEME_DATA:
197 //do nothing
198 break;
200 }//switch
202 closed = true;
203 }
205 /**
206 * Reads the next byte of data from the input stream. -1 if EOF
207 */
208 int UriInputStream::get() throw(StreamException)
209 {
210 int retVal = -1;
211 if (!closed)
212 {
213 switch (scheme) {
215 case SCHEME_FILE:
216 if (!inf || feof(inf))
217 {
218 retVal = -1;
219 }
220 else
221 {
222 retVal = fgetc(inf);
223 }
224 break;
226 case SCHEME_DATA:
227 if (dataPos >= dataLen)
228 {
229 retVal = -1;
230 }
231 else
232 {
233 retVal = data[dataPos++];
234 }
235 break;
236 }//switch
237 }
238 return retVal;
239 }
246 /**
247 *
248 */
249 UriReader::UriReader(Inkscape::URI &uri)
250 throw (StreamException)
251 {
252 inputStream = new UriInputStream(uri);
253 }
255 /**
256 *
257 */
258 UriReader::~UriReader() throw (StreamException)
259 {
260 delete inputStream;
261 }
263 /**
264 *
265 */
266 int UriReader::available() throw(StreamException)
267 {
268 return inputStream->available();
269 }
271 /**
272 *
273 */
274 void UriReader::close() throw(StreamException)
275 {
276 inputStream->close();
277 }
279 /**
280 *
281 */
282 gunichar UriReader::get() throw(StreamException)
283 {
284 gunichar ch = (gunichar)inputStream->get();
285 return ch;
286 }
289 //#########################################################################
290 //# U R I O U T P U T S T R E A M / W R I T E R
291 //#########################################################################
293 /**
294 * Temporary kludge
295 */
296 UriOutputStream::UriOutputStream(FILE* fp, Inkscape::URI &destination)
297 throw (StreamException): closed(false),
298 ownsFile(false),
299 outf(fp),
300 uri(destination),
301 scheme(SCHEME_FILE)
302 {
303 if (!outf) {
304 Glib::ustring err = "UriOutputStream given null file ";
305 throw StreamException(err);
306 }
307 }
309 /**
310 *
311 */
312 UriOutputStream::UriOutputStream(Inkscape::URI &destination)
313 throw (StreamException): closed(false),
314 ownsFile(true),
315 outf(NULL),
316 uri(destination),
317 scheme(SCHEME_FILE)
318 {
319 //get information from uri
320 char *schemestr = (char *) uri.getScheme();
321 if (!schemestr || strncmp("file", schemestr, 4)==0)
322 scheme = SCHEME_FILE;
323 else if (strncmp("data", schemestr, 4)==0)
324 scheme = SCHEME_DATA;
325 //printf("out schemestr:'%s' scheme:'%d'\n", schemestr, scheme);
326 char *cpath = NULL;
328 switch (scheme) {
330 case SCHEME_FILE:
331 cpath = (char *) uri.toNativeFilename();
332 //printf("out path:'%s'\n", cpath);
333 outf = fopen_utf8name(cpath, FILE_WRITE);
334 //outf = fopen(cpath, "wb");
335 g_free(cpath);
336 if (!outf) {
337 Glib::ustring err = "UriOutputStream cannot open file ";
338 err += cpath;
339 throw StreamException(err);
340 }
341 break;
343 case SCHEME_DATA:
344 data = "data:";
345 break;
347 }//switch
348 }
351 /**
352 *
353 */
354 UriOutputStream::~UriOutputStream() throw(StreamException)
355 {
356 close();
357 }
359 /**
360 * Closes this output stream and releases any system resources
361 * associated with this stream.
362 */
363 void UriOutputStream::close() throw(StreamException)
364 {
365 if (closed)
366 return;
368 switch (scheme) {
370 case SCHEME_FILE:
371 if (!outf)
372 return;
373 fflush(outf);
374 if ( ownsFile )
375 fclose(outf);
376 outf=NULL;
377 break;
379 case SCHEME_DATA:
380 uri = URI(data.raw().c_str());
381 break;
383 }//switch
385 closed = true;
386 }
388 /**
389 * Flushes this output stream and forces any buffered output
390 * bytes to be written out.
391 */
392 void UriOutputStream::flush() throw(StreamException)
393 {
394 if (closed)
395 return;
397 switch (scheme) {
399 case SCHEME_FILE:
400 if (!outf)
401 return;
402 fflush(outf);
403 break;
405 case SCHEME_DATA:
406 //nothing
407 break;
409 }//switch
411 }
413 /**
414 * Writes the specified byte to this output stream.
415 */
416 void UriOutputStream::put(int ch) throw(StreamException)
417 {
418 if (closed)
419 return;
421 unsigned char uch;
422 gunichar gch;
424 switch (scheme) {
426 case SCHEME_FILE:
427 if (!outf)
428 return;
429 uch = (unsigned char)(ch & 0xff);
430 fputc(uch, outf);
431 //fwrite(uch, 1, 1, outf);
432 break;
434 case SCHEME_DATA:
435 gch = (gunichar) ch;
436 data.push_back(gch);
437 break;
439 }//switch
441 }
447 /**
448 *
449 */
450 UriWriter::UriWriter(Inkscape::URI &uri)
451 throw (StreamException)
452 {
453 outputStream = new UriOutputStream(uri);
454 }
456 /**
457 *
458 */
459 UriWriter::~UriWriter() throw (StreamException)
460 {
461 delete outputStream;
462 }
464 /**
465 *
466 */
467 void UriWriter::close() throw(StreamException)
468 {
469 outputStream->close();
470 }
472 /**
473 *
474 */
475 void UriWriter::flush() throw(StreamException)
476 {
477 outputStream->flush();
478 }
480 /**
481 *
482 */
483 void UriWriter::put(gunichar ch) throw(StreamException)
484 {
485 int ich = (int)ch;
486 outputStream->put(ich);
487 }
493 } // namespace IO
494 } // namespace Inkscape
497 //#########################################################################
498 //# E N D O F F I L E
499 //#########################################################################