00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "binarystream.h"
00024
00025 #include <algorithm>
00026
00027 using namespace sheep;
00028 using namespace std;
00029
00030
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 )
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 )
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
00149 const size_t room = m_buffer_end - m_buffer_ptr;
00150 assert(room >= 0);
00151
00152
00153 if(room == 0)
00154 flush_output_buffer();
00155
00156
00157 const size_t block_size = min(size, room);
00158 assert(block_size > 0);
00159
00160
00161 memcpy(m_buffer_ptr, data_ptr, block_size);
00162
00163
00164 data_ptr += block_size;
00165 m_buffer_ptr += block_size;
00166
00167
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
00184 size_t remaining = m_buffer_end - m_buffer_ptr;
00185 assert(remaining >= 0);
00186
00187
00188 if(remaining == 0) {
00189 remaining = fill_input_buffer();
00190
00191
00192 if(remaining == 0)
00193 throw ReadException();
00194 }
00195
00196
00197 const size_t block_size = min(size, remaining);
00198 assert(block_size > 0);
00199
00200
00201 memcpy(data_ptr, m_buffer_ptr, block_size);
00202
00203
00204 data_ptr += block_size;
00205 m_buffer_ptr += block_size;
00206
00207
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;
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 }