fix seek within subStream

This commit is contained in:
David Rose 2002-08-05 14:56:13 +00:00
parent 7a33acfa3b
commit c5103b67e5
2 changed files with 87 additions and 38 deletions

View File

@ -31,9 +31,29 @@ typedef int streamsize;
SubStreamBuf::
SubStreamBuf() {
_source = (istream *)NULL;
// _start is the streampos of the first byte of the SubStream within
// its parent stream.
_start = 0;
// _end is the streampos of the byte following the last byte of the
// SubStream within its parent stream. If _end is 0, the SubStream
// continues to the end of the parent stream, wherever that is.
_end = 0;
// _cur is the streampos of the end of the read buffer (that is,
// egptr()) within the parent stream. By comparing _cur to gpos(),
// we can determine the actual current file position.
_cur = 0;
// _unused counts the number of bytes at the beginning of the buffer
// that are unused. Usually this is 0, but when we reach the end of
// the file we might not need the whole buffer to read the last bit,
// so the first part of the buffer is unused. This is important to
// prevent us from inadvertently seeking into the unused part of the
// buffer.
_unused = 0;
#ifndef WIN32_VC
// These lines, which are essential on Irix and Linux, seem to be
// unnecessary and not understood on Windows.
@ -63,6 +83,7 @@ open(istream *source, streampos start, streampos end) {
_start = start;
_end = end;
_cur = _start;
_unused = 0;
}
////////////////////////////////////////////////////////////////////
@ -72,11 +93,11 @@ open(istream *source, streampos start, streampos end) {
////////////////////////////////////////////////////////////////////
void SubStreamBuf::
close() {
sync();
_source = (istream *)NULL;
_start = 0;
_end = 0;
_cur = 0;
_unused = 0;
}
////////////////////////////////////////////////////////////////////
@ -86,22 +107,52 @@ close() {
////////////////////////////////////////////////////////////////////
streampos SubStreamBuf::
seekoff(streamoff off, ios::seek_dir dir, int mode) {
// Invariant: _cur points to the file location of the buffer at
// egptr().
// Use this to determine the actual file position right now.
streamsize n = egptr() - gptr();
streampos cur_pos = _cur - n;
streampos new_pos = cur_pos;
// Now adjust the data pointer appropriately.
switch (dir) {
case ios::beg:
_cur = _start + off;
new_pos = _start + off;
break;
case ios::cur:
_cur += off;
new_pos = cur_pos + off;
break;
case ios::end:
_cur = _end + off;
if (_end == 0) {
// If the end of the file is unspecified, we have to seek to
// find it.
_source->seekg(off, ios::end);
new_pos = _source->tellg();
} else {
new_pos = _end + off;
}
break;
}
_cur = max(_start, _cur);
return _cur - _start;
new_pos = max(_start, new_pos);
streamsize delta = new_pos - cur_pos;
if (gptr() + delta >= eback() + _unused && gptr() + delta <= egptr()) {
// If we can get away with just bumping the gptr within the
// buffer, do so.
gbump(delta);
} else {
// Otherwise, empty the buffer and force it to call underflow().
gbump(n);
_cur = new_pos;
}
return new_pos - _start;
}
////////////////////////////////////////////////////////////////////
@ -113,19 +164,6 @@ seekoff(streamoff off, ios::seek_dir dir, int mode) {
int SubStreamBuf::
overflow(int c) {
// We don't support ostream.
/*
streamsize n = pptr() - pbase();
if (n != 0) {
write_chars(pbase(), n, false);
pbump(-n); // reset pptr()
}
if (c != EOF) {
// write one more character
char ch = c;
write_chars(&ch, 1, false);
}
*/
return 0;
}
@ -137,19 +175,9 @@ overflow(int c) {
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
sync() {
/*
streamsize n = pptr() - pbase();
if (n != 0) {
write_chars(pbase(), n, false);
pbump(-n);
}
*/
streamsize n = egptr() - gptr();
if (n != 0) {
gbump(n);
_cur += n;
}
gbump(n);
return 0;
}
@ -172,14 +200,14 @@ underflow() {
// Sometimes underflow() is called even if the buffer is not empty.
if (gptr() >= egptr()) {
if (_cur >= _end) {
if (_end != 0 && _cur >= _end) {
// We're done.
return EOF;
}
size_t buffer_size = egptr() - eback();
size_t num_bytes;
if (_end - _cur > (streampos)buffer_size) {
if (_end == 0 || _end - _cur > (streampos)buffer_size) {
// We have enough bytes in the input stream to fill our buffer.
num_bytes = buffer_size;
} else {
@ -192,13 +220,33 @@ underflow() {
nassertr(gptr() + num_bytes <= egptr(), EOF);
_source->read(gptr(), num_bytes);
if (_source->gcount() != num_bytes) {
// Oops, something screwed up.
_cur = _end;
return EOF;
size_t read_count = _source->gcount();
if (read_count != num_bytes) {
// Oops, we didn't read what we thought we would.
if (read_count == 0) {
_unused = buffer_size;
if (_end != 0) {
_end = _cur;
}
return EOF;
}
// Slide what we did read to the top of the buffer.
nassertr(read_count < num_bytes, EOF);
size_t delta = num_bytes - read_count;
memmove(gptr() + delta, gptr(), read_count);
gbump(delta);
}
_cur += num_bytes;
// Now record whatever bytes at the beginning of the buffer are
// unused, so we won't try to seek into that area.
_unused = buffer_size - read_count;
// Invariant: _cur points to the file location of the buffer at
// egptr().
_cur += read_count;
}
return (unsigned char)*gptr();

View File

@ -45,6 +45,7 @@ private:
streampos _start;
streampos _end;
streampos _cur;
size_t _unused;
};
#endif