| // This file is part of the ustl library, an STL implementation. |
| // |
| // Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> |
| // This file is free software, distributed under the MIT License. |
| // |
| // mstream.cpp |
| // |
| // Helper classes to read and write packed binary streams. |
| // |
| |
| #include "mistream.h" |
| #include "sostream.h" |
| #include "ualgo.h" |
| #include "uassert.h" |
| #include "ustring.h" |
| |
| #if PLATFORM_ANDROID |
| #include <stdio.h> |
| #endif |
| |
| namespace ustl { |
| |
| //-------------------------------------------------------------------- |
| |
| /// \brief Constructs a stream attached to nothing. |
| /// A stream attached to nothing is not usable. Call Link() functions |
| /// inherited from cmemlink to attach to some memory block. |
| /// |
| istream::istream (void) |
| : cmemlink (), |
| m_Pos (0) |
| { |
| } |
| |
| /// Attaches the stream to a block at \p p of size \p n. |
| istream::istream (const void* p, size_type n) |
| : cmemlink (p, n), |
| m_Pos (0) |
| { |
| } |
| |
| /// Attaches to the block pointed to by \p source. |
| istream::istream (const cmemlink& source) |
| : cmemlink (source), |
| m_Pos (0) |
| { |
| } |
| |
| /// Attaches to the block pointed to by source of size source.pos() |
| istream::istream (const ostream& source) |
| : cmemlink (source.begin(), source.pos()), |
| m_Pos (0) |
| { |
| } |
| |
| /// Swaps contents with \p is |
| void istream::swap (istream& is) |
| { |
| cmemlink::swap (is); |
| ::ustl::swap (m_Pos, is.m_Pos); |
| } |
| |
| /// Checks that \p n bytes are available in the stream, or else throws. |
| void istream::verify_remaining (const char* op, const char* type, size_t n) const |
| { |
| if (remaining() < n) |
| #if PLATFORM_ANDROID |
| printf("stream bounds exception\n"); |
| #else |
| throw stream_bounds_exception (op, type, pos(), n, remaining()); |
| #endif |
| } |
| |
| /// Reads \p n bytes into \p buffer. |
| void istream::read (void* buffer, size_type n) |
| { |
| #ifdef WANT_STREAM_BOUNDS_CHECKING |
| verify_remaining ("read", "binary data", n); |
| #else |
| assert (remaining() >= n && "Reading past end of buffer. Make sure you are reading the right format."); |
| #endif |
| copy_n (ipos(), n, reinterpret_cast<value_type*>(buffer)); |
| m_Pos += n; |
| } |
| |
| /// Reads a null-terminated string into \p str. |
| void istream::read_strz (string& str) |
| { |
| const_iterator zp = find (ipos(), end(), string::c_Terminator); |
| if (zp == end()) |
| zp = ipos(); |
| const size_type strl = distance (ipos(), zp); |
| str.resize (strl); |
| copy (ipos(), zp, str.begin()); |
| m_Pos += strl + 1; |
| } |
| |
| /// Reads at most \p n bytes into \p s. |
| istream::size_type istream::readsome (void* s, size_type n) |
| { |
| if (remaining() < n) |
| underflow (n); |
| const size_type ntr (min (n, remaining())); |
| read (s, ntr); |
| return (ntr); |
| } |
| |
| /// Writes all unread bytes into \p os. |
| void istream::write (ostream& os) const |
| { |
| os.write (ipos(), remaining()); |
| } |
| |
| /// Writes the object to stream \p os. |
| void istream::text_write (ostringstream& os) const |
| { |
| os.write (ipos(), remaining()); |
| } |
| |
| /// Links to \p p of size \p n |
| void istream::unlink (void) |
| { |
| cmemlink::unlink(); |
| m_Pos = 0; |
| } |
| |
| //-------------------------------------------------------------------- |
| |
| /// \brief Constructs a stream attached to nothing. |
| /// A stream attached to nothing is not usable. Call Link() functions |
| /// inherited from memlink to attach to some memory block. |
| /// |
| ostream::ostream (void) |
| : memlink (), |
| m_Pos (0) |
| { |
| } |
| |
| /// Attaches the stream to a block at \p p of size \p n. |
| ostream::ostream (void* p, size_type n) |
| : memlink (p, n), |
| m_Pos (0) |
| { |
| } |
| |
| /// Attaches to the block pointed to by \p source. |
| ostream::ostream (const memlink& source) |
| : memlink (source), |
| m_Pos (0) |
| { |
| } |
| |
| /// Links to \p p of size \p n |
| void ostream::unlink (void) |
| { |
| memlink::unlink(); |
| m_Pos = 0; |
| } |
| |
| /// Checks that \p n bytes are available in the stream, or else throws. |
| void ostream::verify_remaining (const char* op, const char* type, size_t n) const |
| { |
| if (remaining() < n) |
| #if PLATFORM_ANDROID |
| printf("stream bounds exception\n"); |
| #else |
| throw stream_bounds_exception (op, type, pos(), n, remaining()); |
| #endif |
| } |
| |
| /// Aligns the write pointer on \p grain. The skipped bytes are zeroed. |
| void ostream::align (size_type grain) |
| { |
| const size_t r = pos() % grain; |
| size_t nb = grain - r; |
| if (!r) nb = 0; |
| #ifdef WANT_STREAM_BOUNDS_CHECKING |
| verify_remaining ("align", "padding", nb); |
| #else |
| assert (remaining() >= nb && "Buffer overrun. Check your stream size calculations."); |
| #endif |
| fill_n (ipos(), nb, '\x0'); |
| m_Pos += nb; |
| } |
| |
| /// Writes \p n bytes from \p buffer. |
| void ostream::write (const void* buffer, size_type n) |
| { |
| #ifdef WANT_STREAM_BOUNDS_CHECKING |
| verify_remaining ("write", "binary data", n); |
| #else |
| assert (remaining() >= n && "Buffer overrun. Check your stream size calculations."); |
| #endif |
| copy_n (const_iterator(buffer), n, ipos()); |
| m_Pos += n; |
| } |
| |
| /// Writes \p str as a null-terminated string. |
| void ostream::write_strz (const char* str) |
| { |
| write (str, strlen(str)); |
| iwrite (string::c_Terminator); |
| } |
| |
| /// Writes all available data from \p is. |
| void ostream::read (istream& is) |
| { |
| is.write (*this); |
| is.seek (is.size()); |
| } |
| |
| /// Writes all written data to \p os. |
| void ostream::text_write (ostringstream& os) const |
| { |
| os.write (begin(), pos()); |
| } |
| |
| /// Inserts an empty area of \p size, at \p start. |
| void ostream::insert (iterator start, size_type s) |
| { |
| memlink::insert (start, s); |
| m_Pos += s; |
| } |
| |
| /// Erases an area of \p size, at \p start. |
| void ostream::erase (iterator start, size_type s) |
| { |
| m_Pos -= s; |
| memlink::erase (start, s); |
| } |
| |
| /// Swaps with \p os |
| void ostream::swap (ostream& os) |
| { |
| memlink::swap (os); |
| ::ustl::swap (m_Pos, os.m_Pos); |
| } |
| |
| //-------------------------------------------------------------------- |
| |
| } // namespace ustl |
| |