Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

binarystream.cpp

Go to the documentation of this file.
00001 /*
00002     Sheep - A Rigid Body Dynamics Engine
00003     Copyright (C) 2001-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of Sheep.
00007 
00008     Sheep is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     Sheep is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with Sheep; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 #include "binarystream.h"   // include first
00024 
00025 #include <algorithm>    // std::min<>()
00026 
00027 using namespace sheep;
00028 using namespace std;
00029 
00030 //! Default buffer size, in bytes.
00031 const int DEFAULT_BUFFER_SIZE = 65536;
00032 
00033 BinaryStream::BinaryStream() {
00034     initialize();
00035 }
00036 
00037 BinaryStream::BinaryStream(const std::string &filename,
00038                            StreamMode mode,
00039                            Endianness endianness /*= NativeEndian*/)
00040 {
00041     initialize();
00042     Open(filename, mode, endianness);
00043 }
00044 
00045 BinaryStream::~BinaryStream() {
00046     Close();
00047 }
00048 
00049 void BinaryStream::Open(const std::string &filename,
00050                         StreamMode mode,
00051                         Endianness endianness /*= NativeEndian*/)
00052 {
00053     assert(m_file == 0);
00054 
00055     m_mode = mode;
00056 
00057     if(mode == InputStream)
00058         m_file = fopen(filename.c_str(), "rb");
00059     else m_file = fopen(filename.c_str(), "wb");
00060 
00061     SetEndianness(endianness);
00062     SetBufferSize(DEFAULT_BUFFER_SIZE);
00063 }
00064 
00065 void BinaryStream::Close() throw(WriteException) {
00066     if(m_file) {
00067         if(m_mode == OutputStream)
00068             flush_output_buffer();
00069 
00070         fclose(m_file);
00071         m_file = 0;
00072 
00073         delete m_buffer_base;
00074         m_buffer_base = 0;
00075     }
00076 }
00077 
00078 bool BinaryStream::IsOpen() const {
00079     return m_file != 0;
00080 }
00081 
00082 void BinaryStream::SetBufferSize(int size) {
00083     assert(size > 0);
00084 
00085     delete m_buffer_base;
00086 
00087     m_buffer_base = new char[size];
00088 
00089     if(m_mode == InputStream)
00090         m_buffer_end = m_buffer_base;
00091     else m_buffer_end = m_buffer_base + size;
00092 
00093     m_buffer_ptr = m_buffer_base;
00094     m_buffer_size = size;
00095 }
00096 
00097 void BinaryStream::SetEndianness(Endianness endianness) {
00098     if(endianness == NativeEndian)
00099         m_swap = false;
00100     else m_swap = (endianness != get_host_endianness());
00101 }
00102 
00103 void BinaryStream::Seek(long offset, SeekOrigin origin) throw(SeekException) {
00104     assert(m_file);
00105     assert(m_mode == InputStream);
00106     assert(m_buffer_base);
00107 
00108     switch(origin) {
00109     case SeekFromBeginning:
00110         fseek(m_file, offset, SEEK_SET);
00111         break;
00112     case SeekFromCurrent:
00113         fseek(m_file, offset, SEEK_CUR);
00114         break;
00115     case SeekFromEnd:
00116         fseek(m_file, offset, SEEK_END);
00117         break;
00118     }
00119 
00120     if(ferror(m_file))
00121         throw SeekException();
00122 
00123     invalidate_input_buffer();
00124 }
00125 
00126 long BinaryStream::Tell() const throw(SeekException) {
00127     assert(m_file);
00128 
00129     const long position = ftell(m_file);
00130 
00131     if(ferror(m_file))
00132         throw SeekException();
00133 
00134     return position;
00135 }
00136 
00137 void BinaryStream::Write(const void *data, size_t size) throw(WriteException) {
00138     assert(m_file);
00139     assert(m_mode == OutputStream);
00140     assert(m_buffer_base);
00141 
00142     assert(data);
00143     assert(size >= 0);
00144 
00145     const char *data_ptr = static_cast<const char *>(data);
00146 
00147     while(size > 0) {
00148         // Calculate space available in the output buffer.
00149         const size_t room = m_buffer_end - m_buffer_ptr;
00150         assert(room >= 0);
00151 
00152         // Flush the output buffer if full.
00153         if(room == 0)
00154             flush_output_buffer();
00155 
00156         // Compute the amount of data to copy.
00157         const size_t block_size = min(size, room);
00158         assert(block_size > 0);
00159 
00160         // Append data to the output buffer.
00161         memcpy(m_buffer_ptr, data_ptr, block_size);
00162 
00163         // Advance source and destination pointers.
00164         data_ptr += block_size;
00165         m_buffer_ptr += block_size;
00166 
00167         // Compute the amount of data that remains to copy.
00168         size -= block_size;
00169     }
00170 }
00171 
00172 void BinaryStream::Read(void *data, size_t size) throw(ReadException) {
00173     assert(m_file);
00174     assert(m_mode == InputStream);
00175     assert(m_buffer_base);
00176 
00177     assert(data);
00178     assert(size >= 0);
00179 
00180     char *data_ptr = static_cast<char *>(data);
00181 
00182     while(size > 0) {
00183         // Compute the amount of data available in the input buffer.
00184         size_t remaining = m_buffer_end - m_buffer_ptr;
00185         assert(remaining >= 0);
00186 
00187         // Fill the input buffer if empty.
00188         if(remaining == 0) {
00189             remaining = fill_input_buffer();
00190 
00191             // Error: no more data.
00192             if(remaining == 0)
00193                 throw ReadException();
00194         }
00195 
00196         // Compute the amount of data to copy.
00197         const size_t block_size = min(size, remaining);
00198         assert(block_size > 0);
00199 
00200         // Copy data from buffer.
00201         memcpy(data_ptr, m_buffer_ptr, block_size);
00202 
00203         // Advance source and destination pointers.
00204         data_ptr += block_size;
00205         m_buffer_ptr += block_size;
00206 
00207         // Compute the amount of data that remains to copy.
00208         size -= block_size;
00209     }
00210 }
00211 
00212 BinaryStream::Endianness BinaryStream::get_host_endianness() const {
00213     const long x = 1;
00214     const char *p = reinterpret_cast<const char *>(&x);
00215 
00216     return *p ? LittleEndian : BigEndian;
00217 }
00218 
00219 void BinaryStream::initialize() {
00220     m_file = 0;
00221     m_mode = InputStream;   // arbitrary
00222     m_swap = false;
00223     m_buffer_base = m_buffer_end = 0;
00224     m_buffer_ptr = 0;
00225     m_buffer_size = 0;
00226 }
00227 
00228 void BinaryStream::flush_output_buffer() throw(WriteException) {
00229     assert(m_file);
00230     assert(m_mode == OutputStream);
00231     assert(m_buffer_base);
00232 
00233     const size_t block_size = m_buffer_ptr - m_buffer_base;
00234     assert(block_size >= 0);
00235 
00236     const size_t written =
00237         fwrite(m_buffer_base, 1, block_size, m_file);
00238 
00239     if(written < block_size || ferror(m_file))
00240         throw WriteException();
00241 
00242     m_buffer_ptr = m_buffer_base;
00243 }
00244 
00245 size_t BinaryStream::fill_input_buffer() throw(ReadException) {
00246     assert(m_file);
00247     assert(m_mode == InputStream);
00248     assert(m_buffer_base);
00249 
00250     const size_t read =
00251         fread(m_buffer_base, 1, m_buffer_size, m_file);
00252 
00253     if(ferror(m_file))
00254         throw ReadException();
00255 
00256     m_buffer_ptr = m_buffer_base;
00257     m_buffer_end = m_buffer_base + read;
00258 
00259     return read;
00260 }
00261 
00262 void BinaryStream::invalidate_input_buffer() {
00263     m_buffer_end = m_buffer_base;
00264 }

Generated on Tue May 11 01:31:49 2004 for toxic by doxygen 1.3.6