From cc437b9654244bfb8b638f98252aa34145323b9c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 20 May 2013 13:15:16 +0000 Subject: [PATCH 1/1] Add wxInputStream::ReadAll() and wxOutputStream::WriteAll(). Unlike Read() and Write(), these functions always transfer exactly the specified number of bytes or fail. See #12056. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74034 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + include/wx/stream.h | 11 ++++++++ interface/wx/stream.h | 31 +++++++++++++++++++++ src/common/stream.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+) diff --git a/docs/changes.txt b/docs/changes.txt index 20015c11a3..28c1415142 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -576,6 +576,7 @@ All: - Add wxDIR_NO_FOLLOW flag for wxDir traversal (David Hart). - Allow testing for symlink/FIFO/socket existence in wxFileName (David Hart). - Many important bug fixes in wxFileSystemWatcher (David Hart). +- Add wxInputStream::ReadAll() and wxOutputStream::WriteAll() (Catalin Raceanu). - Add new wxFSW_EVENT_ATTRIB and wxFSW_EVENT_UNMOUNT flags (David Hart). - Add separate read/written bytes counters and per-direction NOWAIT and WAITALL flags to wxSocket (Rob Bresalier). diff --git a/include/wx/stream.h b/include/wx/stream.h index 80c81bcbdc..7f57e1f39c 100644 --- a/include/wx/stream.h +++ b/include/wx/stream.h @@ -128,6 +128,11 @@ public: // it means that EOF has been reached. virtual wxInputStream& Read(void *buffer, size_t size); + // Read exactly the given number of bytes, unlike Read(), which may read + // less than the requested amount of data without returning an error, this + // method either reads all the data or returns false. + bool ReadAll(void *buffer, size_t size); + // copy the entire contents of this stream into streamOut, stopping only // when EOF is reached or an error occurs wxInputStream& Read(wxOutputStream& streamOut); @@ -233,6 +238,12 @@ public: void PutC(char c); virtual wxOutputStream& Write(const void *buffer, size_t size); + + // This is ReadAll() equivalent for Write(): it either writes exactly the + // given number of bytes or returns false, unlike Write() which can write + // less data than requested but still return without error. + bool WriteAll(const void *buffer, size_t size); + wxOutputStream& Write(wxInputStream& stream_in); virtual wxFileOffset SeekO(wxFileOffset pos, wxSeekMode mode = wxFromStart); diff --git a/interface/wx/stream.h b/interface/wx/stream.h index 6fd27a4126..7bed3174ca 100644 --- a/interface/wx/stream.h +++ b/interface/wx/stream.h @@ -537,6 +537,20 @@ public: */ wxOutputStream& Write(wxInputStream& stream_in); + /** + Writes exactly the specified number of bytes from the buffer. + + Returns @true if exactly @a size bytes were written. Otherwise, returns + @false and LastWrite() should be used to retrieve the exact amount of + the data written if necessary. + + This method uses repeated calls to Write() (which may return writing + only part of the data) if necessary. + + @since 2.9.5 + */ + bool WriteAll(const void* buffer, size_t size); + protected: /** Internal function. It is called when the stream wants to write data of the @@ -629,6 +643,23 @@ public: */ wxInputStream& Read(wxOutputStream& stream_out); + /** + Reads exactly the specified number of bytes into the buffer. + + Returns @true only if the entire amount of data was read, otherwise + @false is returned and the number of bytes really read can be retrieved + using LastRead(), as with Read(). + + This method uses repeated calls to Read() (which may return after + reading less than the requested number of bytes) if necessary. + + @warning + The buffer absolutely needs to have at least the specified size. + + @since 2.9.5 + */ + bool ReadAll(void* buffer, size_t size); + /** Changes the stream current position. diff --git a/src/common/stream.cpp b/src/common/stream.cpp index f7cd2ea2c5..94a1244b2b 100644 --- a/src/common/stream.cpp +++ b/src/common/stream.cpp @@ -913,6 +913,42 @@ wxInputStream& wxInputStream::Read(wxOutputStream& stream_out) return *this; } +bool wxInputStream::ReadAll(void *buffer_, size_t size) +{ + char* buffer = static_cast(buffer_); + + m_lastcount = 0; + + for ( ;; ) + { + const size_t lastCount = Read(buffer, size).LastRead(); + + // There is no point in continuing looping if we can't read anything at + // all. + if ( !lastCount ) + break; + + m_lastcount += lastCount; + + // ... Or if an error occurred on the stream. + if ( !IsOk() ) + break; + + // Return successfully if we read exactly the requested number of + // bytes (normally the ">" case should never occur and so we could use + // "==" test, but be safe and avoid overflowing size even in case of + // bugs in LastRead()). + if ( lastCount >= size ) + return true; + + // Advance the buffer before trying to read the rest of data. + size -= lastCount; + buffer += lastCount; + } + + return false; +} + wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) { // RR: This code is duplicated in wxBufferedInputStream. This is @@ -1030,6 +1066,34 @@ wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in) return *this; } +bool wxOutputStream::WriteAll(const void *buffer_, size_t size) +{ + // This exactly mirrors ReadAll(), see there for more comments. + const char* buffer = static_cast(buffer_); + + m_lastcount = 0; + + for ( ;; ) + { + const size_t lastCount = Write(buffer, size).LastWrite(); + if ( !lastCount ) + break; + + m_lastcount += lastCount; + + if ( !IsOk() ) + break; + + if ( lastCount >= size ) + return true; + + size -= lastCount; + buffer += lastCount; + } + + return false; +} + wxFileOffset wxOutputStream::TellO() const { return OnSysTell(); -- 2.45.2