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

source code of qt3d/src/3rdparty/assimp/src/include/assimp/StreamReader.h