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
|