1 |
///////////////////////////////////////////////////////////////////////////// |
2 |
// Name: src/common/stream.cpp |
3 |
// Purpose: wxStream base classes |
4 |
// Author: Guilhem Lavaux |
5 |
// Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory, |
6 |
// general code review |
7 |
// Created: 11/07/98 |
8 |
// RCS-ID: $Id: stream.cpp 51662 2008-02-11 20:23:29Z VZ $ |
9 |
// Copyright: (c) Guilhem Lavaux |
10 |
// Licence: wxWindows licence |
11 |
///////////////////////////////////////////////////////////////////////////// |
12 |
|
13 |
// ============================================================================ |
14 |
// declarations |
15 |
// ============================================================================ |
16 |
|
17 |
// ---------------------------------------------------------------------------- |
18 |
// headers |
19 |
// ---------------------------------------------------------------------------- |
20 |
|
21 |
// For compilers that support precompilation, includes "wx.h". |
22 |
#include "wx/wxprec.h" |
23 |
|
24 |
#ifdef __BORLANDC__ |
25 |
#pragma hdrstop |
26 |
#endif |
27 |
|
28 |
#if wxUSE_STREAMS |
29 |
|
30 |
#include "wx/stream.h" |
31 |
|
32 |
#ifndef WX_PRECOMP |
33 |
#include "wx/log.h" |
34 |
#endif |
35 |
|
36 |
#include <ctype.h> |
37 |
#include "wx/datstrm.h" |
38 |
#include "wx/textfile.h" |
39 |
|
40 |
// ---------------------------------------------------------------------------- |
41 |
// constants |
42 |
// ---------------------------------------------------------------------------- |
43 |
|
44 |
// the temporary buffer size used when copying from stream to stream |
45 |
#define BUF_TEMP_SIZE 4096 |
46 |
|
47 |
// ============================================================================ |
48 |
// implementation |
49 |
// ============================================================================ |
50 |
|
51 |
// ---------------------------------------------------------------------------- |
52 |
// wxStreamBuffer |
53 |
// ---------------------------------------------------------------------------- |
54 |
|
55 |
void wxStreamBuffer::SetError(wxStreamError err) |
56 |
{ |
57 |
if ( m_stream && m_stream->m_lasterror == wxSTREAM_NO_ERROR ) |
58 |
m_stream->m_lasterror = err; |
59 |
} |
60 |
|
61 |
void wxStreamBuffer::InitBuffer() |
62 |
{ |
63 |
m_buffer_start = |
64 |
m_buffer_end = |
65 |
m_buffer_pos = NULL; |
66 |
m_buffer_size = 0; |
67 |
|
68 |
// if we are going to allocate the buffer, we should free it later as well |
69 |
m_destroybuf = true; |
70 |
} |
71 |
|
72 |
void wxStreamBuffer::Init() |
73 |
{ |
74 |
InitBuffer(); |
75 |
|
76 |
m_fixed = true; |
77 |
} |
78 |
|
79 |
wxStreamBuffer::wxStreamBuffer(BufMode mode) |
80 |
{ |
81 |
Init(); |
82 |
|
83 |
m_stream = NULL; |
84 |
m_mode = mode; |
85 |
|
86 |
m_flushable = false; |
87 |
} |
88 |
|
89 |
wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode) |
90 |
{ |
91 |
Init(); |
92 |
|
93 |
m_stream = &stream; |
94 |
m_mode = mode; |
95 |
|
96 |
m_flushable = true; |
97 |
} |
98 |
|
99 |
wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer) |
100 |
{ |
101 |
// doing this has big chances to lead to a crash when the source buffer is |
102 |
// destroyed (otherwise assume the caller knows what he does) |
103 |
wxASSERT_MSG( !buffer.m_destroybuf, |
104 |
_T("it's a bad idea to copy this buffer") ); |
105 |
|
106 |
m_buffer_start = buffer.m_buffer_start; |
107 |
m_buffer_end = buffer.m_buffer_end; |
108 |
m_buffer_pos = buffer.m_buffer_pos; |
109 |
m_buffer_size = buffer.m_buffer_size; |
110 |
m_fixed = buffer.m_fixed; |
111 |
m_flushable = buffer.m_flushable; |
112 |
m_stream = buffer.m_stream; |
113 |
m_mode = buffer.m_mode; |
114 |
m_destroybuf = false; |
115 |
} |
116 |
|
117 |
void wxStreamBuffer::FreeBuffer() |
118 |
{ |
119 |
if ( m_destroybuf ) |
120 |
{ |
121 |
free(m_buffer_start); |
122 |
m_buffer_start = NULL; |
123 |
} |
124 |
} |
125 |
|
126 |
wxStreamBuffer::~wxStreamBuffer() |
127 |
{ |
128 |
FreeBuffer(); |
129 |
} |
130 |
|
131 |
wxInputStream *wxStreamBuffer::GetInputStream() const |
132 |
{ |
133 |
return m_mode == write ? NULL : (wxInputStream *)m_stream; |
134 |
} |
135 |
|
136 |
wxOutputStream *wxStreamBuffer::GetOutputStream() const |
137 |
{ |
138 |
return m_mode == read ? NULL : (wxOutputStream *)m_stream; |
139 |
} |
140 |
|
141 |
void wxStreamBuffer::SetBufferIO(void *buffer_start, |
142 |
void *buffer_end, |
143 |
bool takeOwnership) |
144 |
{ |
145 |
SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start, |
146 |
takeOwnership); |
147 |
} |
148 |
|
149 |
void wxStreamBuffer::SetBufferIO(void *start, |
150 |
size_t len, |
151 |
bool takeOwnership) |
152 |
{ |
153 |
// start by freeing the old buffer |
154 |
FreeBuffer(); |
155 |
|
156 |
m_buffer_start = (char *)start; |
157 |
m_buffer_end = m_buffer_start + len; |
158 |
|
159 |
m_buffer_size = len; |
160 |
|
161 |
// if we own it, we free it |
162 |
m_destroybuf = takeOwnership; |
163 |
|
164 |
ResetBuffer(); |
165 |
} |
166 |
|
167 |
void wxStreamBuffer::SetBufferIO(size_t bufsize) |
168 |
{ |
169 |
if ( bufsize ) |
170 |
{ |
171 |
// this will free the old buffer and allocate the new one |
172 |
SetBufferIO(malloc(bufsize), bufsize, true /* take ownership */); |
173 |
} |
174 |
else // no buffer size => no buffer |
175 |
{ |
176 |
// still free the old one |
177 |
FreeBuffer(); |
178 |
InitBuffer(); |
179 |
} |
180 |
} |
181 |
|
182 |
void wxStreamBuffer::ResetBuffer() |
183 |
{ |
184 |
if ( m_stream ) |
185 |
{ |
186 |
m_stream->Reset(); |
187 |
m_stream->m_lastcount = 0; |
188 |
} |
189 |
|
190 |
m_buffer_pos = m_mode == read && m_flushable |
191 |
? m_buffer_end |
192 |
: m_buffer_start; |
193 |
} |
194 |
|
195 |
// fill the buffer with as much data as possible (only for read buffers) |
196 |
bool wxStreamBuffer::FillBuffer() |
197 |
{ |
198 |
wxInputStream *inStream = GetInputStream(); |
199 |
|
200 |
// It's legal to have no stream, so we don't complain about it just return false |
201 |
if ( !inStream ) |
202 |
return false; |
203 |
|
204 |
size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size); |
205 |
if ( !count ) |
206 |
return false; |
207 |
|
208 |
m_buffer_end = m_buffer_start + count; |
209 |
m_buffer_pos = m_buffer_start; |
210 |
|
211 |
return true; |
212 |
} |
213 |
|
214 |
// write the buffer contents to the stream (only for write buffers) |
215 |
bool wxStreamBuffer::FlushBuffer() |
216 |
{ |
217 |
wxCHECK_MSG( m_flushable, false, _T("can't flush this buffer") ); |
218 |
|
219 |
// FIXME: what is this check for? (VZ) |
220 |
if ( m_buffer_pos == m_buffer_start ) |
221 |
return false; |
222 |
|
223 |
wxOutputStream *outStream = GetOutputStream(); |
224 |
|
225 |
wxCHECK_MSG( outStream, false, _T("should have a stream in wxStreamBuffer") ); |
226 |
|
227 |
size_t current = m_buffer_pos - m_buffer_start; |
228 |
size_t count = outStream->OnSysWrite(m_buffer_start, current); |
229 |
if ( count != current ) |
230 |
return false; |
231 |
|
232 |
m_buffer_pos = m_buffer_start; |
233 |
|
234 |
return true; |
235 |
} |
236 |
|
237 |
size_t wxStreamBuffer::GetDataLeft() |
238 |
{ |
239 |
/* Why is this done? RR. */ |
240 |
if ( m_buffer_pos == m_buffer_end && m_flushable) |
241 |
FillBuffer(); |
242 |
|
243 |
return GetBytesLeft(); |
244 |
} |
245 |
|
246 |
// copy up to size bytes from our buffer into the provided one |
247 |
void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size) |
248 |
{ |
249 |
// don't get more bytes than left in the buffer |
250 |
size_t left = GetBytesLeft(); |
251 |
|
252 |
if ( size > left ) |
253 |
size = left; |
254 |
|
255 |
memcpy(buffer, m_buffer_pos, size); |
256 |
m_buffer_pos += size; |
257 |
} |
258 |
|
259 |
// copy the contents of the provided buffer into this one |
260 |
void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size) |
261 |
{ |
262 |
size_t left = GetBytesLeft(); |
263 |
|
264 |
if ( size > left ) |
265 |
{ |
266 |
if ( m_fixed ) |
267 |
{ |
268 |
// we can't realloc the buffer, so just copy what we can |
269 |
size = left; |
270 |
} |
271 |
else // !m_fixed |
272 |
{ |
273 |
// realloc the buffer to have enough space for the data |
274 |
size_t delta = m_buffer_pos - m_buffer_start; |
275 |
|
276 |
char *startOld = m_buffer_start; |
277 |
m_buffer_size += size; |
278 |
m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size); |
279 |
if ( !m_buffer_start ) |
280 |
{ |
281 |
// don't leak memory if realloc() failed |
282 |
m_buffer_start = startOld; |
283 |
m_buffer_size -= size; |
284 |
|
285 |
// what else can we do? |
286 |
return; |
287 |
} |
288 |
|
289 |
// adjust the pointers invalidated by realloc() |
290 |
m_buffer_pos = m_buffer_start + delta; |
291 |
m_buffer_end = m_buffer_start + m_buffer_size; |
292 |
} |
293 |
} |
294 |
|
295 |
memcpy(m_buffer_pos, buffer, size); |
296 |
m_buffer_pos += size; |
297 |
} |
298 |
|
299 |
void wxStreamBuffer::PutChar(char c) |
300 |
{ |
301 |
wxOutputStream *outStream = GetOutputStream(); |
302 |
|
303 |
wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") ); |
304 |
|
305 |
// if we don't have buffer at all, just forward this call to the stream, |
306 |
if ( !HasBuffer() ) |
307 |
{ |
308 |
outStream->OnSysWrite(&c, sizeof(c)); |
309 |
} |
310 |
else |
311 |
{ |
312 |
// otherwise check we have enough space left |
313 |
if ( !GetDataLeft() && !FlushBuffer() ) |
314 |
{ |
315 |
// we don't |
316 |
SetError(wxSTREAM_WRITE_ERROR); |
317 |
} |
318 |
else |
319 |
{ |
320 |
PutToBuffer(&c, sizeof(c)); |
321 |
m_stream->m_lastcount = 1; |
322 |
} |
323 |
} |
324 |
} |
325 |
|
326 |
char wxStreamBuffer::Peek() |
327 |
{ |
328 |
wxCHECK_MSG( m_stream && HasBuffer(), 0, |
329 |
_T("should have the stream and the buffer in wxStreamBuffer") ); |
330 |
|
331 |
if ( !GetDataLeft() ) |
332 |
{ |
333 |
SetError(wxSTREAM_READ_ERROR); |
334 |
return 0; |
335 |
} |
336 |
|
337 |
char c; |
338 |
GetFromBuffer(&c, sizeof(c)); |
339 |
m_buffer_pos--; |
340 |
|
341 |
return c; |
342 |
} |
343 |
|
344 |
char wxStreamBuffer::GetChar() |
345 |
{ |
346 |
wxInputStream *inStream = GetInputStream(); |
347 |
|
348 |
wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); |
349 |
|
350 |
char c; |
351 |
if ( !HasBuffer() ) |
352 |
{ |
353 |
inStream->OnSysRead(&c, sizeof(c)); |
354 |
} |
355 |
else |
356 |
{ |
357 |
if ( !GetDataLeft() ) |
358 |
{ |
359 |
SetError(wxSTREAM_READ_ERROR); |
360 |
c = 0; |
361 |
} |
362 |
else |
363 |
{ |
364 |
GetFromBuffer(&c, sizeof(c)); |
365 |
m_stream->m_lastcount = 1; |
366 |
} |
367 |
} |
368 |
|
369 |
return c; |
370 |
} |
371 |
|
372 |
size_t wxStreamBuffer::Read(void *buffer, size_t size) |
373 |
{ |
374 |
wxASSERT_MSG( buffer, _T("Warning: Null pointer is about to be used") ); |
375 |
|
376 |
/* Clear buffer first */ |
377 |
memset(buffer, 0x00, size); |
378 |
|
379 |
// lasterror is reset before all new IO calls |
380 |
if ( m_stream ) |
381 |
m_stream->Reset(); |
382 |
|
383 |
size_t readBytes; |
384 |
if ( !HasBuffer() ) |
385 |
{ |
386 |
wxInputStream *inStream = GetInputStream(); |
387 |
|
388 |
wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); |
389 |
|
390 |
readBytes = inStream->OnSysRead(buffer, size); |
391 |
} |
392 |
else // we have a buffer, use it |
393 |
{ |
394 |
size_t orig_size = size; |
395 |
|
396 |
while ( size > 0 ) |
397 |
{ |
398 |
size_t left = GetDataLeft(); |
399 |
|
400 |
// if the requested number of bytes if greater than the buffer |
401 |
// size, read data in chunks |
402 |
if ( size > left ) |
403 |
{ |
404 |
GetFromBuffer(buffer, left); |
405 |
size -= left; |
406 |
buffer = (char *)buffer + left; |
407 |
|
408 |
if ( !FillBuffer() ) |
409 |
{ |
410 |
SetError(wxSTREAM_EOF); |
411 |
break; |
412 |
} |
413 |
} |
414 |
else // otherwise just do it in one gulp |
415 |
{ |
416 |
GetFromBuffer(buffer, size); |
417 |
size = 0; |
418 |
} |
419 |
} |
420 |
|
421 |
readBytes = orig_size - size; |
422 |
} |
423 |
|
424 |
if ( m_stream ) |
425 |
m_stream->m_lastcount = readBytes; |
426 |
|
427 |
return readBytes; |
428 |
} |
429 |
|
430 |
// this should really be called "Copy()" |
431 |
size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf) |
432 |
{ |
433 |
wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") ); |
434 |
|
435 |
char buf[BUF_TEMP_SIZE]; |
436 |
size_t nRead, |
437 |
total = 0; |
438 |
|
439 |
do |
440 |
{ |
441 |
nRead = Read(buf, WXSIZEOF(buf)); |
442 |
if ( nRead ) |
443 |
{ |
444 |
nRead = dbuf->Write(buf, nRead); |
445 |
total += nRead; |
446 |
} |
447 |
} |
448 |
while ( nRead ); |
449 |
|
450 |
return total; |
451 |
} |
452 |
|
453 |
size_t wxStreamBuffer::Write(const void *buffer, size_t size) |
454 |
{ |
455 |
wxASSERT_MSG( buffer, _T("Warning: Null pointer is about to be send") ); |
456 |
|
457 |
if (m_stream) |
458 |
{ |
459 |
// lasterror is reset before all new IO calls |
460 |
m_stream->Reset(); |
461 |
} |
462 |
|
463 |
size_t ret; |
464 |
|
465 |
if ( !HasBuffer() && m_fixed ) |
466 |
{ |
467 |
wxOutputStream *outStream = GetOutputStream(); |
468 |
|
469 |
wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") ); |
470 |
|
471 |
// no buffer, just forward the call to the stream |
472 |
ret = outStream->OnSysWrite(buffer, size); |
473 |
} |
474 |
else // we [may] have a buffer, use it |
475 |
{ |
476 |
size_t orig_size = size; |
477 |
|
478 |
while ( size > 0 ) |
479 |
{ |
480 |
size_t left = GetBytesLeft(); |
481 |
|
482 |
// if the buffer is too large to fit in the stream buffer, split |
483 |
// it in smaller parts |
484 |
// |
485 |
// NB: If stream buffer isn't fixed (as for wxMemoryOutputStream), |
486 |
// we always go to the second case. |
487 |
// |
488 |
// FIXME: fine, but if it fails we should (re)try writing it by |
489 |
// chunks as this will (hopefully) always work (VZ) |
490 |
|
491 |
if ( size > left && m_fixed ) |
492 |
{ |
493 |
PutToBuffer(buffer, left); |
494 |
size -= left; |
495 |
buffer = (char *)buffer + left; |
496 |
|
497 |
if ( !FlushBuffer() ) |
498 |
{ |
499 |
SetError(wxSTREAM_WRITE_ERROR); |
500 |
|
501 |
break; |
502 |
} |
503 |
|
504 |
m_buffer_pos = m_buffer_start; |
505 |
} |
506 |
else // we can do it in one gulp |
507 |
{ |
508 |
PutToBuffer(buffer, size); |
509 |
size = 0; |
510 |
} |
511 |
} |
512 |
|
513 |
ret = orig_size - size; |
514 |
} |
515 |
|
516 |
if (m_stream) |
517 |
{ |
518 |
// i am not entirely sure what we do this for |
519 |
m_stream->m_lastcount = ret; |
520 |
} |
521 |
|
522 |
return ret; |
523 |
} |
524 |
|
525 |
size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf) |
526 |
{ |
527 |
wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") ); |
528 |
wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") ); |
529 |
|
530 |
char buf[BUF_TEMP_SIZE]; |
531 |
size_t nWrite, |
532 |
total = 0; |
533 |
|
534 |
do |
535 |
{ |
536 |
size_t nRead = sbuf->Read(buf, WXSIZEOF(buf)); |
537 |
if ( nRead ) |
538 |
{ |
539 |
nWrite = Write(buf, nRead); |
540 |
if ( nWrite < nRead ) |
541 |
{ |
542 |
// put back data we couldn't copy |
543 |
wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream(); |
544 |
|
545 |
in_stream->Ungetch(buf + nWrite, nRead - nWrite); |
546 |
} |
547 |
|
548 |
total += nWrite; |
549 |
} |
550 |
else |
551 |
{ |
552 |
nWrite = 0; |
553 |
} |
554 |
} |
555 |
while ( nWrite == WXSIZEOF(buf) ); |
556 |
|
557 |
return total; |
558 |
} |
559 |
|
560 |
wxFileOffset wxStreamBuffer::Seek(wxFileOffset pos, wxSeekMode mode) |
561 |
{ |
562 |
wxFileOffset ret_off, diff; |
563 |
|
564 |
wxFileOffset last_access = GetLastAccess(); |
565 |
|
566 |
if ( !m_flushable ) |
567 |
{ |
568 |
switch (mode) |
569 |
{ |
570 |
case wxFromStart: |
571 |
diff = pos; |
572 |
break; |
573 |
|
574 |
case wxFromCurrent: |
575 |
diff = pos + GetIntPosition(); |
576 |
break; |
577 |
|
578 |
case wxFromEnd: |
579 |
diff = pos + last_access; |
580 |
break; |
581 |
|
582 |
default: |
583 |
wxFAIL_MSG( _T("invalid seek mode") ); |
584 |
|
585 |
return wxInvalidOffset; |
586 |
} |
587 |
if (diff < 0 || diff > last_access) |
588 |
return wxInvalidOffset; |
589 |
size_t int_diff = wx_truncate_cast(size_t, diff); |
590 |
wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") ); |
591 |
SetIntPosition(int_diff); |
592 |
return diff; |
593 |
} |
594 |
|
595 |
switch ( mode ) |
596 |
{ |
597 |
case wxFromStart: |
598 |
// We'll try to compute an internal position later ... |
599 |
ret_off = m_stream->OnSysSeek(pos, wxFromStart); |
600 |
ResetBuffer(); |
601 |
return ret_off; |
602 |
|
603 |
case wxFromCurrent: |
604 |
diff = pos + GetIntPosition(); |
605 |
|
606 |
if ( (diff > last_access) || (diff < 0) ) |
607 |
{ |
608 |
// We must take into account the fact that we have read |
609 |
// something previously. |
610 |
ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent); |
611 |
ResetBuffer(); |
612 |
return ret_off; |
613 |
} |
614 |
else |
615 |
{ |
616 |
size_t int_diff = wx_truncate_cast(size_t, diff); |
617 |
wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") ); |
618 |
SetIntPosition(int_diff); |
619 |
return pos; |
620 |
} |
621 |
|
622 |
case wxFromEnd: |
623 |
// Hard to compute: always seek to the requested position. |
624 |
ret_off = m_stream->OnSysSeek(pos, wxFromEnd); |
625 |
ResetBuffer(); |
626 |
return ret_off; |
627 |
} |
628 |
|
629 |
return wxInvalidOffset; |
630 |
} |
631 |
|
632 |
wxFileOffset wxStreamBuffer::Tell() const |
633 |
{ |
634 |
wxFileOffset pos; |
635 |
|
636 |
// ask the stream for position if we have a real one |
637 |
if ( m_stream ) |
638 |
{ |
639 |
pos = m_stream->OnSysTell(); |
640 |
if ( pos == wxInvalidOffset ) |
641 |
return wxInvalidOffset; |
642 |
} |
643 |
else // no associated stream |
644 |
{ |
645 |
pos = 0; |
646 |
} |
647 |
|
648 |
pos += GetIntPosition(); |
649 |
|
650 |
if ( m_mode == read && m_flushable ) |
651 |
pos -= GetLastAccess(); |
652 |
|
653 |
return pos; |
654 |
} |
655 |
|
656 |
// ---------------------------------------------------------------------------- |
657 |
// wxStreamBase |
658 |
// ---------------------------------------------------------------------------- |
659 |
|
660 |
wxStreamBase::wxStreamBase() |
661 |
{ |
662 |
m_lasterror = wxSTREAM_NO_ERROR; |
663 |
m_lastcount = 0; |
664 |
} |
665 |
|
666 |
wxStreamBase::~wxStreamBase() |
667 |
{ |
668 |
} |
669 |
|
670 |
size_t wxStreamBase::GetSize() const |
671 |
{ |
672 |
wxFileOffset length = GetLength(); |
673 |
if ( length == (wxFileOffset)wxInvalidOffset ) |
674 |
return 0; |
675 |
|
676 |
const size_t len = wx_truncate_cast(size_t, length); |
677 |
wxASSERT_MSG( len == length + size_t(0), _T("large files not supported") ); |
678 |
|
679 |
return len; |
680 |
} |
681 |
|
682 |
wxFileOffset wxStreamBase::OnSysSeek(wxFileOffset WXUNUSED(seek), wxSeekMode WXUNUSED(mode)) |
683 |
{ |
684 |
return wxInvalidOffset; |
685 |
} |
686 |
|
687 |
wxFileOffset wxStreamBase::OnSysTell() const |
688 |
{ |
689 |
return wxInvalidOffset; |
690 |
} |
691 |
|
692 |
// ---------------------------------------------------------------------------- |
693 |
// wxInputStream |
694 |
// ---------------------------------------------------------------------------- |
695 |
|
696 |
wxInputStream::wxInputStream() |
697 |
{ |
698 |
m_wback = NULL; |
699 |
m_wbacksize = |
700 |
m_wbackcur = 0; |
701 |
} |
702 |
|
703 |
wxInputStream::~wxInputStream() |
704 |
{ |
705 |
free(m_wback); |
706 |
} |
707 |
|
708 |
bool wxInputStream::CanRead() const |
709 |
{ |
710 |
// we don't know if there is anything to read or not and by default we |
711 |
// prefer to be optimistic and try to read data unless we know for sure |
712 |
// there is no more of it |
713 |
return m_lasterror != wxSTREAM_EOF; |
714 |
} |
715 |
|
716 |
bool wxInputStream::Eof() const |
717 |
{ |
718 |
// the only way the base class can know we're at EOF is when we'd already |
719 |
// tried to read beyond it in which case last error is set accordingly |
720 |
return GetLastError() == wxSTREAM_EOF; |
721 |
} |
722 |
|
723 |
char *wxInputStream::AllocSpaceWBack(size_t needed_size) |
724 |
{ |
725 |
// get number of bytes left from previous wback buffer |
726 |
size_t toget = m_wbacksize - m_wbackcur; |
727 |
|
728 |
// allocate a buffer large enough to hold prev + new data |
729 |
char *temp_b = (char *)malloc(needed_size + toget); |
730 |
|
731 |
if (!temp_b) |
732 |
return NULL; |
733 |
|
734 |
// copy previous data (and free old buffer) if needed |
735 |
if (m_wback) |
736 |
{ |
737 |
memmove(temp_b + needed_size, m_wback + m_wbackcur, toget); |
738 |
free(m_wback); |
739 |
} |
740 |
|
741 |
// done |
742 |
m_wback = temp_b; |
743 |
m_wbackcur = 0; |
744 |
m_wbacksize = needed_size + toget; |
745 |
|
746 |
return m_wback; |
747 |
} |
748 |
|
749 |
size_t wxInputStream::GetWBack(void *buf, size_t size) |
750 |
{ |
751 |
wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be used") ); |
752 |
|
753 |
/* Clear buffer first */ |
754 |
memset(buf, 0x00, size); |
755 |
|
756 |
if (!m_wback) |
757 |
return 0; |
758 |
|
759 |
// how many bytes do we have in the buffer? |
760 |
size_t toget = m_wbacksize - m_wbackcur; |
761 |
|
762 |
if ( size < toget ) |
763 |
{ |
764 |
// we won't read everything |
765 |
toget = size; |
766 |
} |
767 |
|
768 |
// copy the data from the cache |
769 |
memcpy(buf, m_wback + m_wbackcur, toget); |
770 |
|
771 |
m_wbackcur += toget; |
772 |
if ( m_wbackcur == m_wbacksize ) |
773 |
{ |
774 |
// TODO: should we really free it here all the time? maybe keep it? |
775 |
free(m_wback); |
776 |
m_wback = NULL; |
777 |
m_wbacksize = 0; |
778 |
m_wbackcur = 0; |
779 |
} |
780 |
|
781 |
// return the number of bytes copied |
782 |
return toget; |
783 |
} |
784 |
|
785 |
size_t wxInputStream::Ungetch(const void *buf, size_t bufsize) |
786 |
{ |
787 |
wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be used in Ungetch()") ); |
788 |
|
789 |
if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF ) |
790 |
{ |
791 |
// can't operate on this stream until the error is cleared |
792 |
return 0; |
793 |
} |
794 |
|
795 |
char *ptrback = AllocSpaceWBack(bufsize); |
796 |
if (!ptrback) |
797 |
return 0; |
798 |
|
799 |
// Eof() shouldn't return true any longer |
800 |
if ( m_lasterror == wxSTREAM_EOF ) |
801 |
m_lasterror = wxSTREAM_NO_ERROR; |
802 |
|
803 |
memcpy(ptrback, buf, bufsize); |
804 |
return bufsize; |
805 |
} |
806 |
|
807 |
bool wxInputStream::Ungetch(char c) |
808 |
{ |
809 |
return Ungetch(&c, sizeof(c)) != 0; |
810 |
} |
811 |
|
812 |
int wxInputStream::GetC() |
813 |
{ |
814 |
unsigned char c; |
815 |
Read(&c, sizeof(c)); |
816 |
return LastRead() ? c : wxEOF; |
817 |
} |
818 |
|
819 |
wxInputStream& wxInputStream::Read(void *buf, size_t size) |
820 |
{ |
821 |
wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be read") ); |
822 |
|
823 |
char *p = (char *)buf; |
824 |
m_lastcount = 0; |
825 |
|
826 |
size_t read = GetWBack(buf, size); |
827 |
for ( ;; ) |
828 |
{ |
829 |
size -= read; |
830 |
m_lastcount += read; |
831 |
p += read; |
832 |
|
833 |
if ( !size ) |
834 |
{ |
835 |
// we read the requested amount of data |
836 |
break; |
837 |
} |
838 |
|
839 |
if ( p != buf && !CanRead() ) |
840 |
{ |
841 |
// we have already read something and we would block in OnSysRead() |
842 |
// now: don't do it but return immediately |
843 |
break; |
844 |
} |
845 |
|
846 |
read = OnSysRead(p, size); |
847 |
if ( !read ) |
848 |
{ |
849 |
// no more data available |
850 |
break; |
851 |
} |
852 |
} |
853 |
|
854 |
return *this; |
855 |
} |
856 |
|
857 |
char wxInputStream::Peek() |
858 |
{ |
859 |
char c; |
860 |
Read(&c, sizeof(c)); |
861 |
if (m_lasterror == wxSTREAM_NO_ERROR) |
862 |
{ |
863 |
Ungetch(c); |
864 |
return c; |
865 |
} |
866 |
|
867 |
return 0; |
868 |
} |
869 |
|
870 |
wxInputStream& wxInputStream::Read(wxOutputStream& stream_out) |
871 |
{ |
872 |
size_t lastcount = 0; |
873 |
char buf[BUF_TEMP_SIZE]; |
874 |
|
875 |
for ( ;; ) |
876 |
{ |
877 |
size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead(); |
878 |
if ( !bytes_read ) |
879 |
break; |
880 |
|
881 |
if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read ) |
882 |
break; |
883 |
|
884 |
lastcount += bytes_read; |
885 |
} |
886 |
|
887 |
m_lastcount = lastcount; |
888 |
|
889 |
return *this; |
890 |
} |
891 |
|
892 |
wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) |
893 |
{ |
894 |
// RR: This code is duplicated in wxBufferedInputStream. This is |
895 |
// not really a good design, but buffered stream are different |
896 |
// from all other in that they handle two stream-related objects, |
897 |
// the stream buffer and parent stream. |
898 |
|
899 |
// I don't know whether it should be put as well in wxFileInputStream::OnSysSeek |
900 |
if (m_lasterror==wxSTREAM_EOF) |
901 |
m_lasterror=wxSTREAM_NO_ERROR; |
902 |
|
903 |
/* RR: A call to SeekI() will automatically invalidate any previous |
904 |
call to Ungetch(), otherwise it would be possible to SeekI() to |
905 |
one position, unread some bytes there, SeekI() to another position |
906 |
and the data would be corrupted. |
907 |
|
908 |
GRG: Could add code here to try to navigate within the wback |
909 |
buffer if possible, but is it really needed? It would only work |
910 |
when seeking in wxFromCurrent mode, else it would invalidate |
911 |
anyway... */ |
912 |
|
913 |
if (m_wback) |
914 |
{ |
915 |
wxLogDebug( wxT("Seeking in stream which has data written back to it.") ); |
916 |
|
917 |
free(m_wback); |
918 |
m_wback = NULL; |
919 |
m_wbacksize = 0; |
920 |
m_wbackcur = 0; |
921 |
} |
922 |
|
923 |
return OnSysSeek(pos, mode); |
924 |
} |
925 |
|
926 |
wxFileOffset wxInputStream::TellI() const |
927 |
{ |
928 |
wxFileOffset pos = OnSysTell(); |
929 |
|
930 |
if (pos != wxInvalidOffset) |
931 |
pos -= (m_wbacksize - m_wbackcur); |
932 |
|
933 |
return pos; |
934 |
} |
935 |
|
936 |
|
937 |
// ---------------------------------------------------------------------------- |
938 |
// wxOutputStream |
939 |
// ---------------------------------------------------------------------------- |
940 |
|
941 |
wxOutputStream::wxOutputStream() |
942 |
{ |
943 |
} |
944 |
|
945 |
wxOutputStream::~wxOutputStream() |
946 |
{ |
947 |
} |
948 |
|
949 |
size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer), |
950 |
size_t WXUNUSED(bufsize)) |
951 |
{ |
952 |
return 0; |
953 |
} |
954 |
|
955 |
void wxOutputStream::PutC(char c) |
956 |
{ |
957 |
Write(&c, sizeof(c)); |
958 |
} |
959 |
|
960 |
wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size) |
961 |
{ |
962 |
m_lastcount = OnSysWrite(buffer, size); |
963 |
return *this; |
964 |
} |
965 |
|
966 |
wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in) |
967 |
{ |
968 |
stream_in.Read(*this); |
969 |
return *this; |
970 |
} |
971 |
|
972 |
wxFileOffset wxOutputStream::TellO() const |
973 |
{ |
974 |
return OnSysTell(); |
975 |
} |
976 |
|
977 |
wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode) |
978 |
{ |
979 |
return OnSysSeek(pos, mode); |
980 |
} |
981 |
|
982 |
void wxOutputStream::Sync() |
983 |
{ |
984 |
} |
985 |
|
986 |
|
987 |
// ---------------------------------------------------------------------------- |
988 |
// wxCountingOutputStream |
989 |
// ---------------------------------------------------------------------------- |
990 |
|
991 |
wxCountingOutputStream::wxCountingOutputStream () |
992 |
{ |
993 |
m_currentPos = 0; |
994 |
} |
995 |
|
996 |
wxFileOffset wxCountingOutputStream::GetLength() const |
997 |
{ |
998 |
return m_lastcount; |
999 |
} |
1000 |
|
1001 |
size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer), |
1002 |
size_t size) |
1003 |
{ |
1004 |
m_currentPos += size; |
1005 |
if (m_currentPos > m_lastcount) |
1006 |
m_lastcount = m_currentPos; |
1007 |
|
1008 |
return m_currentPos; |
1009 |
} |
1010 |
|
1011 |
wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) |
1012 |
{ |
1013 |
ssize_t new_pos = wx_truncate_cast(ssize_t, pos); |
1014 |
|
1015 |
switch ( mode ) |
1016 |
{ |
1017 |
case wxFromStart: |
1018 |
wxCHECK_MSG( (wxFileOffset)new_pos == pos, wxInvalidOffset, wxT("huge position not supported") ); |
1019 |
break; |
1020 |
|
1021 |
case wxFromEnd: |
1022 |
new_pos = m_lastcount + new_pos; |
1023 |
wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_lastcount + pos), wxInvalidOffset, wxT("huge position not supported") ); |
1024 |
break; |
1025 |
|
1026 |
case wxFromCurrent: |
1027 |
new_pos = m_currentPos + new_pos; |
1028 |
wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_currentPos + pos), wxInvalidOffset, wxT("huge position not supported") ); |
1029 |
break; |
1030 |
|
1031 |
default: |
1032 |
wxFAIL_MSG( _T("invalid seek mode") ); |
1033 |
return wxInvalidOffset; |
1034 |
} |
1035 |
|
1036 |
m_currentPos = new_pos; |
1037 |
|
1038 |
if (m_currentPos > m_lastcount) |
1039 |
m_lastcount = m_currentPos; |
1040 |
|
1041 |
return m_currentPos; |
1042 |
} |
1043 |
|
1044 |
wxFileOffset wxCountingOutputStream::OnSysTell() const |
1045 |
{ |
1046 |
return m_currentPos; |
1047 |
} |
1048 |
|
1049 |
// ---------------------------------------------------------------------------- |
1050 |
// wxFilterInputStream |
1051 |
// ---------------------------------------------------------------------------- |
1052 |
|
1053 |
wxFilterInputStream::wxFilterInputStream() |
1054 |
: m_parent_i_stream(NULL), |
1055 |
m_owns(false) |
1056 |
{ |
1057 |
} |
1058 |
|
1059 |
wxFilterInputStream::wxFilterInputStream(wxInputStream& stream) |
1060 |
: m_parent_i_stream(&stream), |
1061 |
m_owns(false) |
1062 |
{ |
1063 |
} |
1064 |
|
1065 |
wxFilterInputStream::wxFilterInputStream(wxInputStream *stream) |
1066 |
: m_parent_i_stream(stream), |
1067 |
m_owns(true) |
1068 |
{ |
1069 |
} |
1070 |
|
1071 |
wxFilterInputStream::~wxFilterInputStream() |
1072 |
{ |
1073 |
if (m_owns) |
1074 |
delete m_parent_i_stream; |
1075 |
} |
1076 |
|
1077 |
// ---------------------------------------------------------------------------- |
1078 |
// wxFilterOutputStream |
1079 |
// ---------------------------------------------------------------------------- |
1080 |
|
1081 |
wxFilterOutputStream::wxFilterOutputStream() |
1082 |
: m_parent_o_stream(NULL), |
1083 |
m_owns(false) |
1084 |
{ |
1085 |
} |
1086 |
|
1087 |
wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream) |
1088 |
: m_parent_o_stream(&stream), |
1089 |
m_owns(false) |
1090 |
{ |
1091 |
} |
1092 |
|
1093 |
wxFilterOutputStream::wxFilterOutputStream(wxOutputStream *stream) |
1094 |
: m_parent_o_stream(stream), |
1095 |
m_owns(true) |
1096 |
{ |
1097 |
} |
1098 |
|
1099 |
bool wxFilterOutputStream::Close() |
1100 |
{ |
1101 |
if (m_parent_o_stream && m_owns) |
1102 |
return m_parent_o_stream->Close(); |
1103 |
else |
1104 |
return true; |
1105 |
} |
1106 |
|
1107 |
wxFilterOutputStream::~wxFilterOutputStream() |
1108 |
{ |
1109 |
if (m_owns) |
1110 |
delete m_parent_o_stream; |
1111 |
} |
1112 |
|
1113 |
// ---------------------------------------------------------------------------- |
1114 |
// wxFilterClassFactoryBase |
1115 |
// ---------------------------------------------------------------------------- |
1116 |
|
1117 |
IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase, wxObject) |
1118 |
|
1119 |
wxString wxFilterClassFactoryBase::PopExtension(const wxString& location) const |
1120 |
{ |
1121 |
return location.substr(0, FindExtension(location)); |
1122 |
} |
1123 |
|
1124 |
wxString::size_type wxFilterClassFactoryBase::FindExtension( |
1125 |
const wxChar *location) const |
1126 |
{ |
1127 |
size_t len = wxStrlen(location); |
1128 |
|
1129 |
for (const wxChar *const *p = GetProtocols(wxSTREAM_FILEEXT); *p; p++) |
1130 |
{ |
1131 |
size_t l = wxStrlen(*p); |
1132 |
|
1133 |
if (l <= len && wxStrcmp(*p, location + len - l) == 0) |
1134 |
return len - l; |
1135 |
} |
1136 |
|
1137 |
return wxString::npos; |
1138 |
} |
1139 |
|
1140 |
bool wxFilterClassFactoryBase::CanHandle(const wxChar *protocol, |
1141 |
wxStreamProtocolType type) const |
1142 |
{ |
1143 |
if (type == wxSTREAM_FILEEXT) |
1144 |
return FindExtension(protocol) != wxString::npos; |
1145 |
else |
1146 |
for (const wxChar *const *p = GetProtocols(type); *p; p++) |
1147 |
if (wxStrcmp(*p, protocol) == 0) |
1148 |
return true; |
1149 |
|
1150 |
return false; |
1151 |
} |
1152 |
|
1153 |
// ---------------------------------------------------------------------------- |
1154 |
// wxFilterClassFactory |
1155 |
// ---------------------------------------------------------------------------- |
1156 |
|
1157 |
IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory, wxFilterClassFactoryBase) |
1158 |
|
1159 |
wxFilterClassFactory *wxFilterClassFactory::sm_first = NULL; |
1160 |
|
1161 |
void wxFilterClassFactory::Remove() |
1162 |
{ |
1163 |
if (m_next != this) |
1164 |
{ |
1165 |
wxFilterClassFactory **pp = &sm_first; |
1166 |
|
1167 |
while (*pp != this) |
1168 |
pp = &(*pp)->m_next; |
1169 |
|
1170 |
*pp = m_next; |
1171 |
|
1172 |
m_next = this; |
1173 |
} |
1174 |
} |
1175 |
|
1176 |
// ---------------------------------------------------------------------------- |
1177 |
// wxBufferedInputStream |
1178 |
// ---------------------------------------------------------------------------- |
1179 |
|
1180 |
wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s, |
1181 |
wxStreamBuffer *buffer) |
1182 |
: wxFilterInputStream(s) |
1183 |
{ |
1184 |
if ( buffer ) |
1185 |
{ |
1186 |
// use the buffer provided by the user |
1187 |
m_i_streambuf = buffer; |
1188 |
} |
1189 |
else // create a default buffer |
1190 |
{ |
1191 |
m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read); |
1192 |
|
1193 |
m_i_streambuf->SetBufferIO(1024); |
1194 |
} |
1195 |
} |
1196 |
|
1197 |
wxBufferedInputStream::~wxBufferedInputStream() |
1198 |
{ |
1199 |
m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(), |
1200 |
wxFromCurrent); |
1201 |
|
1202 |
delete m_i_streambuf; |
1203 |
} |
1204 |
|
1205 |
char wxBufferedInputStream::Peek() |
1206 |
{ |
1207 |
return m_i_streambuf->Peek(); |
1208 |
} |
1209 |
|
1210 |
wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size) |
1211 |
{ |
1212 |
// reset the error flag |
1213 |
Reset(); |
1214 |
|
1215 |
// first read from the already cached data |
1216 |
m_lastcount = GetWBack(buf, size); |
1217 |
|
1218 |
// do we have to read anything more? |
1219 |
if ( m_lastcount < size ) |
1220 |
{ |
1221 |
size -= m_lastcount; |
1222 |
buf = (char *)buf + m_lastcount; |
1223 |
|
1224 |
// the call to wxStreamBuffer::Read() below may reset our m_lastcount |
1225 |
// (but it also may not do it if the buffer is associated to another |
1226 |
// existing stream and wasn't created by us), so save it |
1227 |
size_t countOld = m_lastcount; |
1228 |
|
1229 |
// the new count of the bytes read is the count of bytes read this time |
1230 |
m_lastcount = m_i_streambuf->Read(buf, size); |
1231 |
|
1232 |
// plus those we had read before |
1233 |
m_lastcount += countOld; |
1234 |
} |
1235 |
|
1236 |
return *this; |
1237 |
} |
1238 |
|
1239 |
wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) |
1240 |
{ |
1241 |
// RR: Look at wxInputStream for comments. |
1242 |
|
1243 |
if (m_lasterror==wxSTREAM_EOF) |
1244 |
Reset(); |
1245 |
|
1246 |
if (m_wback) |
1247 |
{ |
1248 |
wxLogDebug( wxT("Seeking in stream which has data written back to it.") ); |
1249 |
|
1250 |
free(m_wback); |
1251 |
m_wback = NULL; |
1252 |
m_wbacksize = 0; |
1253 |
m_wbackcur = 0; |
1254 |
} |
1255 |
|
1256 |
return m_i_streambuf->Seek(pos, mode); |
1257 |
} |
1258 |
|
1259 |
wxFileOffset wxBufferedInputStream::TellI() const |
1260 |
{ |
1261 |
wxFileOffset pos = m_i_streambuf->Tell(); |
1262 |
|
1263 |
if (pos != wxInvalidOffset) |
1264 |
pos -= (m_wbacksize - m_wbackcur); |
1265 |
|
1266 |
return pos; |
1267 |
} |
1268 |
|
1269 |
size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize) |
1270 |
{ |
1271 |
return m_parent_i_stream->Read(buffer, bufsize).LastRead(); |
1272 |
} |
1273 |
|
1274 |
wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) |
1275 |
{ |
1276 |
return m_parent_i_stream->SeekI(seek, mode); |
1277 |
} |
1278 |
|
1279 |
wxFileOffset wxBufferedInputStream::OnSysTell() const |
1280 |
{ |
1281 |
return m_parent_i_stream->TellI(); |
1282 |
} |
1283 |
|
1284 |
void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer) |
1285 |
{ |
1286 |
wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") ); |
1287 |
|
1288 |
delete m_i_streambuf; |
1289 |
m_i_streambuf = buffer; |
1290 |
} |
1291 |
|
1292 |
// ---------------------------------------------------------------------------- |
1293 |
// wxBufferedOutputStream |
1294 |
// ---------------------------------------------------------------------------- |
1295 |
|
1296 |
wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s, |
1297 |
wxStreamBuffer *buffer) |
1298 |
: wxFilterOutputStream(s) |
1299 |
{ |
1300 |
if ( buffer ) |
1301 |
{ |
1302 |
m_o_streambuf = buffer; |
1303 |
} |
1304 |
else // create a default one |
1305 |
{ |
1306 |
m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write); |
1307 |
|
1308 |
m_o_streambuf->SetBufferIO(1024); |
1309 |
} |
1310 |
} |
1311 |
|
1312 |
wxBufferedOutputStream::~wxBufferedOutputStream() |
1313 |
{ |
1314 |
Sync(); |
1315 |
delete m_o_streambuf; |
1316 |
} |
1317 |
|
1318 |
bool wxBufferedOutputStream::Close() |
1319 |
{ |
1320 |
Sync(); |
1321 |
return IsOk(); |
1322 |
} |
1323 |
|
1324 |
|
1325 |
wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size) |
1326 |
{ |
1327 |
m_lastcount = 0; |
1328 |
m_o_streambuf->Write(buffer, size); |
1329 |
return *this; |
1330 |
} |
1331 |
|
1332 |
wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode) |
1333 |
{ |
1334 |
Sync(); |
1335 |
return m_o_streambuf->Seek(pos, mode); |
1336 |
} |
1337 |
|
1338 |
wxFileOffset wxBufferedOutputStream::TellO() const |
1339 |
{ |
1340 |
return m_o_streambuf->Tell(); |
1341 |
} |
1342 |
|
1343 |
void wxBufferedOutputStream::Sync() |
1344 |
{ |
1345 |
m_o_streambuf->FlushBuffer(); |
1346 |
m_parent_o_stream->Sync(); |
1347 |
} |
1348 |
|
1349 |
size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize) |
1350 |
{ |
1351 |
return m_parent_o_stream->Write(buffer, bufsize).LastWrite(); |
1352 |
} |
1353 |
|
1354 |
wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) |
1355 |
{ |
1356 |
return m_parent_o_stream->SeekO(seek, mode); |
1357 |
} |
1358 |
|
1359 |
wxFileOffset wxBufferedOutputStream::OnSysTell() const |
1360 |
{ |
1361 |
return m_parent_o_stream->TellO(); |
1362 |
} |
1363 |
|
1364 |
wxFileOffset wxBufferedOutputStream::GetLength() const |
1365 |
{ |
1366 |
return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition(); |
1367 |
} |
1368 |
|
1369 |
void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer) |
1370 |
{ |
1371 |
wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") ); |
1372 |
|
1373 |
delete m_o_streambuf; |
1374 |
m_o_streambuf = buffer; |
1375 |
} |
1376 |
|
1377 |
// ---------------------------------------------------------------------------- |
1378 |
// Some IOManip function |
1379 |
// ---------------------------------------------------------------------------- |
1380 |
|
1381 |
wxOutputStream& wxEndL(wxOutputStream& stream) |
1382 |
{ |
1383 |
static const wxChar *eol = wxTextFile::GetEOL(); |
1384 |
|
1385 |
return stream.Write(eol, wxStrlen(eol)); |
1386 |
} |
1387 |
|
1388 |
#endif // wxUSE_STREAMS |