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