![]() |
|
|||
File indexing completed on 2025-02-21 09:30:10
0001 /* 0002 --------------------------------------------------------------------------- 0003 Open Asset Import Library (assimp) 0004 --------------------------------------------------------------------------- 0005 0006 Copyright (c) 2006-2024, assimp team 0007 0008 All rights reserved. 0009 0010 Redistribution and use of this software in source and binary forms, 0011 with or without modification, are permitted provided that the following 0012 conditions are met: 0013 0014 * Redistributions of source code must retain the above 0015 copyright notice, this list of conditions and the 0016 following disclaimer. 0017 0018 * Redistributions in binary form must reproduce the above 0019 copyright notice, this list of conditions and the 0020 following disclaimer in the documentation and/or other 0021 materials provided with the distribution. 0022 0023 * Neither the name of the assimp team, nor the names of its 0024 contributors may be used to endorse or promote products 0025 derived from this software without specific prior 0026 written permission of the assimp team. 0027 0028 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 0029 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 0030 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 0031 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 0032 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 0033 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 0034 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0035 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0036 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0037 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 0038 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0039 --------------------------------------------------------------------------- 0040 */ 0041 0042 /** @file Defines the StreamReader class which reads data from 0043 * a binary stream with a well-defined endianness. 0044 */ 0045 #pragma once 0046 #ifndef AI_STREAMREADER_H_INCLUDED 0047 #define AI_STREAMREADER_H_INCLUDED 0048 0049 #ifdef __GNUC__ 0050 # pragma GCC system_header 0051 #endif 0052 0053 #include <assimp/ByteSwapper.h> 0054 #include <assimp/Exceptional.h> 0055 #include <assimp/IOStream.hpp> 0056 0057 #include <memory> 0058 0059 namespace Assimp { 0060 0061 // -------------------------------------------------------------------------------------------- 0062 /** Wrapper class around IOStream to allow for consistent reading of binary data in both 0063 * little and big endian format. Don't attempt to instance the template directly. Use 0064 * StreamReaderLE to read from a little-endian stream and StreamReaderBE to read from a 0065 * BE stream. The class expects that the endianness of any input data is known at 0066 * compile-time, which should usually be true (#BaseImporter::ConvertToUTF8 implements 0067 * runtime endianness conversions for text files). 0068 * 0069 * XXX switch from unsigned int for size types to size_t? or ptrdiff_t?*/ 0070 // -------------------------------------------------------------------------------------------- 0071 template <bool SwapEndianness = false, bool RuntimeSwitch = false> 0072 class StreamReader { 0073 public: 0074 using diff = size_t; 0075 using pos = size_t; 0076 0077 // --------------------------------------------------------------------- 0078 /** Construction from a given stream with a well-defined endianness. 0079 * 0080 * The StreamReader holds a permanent strong reference to the 0081 * stream, which is released upon destruction. 0082 * @param stream Input stream. The stream is not restarted if 0083 * its file pointer is not at 0. Instead, the stream reader 0084 * reads from the current position to the end of the stream. 0085 * @param le If @c RuntimeSwitch is true: specifies whether the 0086 * stream is in little endian byte order. Otherwise the 0087 * endianness information is contained in the @c SwapEndianness 0088 * template parameter and this parameter is meaningless. */ 0089 StreamReader(std::shared_ptr<IOStream> stream, bool le = false) : 0090 mStream(stream), 0091 mBuffer(nullptr), 0092 mCurrent(nullptr), 0093 mEnd(nullptr), 0094 mLimit(nullptr), 0095 mLe(le) { 0096 ai_assert(stream); 0097 InternBegin(); 0098 } 0099 0100 // --------------------------------------------------------------------- 0101 StreamReader(IOStream *stream, bool le = false) : 0102 mStream(std::shared_ptr<IOStream>(stream)), 0103 mBuffer(nullptr), 0104 mCurrent(nullptr), 0105 mEnd(nullptr), 0106 mLimit(nullptr), 0107 mLe(le) { 0108 ai_assert(nullptr != stream); 0109 InternBegin(); 0110 } 0111 0112 // --------------------------------------------------------------------- 0113 ~StreamReader() { 0114 delete[] mBuffer; 0115 } 0116 0117 // deprecated, use overloaded operator>> instead 0118 0119 // --------------------------------------------------------------------- 0120 /// Read a float from the stream. 0121 float GetF4() { 0122 return Get<float>(); 0123 } 0124 0125 // --------------------------------------------------------------------- 0126 /// Read a double from the stream. 0127 double GetF8() { 0128 return Get<double>(); 0129 } 0130 0131 // --------------------------------------------------------------------- 0132 /** Read a signed 16 bit integer from the stream */ 0133 int16_t GetI2() { 0134 return Get<int16_t>(); 0135 } 0136 0137 // --------------------------------------------------------------------- 0138 /** Read a signed 8 bit integer from the stream */ 0139 int8_t GetI1() { 0140 return Get<int8_t>(); 0141 } 0142 0143 // --------------------------------------------------------------------- 0144 /** Read an signed 32 bit integer from the stream */ 0145 int32_t GetI4() { 0146 return Get<int32_t>(); 0147 } 0148 0149 // --------------------------------------------------------------------- 0150 /** Read a signed 64 bit integer from the stream */ 0151 int64_t GetI8() { 0152 return Get<int64_t>(); 0153 } 0154 0155 // --------------------------------------------------------------------- 0156 /** Read a unsigned 16 bit integer from the stream */ 0157 uint16_t GetU2() { 0158 return Get<uint16_t>(); 0159 } 0160 0161 // --------------------------------------------------------------------- 0162 /// Read a unsigned 8 bit integer from the stream 0163 uint8_t GetU1() { 0164 return Get<uint8_t>(); 0165 } 0166 0167 // --------------------------------------------------------------------- 0168 /// Read an unsigned 32 bit integer from the stream 0169 uint32_t GetU4() { 0170 return Get<uint32_t>(); 0171 } 0172 0173 // --------------------------------------------------------------------- 0174 /// Read a unsigned 64 bit integer from the stream 0175 uint64_t GetU8() { 0176 return Get<uint64_t>(); 0177 } 0178 0179 // --------------------------------------------------------------------- 0180 /// Get the remaining stream size (to the end of the stream) 0181 size_t GetRemainingSize() const { 0182 return (unsigned int)(mEnd - mCurrent); 0183 } 0184 0185 // --------------------------------------------------------------------- 0186 /** Get the remaining stream size (to the current read limit). The 0187 * return value is the remaining size of the stream if no custom 0188 * read limit has been set. */ 0189 size_t GetRemainingSizeToLimit() const { 0190 return (unsigned int)(mLimit - mCurrent); 0191 } 0192 0193 // --------------------------------------------------------------------- 0194 /** Increase the file pointer (relative seeking) */ 0195 void IncPtr(intptr_t plus) { 0196 mCurrent += plus; 0197 if (mCurrent > mLimit) { 0198 throw DeadlyImportError("End of file or read limit was reached"); 0199 } 0200 } 0201 0202 // --------------------------------------------------------------------- 0203 /** Get the current file pointer */ 0204 int8_t *GetPtr() const { 0205 return mCurrent; 0206 } 0207 0208 // --------------------------------------------------------------------- 0209 /** Set current file pointer (Get it from #GetPtr). This is if you 0210 * prefer to do pointer arithmetic on your own or want to copy 0211 * large chunks of data at once. 0212 * @param p The new pointer, which is validated against the size 0213 * limit and buffer boundaries. */ 0214 void SetPtr(int8_t *p) { 0215 mCurrent = p; 0216 if (mCurrent > mLimit || mCurrent < mBuffer) { 0217 throw DeadlyImportError("End of file or read limit was reached"); 0218 } 0219 } 0220 0221 // --------------------------------------------------------------------- 0222 /** Copy n bytes to an external buffer 0223 * @param out Destination for copying 0224 * @param bytes Number of bytes to copy */ 0225 void CopyAndAdvance(void *out, size_t bytes) { 0226 int8_t *ur = GetPtr(); 0227 SetPtr(ur + bytes); // fire exception if eof 0228 0229 ::memcpy(out, ur, bytes); 0230 } 0231 0232 /// @brief Get the current offset from the beginning of the file 0233 int GetCurrentPos() const { 0234 return (unsigned int)(mCurrent - mBuffer); 0235 } 0236 0237 void SetCurrentPos(size_t pos) { 0238 SetPtr(mBuffer + pos); 0239 } 0240 0241 // --------------------------------------------------------------------- 0242 /** Setup a temporary read limit 0243 * 0244 * @param limit Maximum number of bytes to be read from 0245 * the beginning of the file. Specifying UINT_MAX 0246 * resets the limit to the original end of the stream. 0247 * Returns the previously set limit. */ 0248 unsigned int SetReadLimit(unsigned int _limit) { 0249 unsigned int prev = GetReadLimit(); 0250 if (UINT_MAX == _limit) { 0251 mLimit = mEnd; 0252 return prev; 0253 } 0254 0255 mLimit = mBuffer + _limit; 0256 if (mLimit > mEnd) { 0257 throw DeadlyImportError("StreamReader: Invalid read limit"); 0258 } 0259 return prev; 0260 } 0261 0262 // --------------------------------------------------------------------- 0263 /** Get the current read limit in bytes. Reading over this limit 0264 * accidentally raises an exception. */ 0265 unsigned int GetReadLimit() const { 0266 return (unsigned int)(mLimit - mBuffer); 0267 } 0268 0269 // --------------------------------------------------------------------- 0270 /** Skip to the read limit in bytes. Reading over this limit 0271 * accidentally raises an exception. */ 0272 void SkipToReadLimit() { 0273 mCurrent = mLimit; 0274 } 0275 0276 // --------------------------------------------------------------------- 0277 /** overload operator>> and allow chaining of >> ops. */ 0278 template <typename T> 0279 StreamReader &operator>>(T &f) { 0280 f = Get<T>(); 0281 return *this; 0282 } 0283 0284 // --------------------------------------------------------------------- 0285 /** Generic read method. ByteSwap::Swap(T*) *must* be defined */ 0286 template <typename T> 0287 T Get() { 0288 if (mCurrent + sizeof(T) > mLimit) { 0289 throw DeadlyImportError("End of file or stream limit was reached"); 0290 } 0291 0292 T f; 0293 ::memcpy(&f, mCurrent, sizeof(T)); 0294 Intern::Getter<SwapEndianness, T, RuntimeSwitch>()(&f, mLe); 0295 mCurrent += sizeof(T); 0296 0297 return f; 0298 } 0299 0300 private: 0301 // --------------------------------------------------------------------- 0302 void InternBegin() { 0303 if (nullptr == mStream) { 0304 throw DeadlyImportError("StreamReader: Unable to open file"); 0305 } 0306 0307 const size_t filesize = mStream->FileSize() - mStream->Tell(); 0308 if (0 == filesize) { 0309 throw DeadlyImportError("StreamReader: File is empty or EOF is already reached"); 0310 } 0311 0312 mCurrent = mBuffer = new int8_t[filesize]; 0313 const size_t read = mStream->Read(mCurrent, 1, filesize); 0314 // (read < s) can only happen if the stream was opened in text mode, in which case FileSize() is not reliable 0315 ai_assert(read <= filesize); 0316 mEnd = mLimit = &mBuffer[read - 1] + 1; 0317 } 0318 0319 private: 0320 std::shared_ptr<IOStream> mStream; 0321 int8_t *mBuffer; 0322 int8_t *mCurrent; 0323 int8_t *mEnd; 0324 int8_t *mLimit; 0325 bool mLe; 0326 }; 0327 0328 // -------------------------------------------------------------------------------------------- 0329 // `static` StreamReaders. Their byte order is fixed and they might be a little bit faster. 0330 #ifdef AI_BUILD_BIG_ENDIAN 0331 typedef StreamReader<true> StreamReaderLE; 0332 typedef StreamReader<false> StreamReaderBE; 0333 #else 0334 typedef StreamReader<true> StreamReaderBE; 0335 typedef StreamReader<false> StreamReaderLE; 0336 #endif 0337 0338 // `dynamic` StreamReader. The byte order of the input data is specified in the 0339 // c'tor. This involves runtime branching and might be a little bit slower. 0340 typedef StreamReader<true, true> StreamReaderAny; 0341 0342 } // end namespace Assimp 0343 0344 #endif // !! AI_STREAMREADER_H_INCLUDED
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |