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