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