1 /****************************************************************************
2 * fileinputoutput.cpp
3 *
4 * This module implements the classes handling file input and output.
5 *
6 * from Persistence of Vision(tm) Ray Tracer version 3.6.
7 * Copyright 1991-2003 Persistence of Vision Team
8 * Copyright 2003-2004 Persistence of Vision Raytracer Pty. Ltd.
9 *---------------------------------------------------------------------------
10 * NOTICE: This source code file is provided so that users may experiment
11 * with enhancements to POV-Ray and to port the software to platforms other
12 * than those supported by the POV-Ray developers. There are strict rules
13 * regarding how you are permitted to use this file. These rules are contained
14 * in the distribution and derivative versions licenses which should have been
15 * provided with this file.
16 *
17 * These licences may be found online, linked from the end-user license
18 * agreement that is located at http://www.povray.org/povlegal.html
19 *---------------------------------------------------------------------------
20 * This program is based on the popular DKB raytracer version 2.12.
21 * DKBTrace was originally written by David K. Buck.
22 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
23 *---------------------------------------------------------------------------
24 *
25 *===========================================================================
26 * This file is part of MegaPOV, a modified and unofficial version of POV-Ray
27 * For more information on MegaPOV visit our website:
28 * http://megapov.inetart.net/
29 *===========================================================================
30 *
31 * $RCSfile: fileinputoutput.cpp,v $
32 * $Revision: 1.12 $
33 * $Author: chris $
34 *
35 *****************************************************************************/
36
37 #include <cstdlib>
38 #include <cstdarg>
39
40 #include "configbase.h"
41
42 #include "fileinputoutput.h"
43 #include "stringutilities.h"
44 #include "platformbase.h"
45 #include "pointer.h"
46 #ifdef BUILD_FOR_MACMEGAPOV
47 #include "povray.h"
48 BEGIN_POV_NAMESPACE
49 extern Opts opts;
50 END_POV_NAMESPACE
51 #endif
52
53 BEGIN_POV_BASE_NAMESPACE
54
55 #ifndef POV_IS1
56 #define POV_IS1 ""
57 #endif
58
59 #ifndef POV_IS2
60 #define POV_IS2 ""
61 #endif
62
63 #ifndef POV_IS3
64 #define POV_IS3 ""
65 #endif
66
67 #ifndef POV_IS4
68 #define POV_IS4 ""
69 #endif
70
71 POV_File_Extensions gPOV_File_Extensions[POV_File_Unknown_Count] =
72 {
73 {{ "", "", "", "" }}, // POV_File_Unknown
74 {{ ".tga", ".TGA", "", "" }}, // POV_File_Image_Targa
75 {{ ".png", ".PNG", "", "" }}, // POV_File_Image_PNG
76 {{ ".ppm", ".PPM", "", "" }}, // POV_File_Image_PPM
77 {{ ".pgm", ".PGM", "", "" }}, // POV_File_Image_PGM
78 {{ ".gif", ".GIF", "", "" }}, // POV_File_Image_GIF
79 {{ ".iff", ".IFF", "", "" }}, // POV_File_Image_IFF
80 {{ ".jpg", ".JPG", ".jpeg", ".JPEG" }}, // POV_File_Image_JPEG
81 {{ ".tif", ".TIF", ".tiff", ".TIFF" }}, // POV_File_Image_TIFF
82 {{ POV_IS1, POV_IS2, POV_IS3, POV_IS4 }}, // POV_File_Image_System
83 {{ ".pov", ".POV", "", "" }}, // POV_File_Text_POV
84 {{ ".inc", ".INC", "", "" }}, // POV_File_Text_INC
85 {{ ".ini", ".INI", "", "" }}, // POV_File_Text_INI
86 {{ ".csv", ".CSV", "", "" }}, // POV_File_Text_CSV
87 {{ ".txt", ".TXT", "", "" }}, // POV_File_Text_Stream
88 {{ "", "", "", "" }}, // POV_File_Text_User
89 {{ ".df3", ".DF3", "", "" }}, // POV_File_Data_DF3
90 {{ ".rca", ".RCA", "", "" }}, // POV_File_Data_RCA
91 {{ ".log", ".LOG", "", "" }}, // POV_File_Data_LOG
92 {{ ".ttf", ".TTF", "", "" }} // POV_File_Font_TTF
93 #ifdef MPEG_PORT_PATCH
94 ,{{ ".mpg", ".MPG", ".mpeg", ".MPEG" }} // POV_File_Image_MPEG
95 #endif
96 /*ML: hdr_patch*/
97 #ifdef HDR_PATCH
98 ,{{ ".hdr", ".HDR", "", "" }} // POV_File_Image_HDR
99 #endif
100 };
101
IOBase(unsigned int dir,unsigned int type)102 IOBase::IOBase(unsigned int dir, unsigned int type)
103 {
104 filetype = type;
105 direction = dir;
106 fail = true;
107 f = NULL;
108 }
109
~IOBase()110 IOBase::~IOBase()
111 {
112 close();
113 }
114
open(const char * Name,unsigned int Flags)115 bool IOBase::open(const char *Name, unsigned int Flags /* = 0 */)
116 {
117 char mode[8];
118
119 close();
120
121 if((Flags & append) == 0)
122 {
123 switch(direction)
124 {
125 case input:
126 strcpy(mode, "r");
127 break;
128 case output:
129 strcpy(mode, "w");
130 break;
131 case io:
132 strcpy(mode, "w+");
133 break;
134 default:
135 return false;
136 }
137 }
138 else
139 {
140 // we cannot use append mode here, since "a" mode is totally incompatible with any
141 // output file format that requires in-place updates(i.e. writing to any location
142 // other than the end of the file). BMP files are in this category. In theory, "r+"
143 // can do anything "a" can do(with appropriate use of seek()) so append mode should
144 // not be needed.
145 strcpy(mode, "r+");
146 }
147
148 strcat(mode, "b");
149
150 f = NULL;
151 if(pov_stricmp(Name, "stdin") == 0)
152 {
153 if(direction != input ||(Flags & append) != 0)
154 return false;
155 f = stdin;
156 }
157 else if(pov_stricmp(Name, "stdout") == 0)
158 {
159 if(direction != output ||(Flags & append) != 0)
160 return false;
161 f = stdout;
162 }
163 else
164 {
165 if((f = fopen(Name, mode)) == NULL)
166 {
167 if((Flags & append) == 0)
168 return false;
169
170 // to maintain traditional POV +c(continue) mode compatibility, if
171 // the open for append of an existing file fails, we allow a new file
172 // to be created.
173 mode [0] = 'w';
174 if((f = fopen(Name, mode)) == NULL)
175 return false;
176 }
177 }
178 fail = false;
179
180 if((Flags & append) != 0)
181 {
182 if(!seekg(0, seek_end))
183 {
184 close();
185 return false;
186 }
187 }
188
189 return true;
190 }
191
close(void)192 bool IOBase::close(void)
193 {
194 if(f != NULL)
195 {
196 fclose(f);
197 f = NULL;
198 }
199 fail = true;
200 return true;
201 }
202
flush(void)203 IOBase& IOBase::flush(void)
204 {
205 if(f != NULL)
206 fflush(f);
207 return *this;
208 }
209
read(void * buffer,unsigned long count)210 IOBase& IOBase::read(void *buffer, unsigned long count)
211 {
212 if(!fail && count > 0)
213 fail = fread(buffer, count, 1, f) != 1;
214 return *this;
215 }
216
write(void * buffer,unsigned long count)217 IOBase& IOBase::write(void *buffer, unsigned long count)
218 {
219 if(!fail && count > 0)
220 fail = fwrite(buffer, count, 1, f) != 1;
221 return *this;
222 }
223
224 // Strictly speaking, this should -not- be called seekg, since 'seekg'(an iostreams
225 // term) applies only to an input stream, and therefore the use of this name here
226 // implies that only the input stream will be affected on streams opened for I/O
227 //(which is not the case with fseek, since fseek moves the pointer for output too).
228 // However, the macintosh code seems to need it to be called seekg, so it is ...
seekg(unsigned long pos,unsigned int whence)229 IOBase& IOBase::seekg(unsigned long pos, unsigned int whence /* = seek_set */)
230 {
231 if(!fail)
232 fail = fseek(f, pos, whence) != 0;
233 return *this;
234 }
235
236 #ifdef POST_PROCESS_PATCH
fsize(void)237 unsigned long IOBase::fsize (void)
238 {
239 unsigned long curr_pos = tellg();
240 seekg(0,seek_end);
241 unsigned long length = tellg();
242 seekg(curr_pos,seek_set);
243 return (length);
244 }
245 #endif
246
IStream(const unsigned int stype)247 IStream::IStream(const unsigned int stype) : IOBase(input, stype)
248 {
249 }
250
~IStream()251 IStream::~IStream()
252 {
253 }
254
Read_Short(void)255 int IStream::Read_Short(void)
256 {
257 short result;
258 read((char *) &result, sizeof(short));
259 return result;
260 }
261
Read_Int(void)262 int IStream::Read_Int(void)
263 {
264 int result;
265 read((char *) &result, sizeof(int));
266 return result;
267 }
268
Read_Long(void)269 long IStream::Read_Long(void)
270 {
271 long result;
272 read((char *) &result, sizeof(long));
273 return result;
274 }
275
UnRead_Byte(int c)276 IStream& IStream::UnRead_Byte(int c)
277 {
278 if(!fail)
279 fail = ungetc(c, f) != c;
280 return *this;
281 }
282
getline(char * s,unsigned long buflen)283 IStream& IStream::getline(char *s, unsigned long buflen)
284 {
285 int chr = 0;
286
287 if(feof(f) != 0)
288 fail = true;
289
290 if(!fail && buflen > 0)
291 {
292 while(buflen > 1)
293 {
294 chr = fgetc(f);
295 if(chr == EOF)
296 break;
297 else if(chr == 10)
298 {
299 chr = fgetc(f);
300 if(chr != 13)
301 ungetc(chr, f);
302 break;
303 }
304 else if(chr == 13)
305 {
306 chr = fgetc(f);
307 if(chr != 10)
308 ungetc(chr, f);
309 break;
310 }
311 *s = chr;
312 s++;
313 buflen--;
314 }
315 *s = 0;
316 }
317
318 return *this;
319 }
320
OStream(const unsigned int stype)321 OStream::OStream(const unsigned int stype) : IOBase(output, stype)
322 {
323 }
324
~OStream()325 OStream::~OStream()
326 {
327 }
328
printf(const char * format,...)329 void OStream::printf(const char *format, ...)
330 {
331 va_list marker;
332 char buffer[1024];
333
334 va_start(marker, format);
335 vsnprintf(buffer, 1023, format, marker);
336 va_end(marker);
337
338 *this << buffer;
339 }
340
New_IStream(const char * sname,const unsigned int stype)341 IStream *New_IStream(const char *sname, const unsigned int stype)
342 {
343 Pointer<IStream> istreamptr(POV_PLATFORM_BASE.CreateIStream(stype));
344
345 if(istreamptr == NULL)
346 return NULL;
347
348 if(istreamptr->open(sname) == 0)
349 return NULL;
350
351 return istreamptr.release();
352 }
353
New_OStream(const char * sname,const unsigned int stype,const bool sappend)354 OStream *New_OStream(const char *sname, const unsigned int stype, const bool sappend)
355 {
356 Pointer<OStream> ostreamptr(POV_PLATFORM_BASE.CreateOStream(stype));
357 unsigned int Flags = IOBase::none;
358
359 if(ostreamptr == NULL)
360 return NULL;
361
362 if(sappend)
363 Flags |= IOBase::append;
364
365 if(ostreamptr->open(sname, Flags) == 0)
366 return NULL;
367
368 return ostreamptr.release();
369 }
370
371 /*****************************************************************************
372 *
373 * FUNCTION
374 *
375 * INPUT
376 *
377 * OUTPUT
378 *
379 * RETURNS
380 *
381 * AUTHOR
382 *
383 * DESCRIPTION
384 *
385 * CHANGES
386 *
387 ******************************************************************************/
388
Has_Extension(const char * name)389 int Has_Extension(const char *name)
390 {
391 if (name!=NULL)
392 {
393 const char *p=strrchr(name, '.');
394
395 if (p!=NULL)
396 {
397 #ifdef BUILD_FOR_MACMEGAPOV
398 if ( POV_NAMESPACE::opts.Output_File_Type == SYS_FILE)
399 {
400 if ((strlen(name)-(p-name))<=5)
401 {
402 return (true);
403 }
404 }
405 #endif
406 if ((strlen(name)-(p-name))<=4)
407 {
408 return (true);
409 }
410 }
411 }
412 return (false);
413 }
414
Split_Path(char * s,char * p,char * f)415 void Split_Path(char *s, char *p, char *f)
416 {
417 char *l;
418
419 strcpy(p,s);
420
421 if ((l=strrchr(p,FILENAME_SEPARATOR))==NULL)
422 {
423 if ((l=strrchr(p,DRIVE_SEPARATOR))==NULL)
424 {
425 strcpy(f,s);
426 p[0]='\0';
427 return;
428 }
429 }
430
431 l++;
432 strcpy(f,l);
433 *l='\0';
434
435 }
436
File_Exist(const char * name)437 bool File_Exist(const char *name)
438 {
439 FILE *file = fopen(name, "r");
440
441 if(file != NULL)
442 fclose(file);
443 else
444 return false;
445
446 return true;
447 }
448
449 END_POV_BASE_NAMESPACE
450