Back to home page

EIC code displayed by LXR

 
 

    


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