1 /*******************************************************************************
2 * textstream.cpp
3 *
4 * This module implements the classes handling text file input and output.
5 *
6 * ---------------------------------------------------------------------------
7 * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
8 * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
9 *
10 * POV-Ray is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as
12 * published by the Free Software Foundation, either version 3 of the
13 * License, or (at your option) any later version.
14 *
15 * POV-Ray is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * ---------------------------------------------------------------------------
23 * POV-Ray is based on the popular DKB raytracer version 2.12.
24 * DKBTrace was originally written by David K. Buck.
25 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
26 * ---------------------------------------------------------------------------
27 * $File: //depot/public/povray/3.x/source/base/textstream.cpp $
28 * $Revision: #1 $
29 * $Change: 6069 $
30 * $DateTime: 2013/11/06 11:59:40 $
31 * $Author: chrisc $
32 *******************************************************************************/
33
34 #include <cstdlib>
35 #include <cstdarg>
36 #include <algorithm>
37
38 // configbase.h must always be the first POV file included within base *.cpp files
39 #include "configbase.h"
40
41 #include "textstream.h"
42
43 // this must be the last file included
44 #include "base/povdebug.h"
45
46 namespace pov_base
47 {
48
ITextStream(const UCS2 * sname,unsigned int stype)49 ITextStream::ITextStream(const UCS2 *sname, unsigned int stype)
50 {
51 if(sname == NULL)
52 throw POV_EXCEPTION_CODE(kParamErr);
53
54 stream = NewIStream(sname, stype);
55 if(stream == NULL)
56 throw POV_EXCEPTION(kCannotOpenFileErr, string("Cannot open file '") + UCS2toASCIIString(sname) + "' for input.");
57
58 filename = UCS2String(sname);
59 lineno = 1;
60 bufferoffset = 0;
61 maxbufferoffset = 0;
62 filelength = 0;
63 ungetbuffer = EOF;
64 curpos = 0 ;
65
66 stream->seekg(0, IOBase::seek_end);
67 filelength = stream->tellg();
68 stream->seekg(0, IOBase::seek_set);
69
70 RefillBuffer();
71 }
72
ITextStream(const UCS2 * sname,IStream * sstream)73 ITextStream::ITextStream(const UCS2 *sname, IStream *sstream)
74 {
75 if(sname == NULL)
76 throw POV_EXCEPTION_CODE(kParamErr);
77 if(sstream == NULL)
78 throw POV_EXCEPTION_CODE(kParamErr);
79
80 stream = sstream;
81 filename = UCS2String(sname);
82 lineno = 1;
83 bufferoffset = 0;
84 maxbufferoffset = 0;
85 filelength = 0;
86 ungetbuffer = EOF;
87 curpos = 0 ;
88
89 stream->seekg(0, IOBase::seek_end);
90 filelength = stream->tellg();
91 stream->seekg(0, IOBase::seek_set);
92
93 RefillBuffer();
94 }
95
~ITextStream()96 ITextStream::~ITextStream()
97 {
98 delete stream;
99 stream = NULL;
100 }
101
getchar()102 int ITextStream::getchar()
103 {
104 int chr = 0;
105
106 if(ungetbuffer != EOF)
107 {
108 chr = ungetbuffer;
109 ungetbuffer = EOF;
110 }
111 else
112 {
113 if(bufferoffset >= maxbufferoffset)
114 chr = EOF;
115 else
116 {
117 chr = buffer[bufferoffset];
118 bufferoffset++;
119 }
120 }
121
122 if(((chr == 10) || (chr == 13)) && (bufferoffset >= maxbufferoffset))
123 RefillBuffer();
124
125 if(chr == 10)
126 {
127 if(buffer[bufferoffset] == 13)
128 bufferoffset++;
129 chr = '\n';
130 lineno++;
131 }
132 else if(chr == 13)
133 {
134 if(buffer[bufferoffset] == 10)
135 bufferoffset++;
136 chr = '\n';
137 lineno++;
138 }
139
140 if(bufferoffset >= maxbufferoffset)
141 RefillBuffer();
142
143 return chr;
144 }
145
ungetchar(int chr)146 void ITextStream::ungetchar(int chr)
147 {
148 ungetbuffer = chr;
149 if(chr == '\n')
150 lineno--;
151 }
152
eof() const153 bool ITextStream::eof() const
154 {
155 if(ungetbuffer != EOF)
156 return false;
157 if(bufferoffset >= maxbufferoffset)
158 return true;
159 return stream->eof();
160 }
161
seekg(ITextStream::FilePos fp)162 bool ITextStream::seekg(ITextStream::FilePos fp)
163 {
164 bool result = true;
165
166 if((fp.offset < curpos) && ((curpos - fp.offset) < maxbufferoffset))
167 {
168 bufferoffset = maxbufferoffset - (curpos - fp.offset);
169 lineno = fp.lineno;
170 ungetbuffer = EOF;
171 }
172 else
173 {
174 result = (stream->seekg(fp.offset) != 0);
175
176 if(result == true)
177 {
178 lineno = fp.lineno;
179
180 bufferoffset = 0;
181 maxbufferoffset = 0;
182 ungetbuffer = EOF;
183 curpos = fp.offset ;
184
185 RefillBuffer();
186 }
187 else
188 curpos = stream->tellg() ;
189 }
190
191 return result;
192 }
193
tellg() const194 ITextStream::FilePos ITextStream::tellg() const
195 {
196 FilePos fp;
197
198 fp.lineno = lineno;
199 fp.offset = curpos - (maxbufferoffset - bufferoffset);
200
201 if(ungetbuffer != EOF)
202 fp.offset--;
203
204 return fp;
205 }
206
RefillBuffer()207 void ITextStream::RefillBuffer()
208 {
209 if(bufferoffset < maxbufferoffset)
210 {
211 curpos -= (maxbufferoffset - bufferoffset);
212 stream->seekg(curpos, IOBase::seek_set);
213 }
214
215 maxbufferoffset = min((POV_ULONG)ITEXTSTREAM_BUFFER_SIZE, filelength - curpos);
216 bufferoffset = 0;
217
218 stream->read(buffer, maxbufferoffset);
219 if (*stream)
220 curpos += maxbufferoffset ;
221 else
222 curpos = stream->tellg() ;
223 }
224
OTextStream(const UCS2 * sname,unsigned int stype,bool append)225 OTextStream::OTextStream(const UCS2 *sname, unsigned int stype, bool append)
226 {
227 if(sname == NULL)
228 throw POV_EXCEPTION_CODE(kParamErr);
229
230 stream = NewOStream(sname, stype, append);
231 if(stream == NULL)
232 throw POV_EXCEPTION(kCannotOpenFileErr, string("Cannot open file '") + UCS2toASCIIString(sname) + "' for output.");
233
234 filename = UCS2String(sname);
235 }
236
OTextStream(const UCS2 * sname,OStream * sstream)237 OTextStream::OTextStream(const UCS2 *sname, OStream *sstream)
238 {
239 if(sname == NULL)
240 throw POV_EXCEPTION_CODE(kParamErr);
241 if(sstream == NULL)
242 throw POV_EXCEPTION_CODE(kParamErr);
243
244 stream = sstream;
245 filename = UCS2String(sname);
246 }
247
~OTextStream()248 OTextStream::~OTextStream()
249 {
250 delete stream;
251 stream = NULL;
252 }
253
putchar(int chr)254 void OTextStream::putchar(int chr)
255 {
256 #ifdef TEXTSTREAM_CRLF
257 if (chr == '\n')
258 stream->Write_Byte('\r');
259 #endif
260
261 stream->Write_Byte((unsigned char)chr);
262 }
263
putraw(int chr)264 void OTextStream::putraw(int chr)
265 {
266 stream->Write_Byte((unsigned char)chr);
267 }
268
printf(const char * format,...)269 void OTextStream::printf(const char *format, ...)
270 {
271 va_list marker;
272 char buffer[1024];
273
274 va_start(marker, format);
275 vsnprintf(buffer, 1023, format, marker);
276 va_end(marker);
277
278 #ifdef TEXTSTREAM_CRLF
279 char *s1 = buffer ;
280 char *s2 ;
281
282 while ((s2 = strchr (s1, '\n')) != NULL)
283 {
284 *s2++ = '\0' ;
285 stream->printf("%s\r\n", s1);
286 s1 = s2 ;
287 }
288 if (*s1)
289 stream->printf("%s", s1);
290 #else
291 stream->printf("%s", buffer);
292 #endif
293 }
294
flush()295 void OTextStream::flush()
296 {
297 stream->flush();
298 }
299
300 }
301