vrshoot

annotate libs/assimp/StreamReader.h @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 ---------------------------------------------------------------------------
nuclear@0 3 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file Defines the StreamReader class which reads data from
nuclear@0 43 * a binary stream with a well-defined endianess. */
nuclear@0 44
nuclear@0 45 #ifndef AI_STREAMREADER_H_INCLUDED
nuclear@0 46 #define AI_STREAMREADER_H_INCLUDED
nuclear@0 47
nuclear@0 48 #include "ByteSwap.h"
nuclear@0 49
nuclear@0 50 namespace Assimp {
nuclear@0 51
nuclear@0 52 // --------------------------------------------------------------------------------------------
nuclear@0 53 /** Wrapper class around IOStream to allow for consistent reading of binary data in both
nuclear@0 54 * little and big endian format. Don't attempt to instance the template directly. Use
nuclear@0 55 * StreamReaderLE to read from a little-endian stream and StreamReaderBE to read from a
nuclear@0 56 * BE stream. The class expects that the endianess of any input data is known at
nuclear@0 57 * compile-time, which should usually be true (#BaseImporter::ConvertToUTF8 implements
nuclear@0 58 * runtime endianess conversions for text files).
nuclear@0 59 *
nuclear@0 60 * XXX switch from unsigned int for size types to size_t? or ptrdiff_t?*/
nuclear@0 61 // --------------------------------------------------------------------------------------------
nuclear@0 62 template <bool SwapEndianess = false, bool RuntimeSwitch = false>
nuclear@0 63 class StreamReader
nuclear@0 64 {
nuclear@0 65
nuclear@0 66 public:
nuclear@0 67
nuclear@0 68 // FIXME: use these data types throughout the whole library,
nuclear@0 69 // then change them to 64 bit values :-)
nuclear@0 70
nuclear@0 71 typedef int diff;
nuclear@0 72 typedef unsigned int pos;
nuclear@0 73
nuclear@0 74 public:
nuclear@0 75
nuclear@0 76
nuclear@0 77 // ---------------------------------------------------------------------
nuclear@0 78 /** Construction from a given stream with a well-defined endianess.
nuclear@0 79 *
nuclear@0 80 * The StreamReader holds a permanent strong reference to the
nuclear@0 81 * stream, which is released upon destruction.
nuclear@0 82 * @param stream Input stream. The stream is not restarted if
nuclear@0 83 * its file pointer is not at 0. Instead, the stream reader
nuclear@0 84 * reads from the current position to the end of the stream.
nuclear@0 85 * @param le If @c RuntimeSwitch is true: specifies whether the
nuclear@0 86 * stream is in little endian byte order. Otherwise the
nuclear@0 87 * endianess information is contained in the @c SwapEndianess
nuclear@0 88 * template parameter and this parameter is meaningless. */
nuclear@0 89 StreamReader(boost::shared_ptr<IOStream> stream, bool le = false)
nuclear@0 90 : stream(stream)
nuclear@0 91 , le(le)
nuclear@0 92 {
nuclear@0 93 ai_assert(stream);
nuclear@0 94 InternBegin();
nuclear@0 95 }
nuclear@0 96
nuclear@0 97 // ---------------------------------------------------------------------
nuclear@0 98 StreamReader(IOStream* stream, bool le = false)
nuclear@0 99 : stream(boost::shared_ptr<IOStream>(stream))
nuclear@0 100 , le(le)
nuclear@0 101 {
nuclear@0 102 ai_assert(stream);
nuclear@0 103 InternBegin();
nuclear@0 104 }
nuclear@0 105
nuclear@0 106 // ---------------------------------------------------------------------
nuclear@0 107 ~StreamReader() {
nuclear@0 108 delete[] buffer;
nuclear@0 109 }
nuclear@0 110
nuclear@0 111 public:
nuclear@0 112
nuclear@0 113 // deprecated, use overloaded operator>> instead
nuclear@0 114
nuclear@0 115 // ---------------------------------------------------------------------
nuclear@0 116 /** Read a float from the stream */
nuclear@0 117 float GetF4()
nuclear@0 118 {
nuclear@0 119 return Get<float>();
nuclear@0 120 }
nuclear@0 121
nuclear@0 122 // ---------------------------------------------------------------------
nuclear@0 123 /** Read a double from the stream */
nuclear@0 124 double GetF8() {
nuclear@0 125 return Get<double>();
nuclear@0 126 }
nuclear@0 127
nuclear@0 128 // ---------------------------------------------------------------------
nuclear@0 129 /** Read a signed 16 bit integer from the stream */
nuclear@0 130 int16_t GetI2() {
nuclear@0 131 return Get<int16_t>();
nuclear@0 132 }
nuclear@0 133
nuclear@0 134 // ---------------------------------------------------------------------
nuclear@0 135 /** Read a signed 8 bit integer from the stream */
nuclear@0 136 int8_t GetI1() {
nuclear@0 137 return Get<int8_t>();
nuclear@0 138 }
nuclear@0 139
nuclear@0 140 // ---------------------------------------------------------------------
nuclear@0 141 /** Read an signed 32 bit integer from the stream */
nuclear@0 142 int32_t GetI4() {
nuclear@0 143 return Get<int32_t>();
nuclear@0 144 }
nuclear@0 145
nuclear@0 146 // ---------------------------------------------------------------------
nuclear@0 147 /** Read a signed 64 bit integer from the stream */
nuclear@0 148 int64_t GetI8() {
nuclear@0 149 return Get<int64_t>();
nuclear@0 150 }
nuclear@0 151
nuclear@0 152 // ---------------------------------------------------------------------
nuclear@0 153 /** Read a unsigned 16 bit integer from the stream */
nuclear@0 154 uint16_t GetU2() {
nuclear@0 155 return Get<uint16_t>();
nuclear@0 156 }
nuclear@0 157
nuclear@0 158 // ---------------------------------------------------------------------
nuclear@0 159 /** Read a unsigned 8 bit integer from the stream */
nuclear@0 160 uint8_t GetU1() {
nuclear@0 161 return Get<uint8_t>();
nuclear@0 162 }
nuclear@0 163
nuclear@0 164 // ---------------------------------------------------------------------
nuclear@0 165 /** Read an unsigned 32 bit integer from the stream */
nuclear@0 166 uint32_t GetU4() {
nuclear@0 167 return Get<uint32_t>();
nuclear@0 168 }
nuclear@0 169
nuclear@0 170 // ---------------------------------------------------------------------
nuclear@0 171 /** Read a unsigned 64 bit integer from the stream */
nuclear@0 172 uint64_t GetU8() {
nuclear@0 173 return Get<uint64_t>();
nuclear@0 174 }
nuclear@0 175
nuclear@0 176 public:
nuclear@0 177
nuclear@0 178 // ---------------------------------------------------------------------
nuclear@0 179 /** Get the remaining stream size (to the end of the srream) */
nuclear@0 180 unsigned int GetRemainingSize() const {
nuclear@0 181 return (unsigned int)(end - current);
nuclear@0 182 }
nuclear@0 183
nuclear@0 184
nuclear@0 185 // ---------------------------------------------------------------------
nuclear@0 186 /** Get the remaining stream size (to the current read limit). The
nuclear@0 187 * return value is the remaining size of the stream if no custom
nuclear@0 188 * read limit has been set. */
nuclear@0 189 unsigned int GetRemainingSizeToLimit() const {
nuclear@0 190 return (unsigned int)(limit - current);
nuclear@0 191 }
nuclear@0 192
nuclear@0 193
nuclear@0 194 // ---------------------------------------------------------------------
nuclear@0 195 /** Increase the file pointer (relative seeking) */
nuclear@0 196 void IncPtr(int plus) {
nuclear@0 197 current += plus;
nuclear@0 198 if (current > limit) {
nuclear@0 199 throw DeadlyImportError("End of file or read limit was reached");
nuclear@0 200 }
nuclear@0 201 }
nuclear@0 202
nuclear@0 203 // ---------------------------------------------------------------------
nuclear@0 204 /** Get the current file pointer */
nuclear@0 205 int8_t* GetPtr() const {
nuclear@0 206 return current;
nuclear@0 207 }
nuclear@0 208
nuclear@0 209
nuclear@0 210 // ---------------------------------------------------------------------
nuclear@0 211 /** Set current file pointer (Get it from #GetPtr). This is if you
nuclear@0 212 * prefer to do pointer arithmetics on your own or want to copy
nuclear@0 213 * large chunks of data at once.
nuclear@0 214 * @param p The new pointer, which is validated against the size
nuclear@0 215 * limit and buffer boundaries. */
nuclear@0 216 void SetPtr(int8_t* p) {
nuclear@0 217
nuclear@0 218 current = p;
nuclear@0 219 if (current > limit || current < buffer) {
nuclear@0 220 throw DeadlyImportError("End of file or read limit was reached");
nuclear@0 221 }
nuclear@0 222 }
nuclear@0 223
nuclear@0 224 // ---------------------------------------------------------------------
nuclear@0 225 /** Copy n bytes to an external buffer
nuclear@0 226 * @param out Destination for copying
nuclear@0 227 * @param bytes Number of bytes to copy */
nuclear@0 228 void CopyAndAdvance(void* out, size_t bytes) {
nuclear@0 229
nuclear@0 230 int8_t* ur = GetPtr();
nuclear@0 231 SetPtr(ur+bytes); // fire exception if eof
nuclear@0 232
nuclear@0 233 memcpy(out,ur,bytes);
nuclear@0 234 }
nuclear@0 235
nuclear@0 236
nuclear@0 237 // ---------------------------------------------------------------------
nuclear@0 238 /** Get the current offset from the beginning of the file */
nuclear@0 239 int GetCurrentPos() const {
nuclear@0 240 return (unsigned int)(current - buffer);
nuclear@0 241 }
nuclear@0 242
nuclear@0 243 void SetCurrentPos(size_t pos) {
nuclear@0 244 SetPtr(buffer + pos);
nuclear@0 245 }
nuclear@0 246
nuclear@0 247 // ---------------------------------------------------------------------
nuclear@0 248 /** Setup a temporary read limit
nuclear@0 249 *
nuclear@0 250 * @param limit Maximum number of bytes to be read from
nuclear@0 251 * the beginning of the file. Specifying UINT_MAX
nuclear@0 252 * resets the limit to the original end of the stream. */
nuclear@0 253 void SetReadLimit(unsigned int _limit) {
nuclear@0 254
nuclear@0 255 if (UINT_MAX == _limit) {
nuclear@0 256 limit = end;
nuclear@0 257 return;
nuclear@0 258 }
nuclear@0 259
nuclear@0 260 limit = buffer + _limit;
nuclear@0 261 if (limit > end) {
nuclear@0 262 throw DeadlyImportError("StreamReader: Invalid read limit");
nuclear@0 263 }
nuclear@0 264 }
nuclear@0 265
nuclear@0 266 // ---------------------------------------------------------------------
nuclear@0 267 /** Get the current read limit in bytes. Reading over this limit
nuclear@0 268 * accidentially raises an exception. */
nuclear@0 269 int GetReadLimit() const {
nuclear@0 270 return (unsigned int)(limit - buffer);
nuclear@0 271 }
nuclear@0 272
nuclear@0 273 // ---------------------------------------------------------------------
nuclear@0 274 /** Skip to the read limit in bytes. Reading over this limit
nuclear@0 275 * accidentially raises an exception. */
nuclear@0 276 void SkipToReadLimit() {
nuclear@0 277 current = limit;
nuclear@0 278 }
nuclear@0 279
nuclear@0 280 // ---------------------------------------------------------------------
nuclear@0 281 /** overload operator>> and allow chaining of >> ops. */
nuclear@0 282 template <typename T>
nuclear@0 283 StreamReader& operator >> (T& f) {
nuclear@0 284 f = Get<T>();
nuclear@0 285 return *this;
nuclear@0 286 }
nuclear@0 287
nuclear@0 288 private:
nuclear@0 289
nuclear@0 290 // ---------------------------------------------------------------------
nuclear@0 291 /** Generic read method. ByteSwap::Swap(T*) *must* be defined */
nuclear@0 292 template <typename T>
nuclear@0 293 T Get() {
nuclear@0 294 if (current + sizeof(T) > limit) {
nuclear@0 295 throw DeadlyImportError("End of file or stream limit was reached");
nuclear@0 296 }
nuclear@0 297
nuclear@0 298 #ifdef __arm__
nuclear@0 299 T f;
nuclear@0 300 memcpy (&f, current, sizeof(T));
nuclear@0 301 #else
nuclear@0 302 T f = *((const T*)current);
nuclear@0 303 #endif
nuclear@0 304 Intern :: Getter<SwapEndianess,T,RuntimeSwitch>() (&f,le);
nuclear@0 305
nuclear@0 306 current += sizeof(T);
nuclear@0 307 return f;
nuclear@0 308 }
nuclear@0 309
nuclear@0 310 // ---------------------------------------------------------------------
nuclear@0 311 void InternBegin() {
nuclear@0 312 if (!stream) {
nuclear@0 313 // incase someone wonders: StreamReader is frequently invoked with
nuclear@0 314 // no prior validation whether the input stream is valid. Since
nuclear@0 315 // no one bothers changing the error message, this message here
nuclear@0 316 // is passed down to the caller and 'unable to open file'
nuclear@0 317 // simply describes best what happened.
nuclear@0 318 throw DeadlyImportError("StreamReader: Unable to open file");
nuclear@0 319 }
nuclear@0 320
nuclear@0 321 const size_t s = stream->FileSize() - stream->Tell();
nuclear@0 322 if (!s) {
nuclear@0 323 throw DeadlyImportError("StreamReader: File is empty or EOF is already reached");
nuclear@0 324 }
nuclear@0 325
nuclear@0 326 current = buffer = new int8_t[s];
nuclear@0 327 const size_t read = stream->Read(current,1,s);
nuclear@0 328 // (read < s) can only happen if the stream was opened in text mode, in which case FileSize() is not reliable
nuclear@0 329 ai_assert(read <= s);
nuclear@0 330 end = limit = &buffer[read];
nuclear@0 331 }
nuclear@0 332
nuclear@0 333 private:
nuclear@0 334
nuclear@0 335
nuclear@0 336 boost::shared_ptr<IOStream> stream;
nuclear@0 337 int8_t *buffer, *current, *end, *limit;
nuclear@0 338 bool le;
nuclear@0 339 };
nuclear@0 340
nuclear@0 341
nuclear@0 342 // --------------------------------------------------------------------------------------------
nuclear@0 343 // `static` StreamReaders. Their byte order is fixed and they might be a little bit faster.
nuclear@0 344 #ifdef AI_BUILD_BIG_ENDIAN
nuclear@0 345 typedef StreamReader<true> StreamReaderLE;
nuclear@0 346 typedef StreamReader<false> StreamReaderBE;
nuclear@0 347 #else
nuclear@0 348 typedef StreamReader<true> StreamReaderBE;
nuclear@0 349 typedef StreamReader<false> StreamReaderLE;
nuclear@0 350 #endif
nuclear@0 351
nuclear@0 352 // `dynamic` StreamReader. The byte order of the input data is specified in the
nuclear@0 353 // c'tor. This involves runtime branching and might be a little bit slower.
nuclear@0 354 typedef StreamReader<true,true> StreamReaderAny;
nuclear@0 355
nuclear@0 356 } // end namespace Assimp
nuclear@0 357
nuclear@0 358 #endif // !! AI_STREAMREADER_H_INCLUDED