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"
16 #include <string>
17 #include <cstring>
19 #ifdef WIN32
20 // For now to get at is_os_wide().
21 # include "extension/internal/win32.h"
22 using Inkscape::Extension::Internal::PrintWin32;
23 #endif
26 namespace Inkscape
27 {
28 namespace IO
29 {
31 /*
32 * URI scheme types
33 */
34 #define SCHEME_NONE 0
35 #define SCHEME_FILE 1
36 #define SCHEME_DATA 2
38 /*
39 * A temporary modification of Jon Cruz's portable fopen().
40 * Simplified a bit, since we will always use binary
41 */
43 #define FILE_READ 1
44 #define FILE_WRITE 2
46 static FILE *fopen_utf8name( char const *utf8name, int mode )
47 {
48 FILE *fp = NULL;
49 if (!utf8name)
50 {
51 return NULL;
52 }
53 if (mode!=FILE_READ && mode!=FILE_WRITE)
54 {
55 return NULL;
56 }
58 #ifndef WIN32
59 gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL );
60 if ( filename ) {
61 if (mode == FILE_READ)
62 fp = std::fopen(filename, "rb");
63 else
64 fp = std::fopen(filename, "wb");
65 g_free(filename);
66 }
67 #else
68 if ( PrintWin32::is_os_wide() ) {
69 gunichar2 *wideName = g_utf8_to_utf16( utf8name, -1, NULL, NULL, NULL );
70 if ( wideName ) {
71 if (mode == FILE_READ)
72 fp = _wfopen( (wchar_t*)wideName, L"rb" );
73 else
74 fp = _wfopen( (wchar_t*)wideName, L"wb" );
75 g_free( wideName );
76 } else {
77 gchar *safe = Inkscape::IO::sanitizeString(utf8name);
78 g_message("Unable to convert filename from UTF-8 to UTF-16 [%s]", safe);
79 g_free(safe);
80 }
81 } else {
82 gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL );
83 if ( filename ) {
84 if (mode == FILE_READ)
85 fp = std::fopen(filename, "rb");
86 else
87 fp = std::fopen(filename, "wb");
88 g_free(filename);
89 }
90 }
91 #endif
93 return fp;
94 }
98 //#########################################################################
99 //# U R I I N P U T S T R E A M / R E A D E R
100 //#########################################################################
103 /**
104 *
105 */
106 UriInputStream::UriInputStream(Inkscape::URI &source)
107 throw (StreamException): uri(source)
108 {
109 //get information from uri
110 char const *schemestr = uri.getScheme();
111 scheme = SCHEME_FILE;
112 if (!schemestr || strncmp("file", schemestr, 4)==0)
113 scheme = SCHEME_FILE;
114 else if (strncmp("data", schemestr, 4)==0)
115 scheme = SCHEME_DATA;
116 //printf("in schemestr:'%s' scheme:'%d'\n", schemestr, scheme);
117 gchar *cpath = NULL;
119 switch (scheme) {
121 case SCHEME_FILE:
122 cpath = uri.toNativeFilename();
123 //printf("in cpath:'%s'\n", cpath);
124 inf = fopen_utf8name(cpath, FILE_READ);
125 //inf = fopen(cpath, "rb");
126 g_free(cpath);
127 if (!inf) {
128 Glib::ustring err = "UriInputStream cannot open file ";
129 err += cpath;
130 throw StreamException(err);
131 }
132 break;
134 case SCHEME_DATA:
135 data = (unsigned char *) uri.getPath();
136 //printf("in data:'%s'\n", data);
137 dataPos = 0;
138 dataLen = strlen((const char *)data);
139 break;
141 }
142 closed = false;
143 }
145 /**
146 *
147 */
148 UriInputStream::UriInputStream(FILE *source, Inkscape::URI &uri)
149 throw (StreamException): inf(source),
150 uri(uri)
151 {
152 scheme = SCHEME_FILE;
153 if (!inf) {
154 Glib::ustring err = "UriInputStream passed NULL";
155 throw StreamException(err);
156 }
157 closed = false;
158 }
160 /**
161 *
162 */
163 UriInputStream::~UriInputStream() throw(StreamException)
164 {
165 close();
166 }
168 /**
169 * Returns the number of bytes that can be read (or skipped over) from
170 * this input stream without blocking by the next caller of a method for
171 * this input stream.
172 */
173 int UriInputStream::available() throw(StreamException)
174 {
175 return 0;
176 }
179 /**
180 * Closes this input stream and releases any system resources
181 * associated with the stream.
182 */
183 void UriInputStream::close() throw(StreamException)
184 {
185 if (closed)
186 return;
188 switch (scheme) {
190 case SCHEME_FILE:
191 if (!inf)
192 return;
193 fflush(inf);
194 fclose(inf);
195 inf=NULL;
196 break;
198 case SCHEME_DATA:
199 //do nothing
200 break;
202 }//switch
204 closed = true;
205 }
207 /**
208 * Reads the next byte of data from the input stream. -1 if EOF
209 */
210 int UriInputStream::get() throw(StreamException)
211 {
212 int retVal = -1;
213 if (!closed)
214 {
215 switch (scheme) {
217 case SCHEME_FILE:
218 if (!inf || feof(inf))
219 {
220 retVal = -1;
221 }
222 else
223 {
224 retVal = fgetc(inf);
225 }
226 break;
228 case SCHEME_DATA:
229 if (dataPos >= dataLen)
230 {
231 retVal = -1;
232 }
233 else
234 {
235 retVal = data[dataPos++];
236 }
237 break;
238 }//switch
239 }
240 return retVal;
241 }
248 /**
249 *
250 */
251 UriReader::UriReader(Inkscape::URI &uri)
252 throw (StreamException)
253 {
254 inputStream = new UriInputStream(uri);
255 }
257 /**
258 *
259 */
260 UriReader::~UriReader() throw (StreamException)
261 {
262 delete inputStream;
263 }
265 /**
266 *
267 */
268 int UriReader::available() throw(StreamException)
269 {
270 return inputStream->available();
271 }
273 /**
274 *
275 */
276 void UriReader::close() throw(StreamException)
277 {
278 inputStream->close();
279 }
281 /**
282 *
283 */
284 gunichar UriReader::get() throw(StreamException)
285 {
286 gunichar ch = (gunichar)inputStream->get();
287 return ch;
288 }
291 //#########################################################################
292 //# U R I O U T P U T S T R E A M / W R I T E R
293 //#########################################################################
295 /**
296 * Temporary kludge
297 */
298 UriOutputStream::UriOutputStream(FILE* fp, Inkscape::URI &destination)
299 throw (StreamException): closed(false),
300 ownsFile(false),
301 outf(fp),
302 uri(destination),
303 scheme(SCHEME_FILE)
304 {
305 if (!outf) {
306 Glib::ustring err = "UriOutputStream given null file ";
307 throw StreamException(err);
308 }
309 }
311 /**
312 *
313 */
314 UriOutputStream::UriOutputStream(Inkscape::URI &destination)
315 throw (StreamException): closed(false),
316 ownsFile(true),
317 outf(NULL),
318 uri(destination),
319 scheme(SCHEME_FILE)
320 {
321 //get information from uri
322 char const *schemestr = uri.getScheme();
323 if (!schemestr || strncmp("file", schemestr, 4)==0)
324 scheme = SCHEME_FILE;
325 else if (strncmp("data", schemestr, 4)==0)
326 scheme = SCHEME_DATA;
327 //printf("out schemestr:'%s' scheme:'%d'\n", schemestr, scheme);
328 gchar *cpath = NULL;
330 switch (scheme) {
332 case SCHEME_FILE:
333 cpath = uri.toNativeFilename();
334 //printf("out path:'%s'\n", cpath);
335 outf = fopen_utf8name(cpath, FILE_WRITE);
336 //outf = fopen(cpath, "wb");
337 g_free(cpath);
338 if (!outf) {
339 Glib::ustring err = "UriOutputStream cannot open file ";
340 err += cpath;
341 throw StreamException(err);
342 }
343 break;
345 case SCHEME_DATA:
346 data = "data:";
347 break;
349 }//switch
350 }
353 /**
354 *
355 */
356 UriOutputStream::~UriOutputStream() throw(StreamException)
357 {
358 close();
359 }
361 /**
362 * Closes this output stream and releases any system resources
363 * associated with this stream.
364 */
365 void UriOutputStream::close() throw(StreamException)
366 {
367 if (closed)
368 return;
370 switch (scheme) {
372 case SCHEME_FILE:
373 if (!outf)
374 return;
375 fflush(outf);
376 if ( ownsFile )
377 fclose(outf);
378 outf=NULL;
379 break;
381 case SCHEME_DATA:
382 uri = URI(data.raw().c_str());
383 break;
385 }//switch
387 closed = true;
388 }
390 /**
391 * Flushes this output stream and forces any buffered output
392 * bytes to be written out.
393 */
394 void UriOutputStream::flush() throw(StreamException)
395 {
396 if (closed)
397 return;
399 switch (scheme) {
401 case SCHEME_FILE:
402 if (!outf)
403 return;
404 fflush(outf);
405 break;
407 case SCHEME_DATA:
408 //nothing
409 break;
411 }//switch
413 }
415 /**
416 * Writes the specified byte to this output stream.
417 */
418 void UriOutputStream::put(int ch) throw(StreamException)
419 {
420 if (closed)
421 return;
423 unsigned char uch;
424 gunichar gch;
426 switch (scheme) {
428 case SCHEME_FILE:
429 if (!outf)
430 return;
431 uch = (unsigned char)(ch & 0xff);
432 fputc(uch, outf);
433 //fwrite(uch, 1, 1, outf);
434 break;
436 case SCHEME_DATA:
437 gch = (gunichar) ch;
438 data.push_back(gch);
439 break;
441 }//switch
443 }
449 /**
450 *
451 */
452 UriWriter::UriWriter(Inkscape::URI &uri)
453 throw (StreamException)
454 {
455 outputStream = new UriOutputStream(uri);
456 }
458 /**
459 *
460 */
461 UriWriter::~UriWriter() throw (StreamException)
462 {
463 delete outputStream;
464 }
466 /**
467 *
468 */
469 void UriWriter::close() throw(StreamException)
470 {
471 outputStream->close();
472 }
474 /**
475 *
476 */
477 void UriWriter::flush() throw(StreamException)
478 {
479 outputStream->flush();
480 }
482 /**
483 *
484 */
485 void UriWriter::put(gunichar ch) throw(StreamException)
486 {
487 int ich = (int)ch;
488 outputStream->put(ich);
489 }
495 } // namespace IO
496 } // namespace Inkscape
499 //#########################################################################
500 //# E N D O F F I L E
501 //#########################################################################