* Ooops, I didn't copy the files in the right directory of my repository.
[wxWidgets.git] / src / common / stream.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: stream.cpp
3 // Purpose: wxStream base classes
4 // Author: Guilhem Lavaux
5 // Modified by:
6 // Created: 11/07/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Guilhem Lavaux
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "stream.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18 #include <ctype.h>
19 #include <wx/stream.h>
20 #include <wx/datstrm.h>
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 // ----------------------------------------------------------------------------
27 // wxStreamBuffer
28 // ----------------------------------------------------------------------------
29
30 wxStreamBuffer::wxStreamBuffer(wxInputStream& i_stream)
31 : m_buffer_start(NULL), m_buffer_end(NULL), m_buffer_pos(NULL),
32 m_buffer_size(0), m_istream(&i_stream), m_ostream(NULL)
33 {
34 }
35
36 wxStreamBuffer::wxStreamBuffer(wxOutputStream& o_stream)
37 : m_buffer_start(NULL), m_buffer_end(NULL), m_buffer_pos(NULL),
38 m_buffer_size(0), m_istream(NULL), m_ostream(&o_stream)
39 {
40 }
41
42 wxStreamBuffer::~wxStreamBuffer()
43 {
44 }
45
46 void wxStreamBuffer::WriteBack(char c)
47 {
48 if (m_ostream)
49 return;
50
51 // Assume that if we write "back" we have read a few bytes: so we have some
52 // space.
53
54 m_buffer_pos--;
55 *m_buffer_pos = c;
56 }
57
58 void wxStreamBuffer::SetBufferIO(char *buffer_start, char *buffer_end)
59 {
60 m_buffer_pos = m_buffer_start = buffer_start;
61 m_buffer_end = buffer_end;
62
63 m_buffer_size = m_buffer_end-m_buffer_start;
64 }
65
66 void wxStreamBuffer::SetBufferIO(size_t bufsize)
67 {
68 if (m_buffer_start)
69 delete[] m_buffer_start;
70
71 if (!bufsize) {
72 m_buffer_start = NULL;
73 m_buffer_end = NULL;
74 m_buffer_pos = NULL;
75 m_buffer_size = 0;
76 }
77
78 m_buffer_start = new char[bufsize];
79 m_buffer_end = m_buffer_start + bufsize;
80 if (m_istream)
81 m_buffer_pos = m_buffer_end;
82 else
83 m_buffer_pos = m_buffer_start;
84 m_buffer_size = bufsize;
85 }
86
87 void wxStreamBuffer::ResetBuffer()
88 {
89 if (m_istream)
90 m_buffer_pos = m_buffer_end;
91 else
92 m_buffer_pos = m_buffer_start;
93 }
94
95 void wxStreamBuffer::Read(void *buffer, size_t size)
96 {
97 wxASSERT(m_istream != NULL);
98
99 // ------------------
100 // Buffering disabled
101 // ------------------
102
103 if (!m_buffer_size) {
104 m_istream->m_lastread = m_istream->DoRead(buffer, size);
105 return;
106 }
107
108 // -----------------
109 // Buffering enabled
110 // -----------------
111 size_t buf_left, orig_size = size;
112 size_t read_ret;
113
114 while (size > 0) {
115 buf_left = m_buffer_end - m_buffer_pos;
116
117 // First case: the requested buffer is larger than the stream buffer,
118 // we split
119 if (size > buf_left) {
120 memcpy(buffer, m_buffer_pos, buf_left);
121 size -= buf_left;
122 buffer = (char *)buffer + buf_left; // ANSI C++ violation.
123
124 read_ret = m_istream->DoRead(m_buffer_start, m_buffer_size);
125
126 // Read failed
127 if (read_ret == 0) {
128 m_istream->m_lastread = orig_size-size;
129 m_buffer_pos = m_buffer_end = m_buffer_start;
130 return;
131 } else {
132 m_buffer_end = m_buffer_start+read_ret;
133 m_buffer_pos = m_buffer_start;
134 }
135 } else {
136
137 // Second case: we just copy from the stream buffer.
138 memcpy(buffer, m_buffer_pos, size);
139 m_buffer_pos += size;
140 break;
141 }
142 }
143 m_istream->m_lastread = orig_size;
144 }
145
146 void wxStreamBuffer::Write(const void *buffer, size_t size)
147 {
148 wxASSERT(m_ostream != NULL);
149
150 // ------------------
151 // Buffering disabled
152 // ------------------
153
154 if (!m_buffer_size) {
155 m_ostream->m_lastwrite = m_ostream->DoWrite(buffer, size);
156 return;
157 }
158
159 // ------------------
160 // Buffering enabled
161 // ------------------
162
163 size_t buf_left, orig_size = size;
164 size_t write_ret;
165
166 while (size > 0) {
167 buf_left = m_buffer_end - m_buffer_pos;
168
169 // First case: the buffer to write is larger than the stream buffer,
170 // we split it
171 if (size > buf_left) {
172 memcpy(m_buffer_pos, buffer, buf_left);
173 size -= buf_left;
174 buffer = (char *)buffer + buf_left; // ANSI C++ violation.
175
176 write_ret = m_ostream->DoWrite(m_buffer_start, m_buffer_size);
177 if (write_ret != m_buffer_size) {
178 m_ostream->m_bad = TRUE;
179 m_ostream->m_lastwrite = orig_size-size;
180 m_buffer_pos = m_buffer_end = m_buffer_start;
181 return;
182 }
183 m_buffer_pos = m_buffer_start;
184
185 } else {
186
187 // Second case: just copy it in the stream buffer.
188
189 memcpy(m_buffer_pos, buffer, size);
190 m_buffer_pos += size;
191 break;
192 }
193 }
194 m_ostream->m_lastwrite = orig_size;
195 }
196
197 // ----------------------------------------------------------------------------
198 // wxInputStream
199 // ----------------------------------------------------------------------------
200
201 wxInputStream::wxInputStream()
202 {
203 m_i_destroybuf = TRUE;
204 m_i_streambuf = new wxStreamBuffer(*this);
205 }
206
207 wxInputStream::wxInputStream(wxStreamBuffer *buffer)
208 {
209 m_i_destroybuf = FALSE;
210 m_i_streambuf = buffer;
211 }
212
213 wxInputStream::~wxInputStream()
214 {
215 if (m_i_destroybuf)
216 delete m_i_streambuf;
217 }
218
219 char wxInputStream::GetC()
220 {
221 char c;
222 m_i_streambuf->Read(&c, 1);
223 return c;
224 }
225
226 wxInputStream& wxInputStream::Read(void *buffer, size_t size)
227 {
228 m_i_streambuf->Read(buffer, size);
229 // wxStreamBuffer sets all variables for us
230 return *this;
231 }
232
233 #define BUF_TEMP_SIZE 10000
234
235 wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
236 {
237 char buf[BUF_TEMP_SIZE];
238 size_t bytes_read = BUF_TEMP_SIZE;
239
240 while (bytes_read == BUF_TEMP_SIZE && !stream_out.Bad()) {
241 bytes_read = Read(buf, bytes_read).LastRead();
242
243 stream_out.Write(buf, bytes_read);
244 }
245 return *this;
246 }
247
248 wxInputStream& wxInputStream::operator>>(wxString& line)
249 {
250 wxDataInputStream s(*this);
251
252 line = s.ReadLine();
253 return *this;
254 }
255
256 wxInputStream& wxInputStream::operator>>(char& c)
257 {
258 c = GetC();
259 return *this;
260 }
261
262 wxInputStream& wxInputStream::operator>>(short& i)
263 {
264 long l;
265
266 *this >> l;
267 i = (short)l;
268 return *this;
269 }
270
271 wxInputStream& wxInputStream::operator>>(long& i)
272 {
273 /* I only implemented a simple integer parser */
274 int c, sign;
275
276 while (isspace( c = GetC() ) )
277 /* Do nothing */ ;
278
279 i = 0;
280 if (! (c == '-' || isdigit(c)) ) {
281 InputStreamBuffer()->WriteBack(c);
282 return *this;
283 }
284
285 if (c == '-') {
286 sign = -1;
287 c = GetC();
288 } else
289 sign = 1;
290
291 while (isdigit(c)) {
292 i = i*10 + c;
293 c = GetC();
294 }
295
296 i *= sign;
297
298 return *this;
299 }
300
301 wxInputStream& wxInputStream::operator>>(float& f)
302 {
303 /* I only implemented a simple float parser */
304 int c, sign;
305
306 while (isspace( c = GetC() ) )
307 /* Do nothing */ ;
308
309 f = 0.0;
310 if (! (c == '-' || isdigit(c)) ) {
311 InputStreamBuffer()->WriteBack(c);
312 return *this;
313 }
314
315 if (c == '-') {
316 sign = -1;
317 c = GetC();
318 } else
319 sign = 1;
320
321 while (isdigit(c)) {
322 f = f*10 + c;
323 c = GetC();
324 }
325
326 if (c == '.') {
327 float f_multiplicator = 0.1;
328 c = GetC();
329
330 while (isdigit(c)) {
331 f += c*f_multiplicator;
332 f_multiplicator /= 10;
333 c = GetC();
334 }
335 }
336
337 f *= sign;
338
339 return *this;
340 }
341
342 off_t wxInputStream::SeekI(off_t pos, wxSeekMode mode)
343 {
344 off_t ret_off;
345
346 switch (mode) {
347 case wxFromStart:
348 if ( (unsigned)abs (DoTellInput()-pos) > m_i_streambuf->GetLastAccess() ) {
349 ret_off = DoSeekInput(pos, wxFromStart);
350 m_i_streambuf->ResetBuffer();
351 return ret_off;
352 } else {
353 m_i_streambuf->SetIntPosition(DoTellInput() - pos);
354 return pos;
355 }
356 case wxFromCurrent:
357 if ( ((unsigned)pos > m_i_streambuf->GetLastAccess()) || (pos < 0) ) {
358 ret_off = DoSeekInput(pos, wxFromCurrent);
359 m_i_streambuf->ResetBuffer();
360 return ret_off;
361 } else {
362 m_i_streambuf->SetIntPosition(pos);
363 return pos;
364 }
365 case wxFromEnd:
366 // Hard to compute: always seek to the requested position.
367 ret_off = DoSeekInput(pos, wxFromEnd);
368 m_i_streambuf->ResetBuffer();
369 return ret_off;
370 }
371 return wxInvalidOffset;
372 }
373
374 off_t wxInputStream::TellI() const
375 {
376 return DoTellInput() - m_i_streambuf->GetLastAccess() +
377 m_i_streambuf->GetIntPosition();
378 }
379
380 // ----------------------------------------------------------------------------
381 // wxOutputStream
382 // ----------------------------------------------------------------------------
383 wxOutputStream::wxOutputStream()
384 {
385 m_o_destroybuf = TRUE;
386 m_o_streambuf = new wxStreamBuffer(*this);
387 }
388
389 wxOutputStream::wxOutputStream(wxStreamBuffer *buffer)
390 {
391 m_o_destroybuf = FALSE;
392 m_o_streambuf = buffer;
393 }
394
395 wxOutputStream::~wxOutputStream()
396 {
397 if (m_o_destroybuf)
398 delete m_o_streambuf;
399 }
400
401 wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size)
402 {
403 m_o_streambuf->Write(buffer, size);
404 return *this;
405 }
406
407 wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in)
408 {
409 stream_in.Read(*this);
410 return *this;
411 }
412
413 off_t wxOutputStream::SeekO(off_t pos, wxSeekMode mode)
414 {
415 off_t ret_off;
416
417 switch (mode) {
418 case wxFromStart:
419 if ( (unsigned)abs (DoTellOutput()-pos) > m_o_streambuf->GetLastAccess() ) {
420 ret_off = DoSeekOutput(pos, wxFromStart);
421 m_o_streambuf->ResetBuffer();
422 return ret_off;
423 } else {
424 m_o_streambuf->SetIntPosition( DoTellOutput() - pos);
425 return pos;
426 }
427 case wxFromCurrent:
428 if ( ((unsigned)pos > m_o_streambuf->GetLastAccess()) || (pos < 0) ) {
429 ret_off = DoSeekOutput(pos, wxFromCurrent);
430 m_o_streambuf->ResetBuffer();
431 return ret_off;
432 } else {
433 m_o_streambuf->SetIntPosition(pos);
434 return pos;
435 }
436 case wxFromEnd:
437 // Hard to compute: always seek to the requested position.
438 ret_off = DoSeekOutput(pos, wxFromEnd);
439 m_o_streambuf->ResetBuffer();
440 return ret_off;
441 }
442 return wxInvalidOffset;
443 }
444
445 off_t wxOutputStream::TellO() const
446 {
447 return DoTellOutput() - m_o_streambuf->GetLastAccess()
448 + m_o_streambuf->GetIntPosition();
449 }
450
451 void wxOutputStream::Sync()
452 {
453 DoWrite(m_o_streambuf->GetBufferStart(), m_o_streambuf->GetIntPosition());
454
455 m_o_streambuf->ResetBuffer();
456 }
457
458 wxOutputStream& wxOutputStream::operator<<(const char *string)
459 {
460 return Write(string, strlen(string));
461 }
462
463 wxOutputStream& wxOutputStream::operator<<(wxString& string)
464 {
465 return Write(string, string.Len());
466 }
467
468 wxOutputStream& wxOutputStream::operator<<(char c)
469 {
470 return Write(&c, 1);
471 }
472
473 wxOutputStream& wxOutputStream::operator<<(short i)
474 {
475 wxString strint;
476
477 strint.Printf("%i", i);
478 return Write(strint, strint.Len());
479 }
480
481 wxOutputStream& wxOutputStream::operator<<(int i)
482 {
483 wxString strint;
484
485 strint.Printf("%i", i);
486 return Write(strint, strint.Len());
487 }
488
489 wxOutputStream& wxOutputStream::operator<<(long i)
490 {
491 wxString strlong;
492
493 strlong.Printf("%i", i);
494 return Write((const char *)strlong, strlong.Len());
495 }
496
497 wxOutputStream& wxOutputStream::operator<<(double f)
498 {
499 wxString strfloat;
500
501 strfloat.Printf("%f", f);
502 return Write(strfloat, strfloat.Len());
503 }
504
505 // ----------------------------------------------------------------------------
506 // wxFilterInputStream
507 // ----------------------------------------------------------------------------
508 wxFilterInputStream::wxFilterInputStream(wxInputStream& stream)
509 : wxInputStream(NULL)
510 {
511 m_parent_i_stream = &stream;
512 m_i_streambuf = stream.InputStreamBuffer();
513 }
514
515 wxFilterInputStream::~wxFilterInputStream()
516 {
517 }
518
519 size_t wxFilterInputStream::DoRead(void *buffer, size_t size)
520 {
521 return m_parent_i_stream->Read(buffer, size).LastRead();
522 }
523
524 off_t wxFilterInputStream::DoSeekInput(off_t pos, wxSeekMode mode)
525 {
526 return m_parent_i_stream->SeekI(pos, mode);
527 }
528
529 off_t wxFilterInputStream::DoTellInput() const
530 {
531 return m_parent_i_stream->TellI();
532 }
533
534
535 // ----------------------------------------------------------------------------
536 // wxFilterOutputStream
537 // ----------------------------------------------------------------------------
538 wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream)
539 : wxOutputStream(NULL)
540 {
541 m_parent_o_stream = &stream;
542 m_o_streambuf = stream.OutputStreamBuffer();
543 }
544
545 wxFilterOutputStream::~wxFilterOutputStream()
546 {
547 }
548
549 size_t wxFilterOutputStream::DoWrite(const void *buffer, size_t size)
550 {
551 return m_parent_o_stream->Write(buffer, size).LastWrite();
552 }
553
554 off_t wxFilterOutputStream::DoSeekOutput(off_t pos, wxSeekMode mode)
555 {
556 return m_parent_o_stream->SeekO(pos, mode);
557 }
558
559 off_t wxFilterOutputStream::DoTellOutput() const
560 {
561 return m_parent_o_stream->TellO();
562 }
563
564 // ----------------------------------------------------------------------------
565 // Some IOManip function
566 // ----------------------------------------------------------------------------
567
568 wxOutputStream& wxEndL(wxOutputStream& stream)
569 {
570 #ifdef __MSW__
571 return stream.Write("\r\n", 2);
572 #else
573 return stream.Write("\n", 1);
574 #endif
575 }