1/*
2---------------------------------------------------------------------------
3Open Asset Import Library (assimp)
4---------------------------------------------------------------------------
5
6Copyright (c) 2006-2017, assimp team
7
8
9All rights reserved.
10
11Redistribution and use of this software in source and binary forms,
12with or without modification, are permitted provided that the following
13conditions are met:
14
15* Redistributions of source code must retain the above
16 copyright notice, this list of conditions and the
17 following disclaimer.
18
19* Redistributions in binary form must reproduce the above
20 copyright notice, this list of conditions and the
21 following disclaimer in the documentation and/or other
22 materials provided with the distribution.
23
24* Neither the name of the assimp team, nor the names of its
25 contributors may be used to endorse or promote products
26 derived from this software without specific prior
27 written permission of the assimp team.
28
29THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40---------------------------------------------------------------------------
41*/
42
43/** @file Defines the StreamWriter class which writes data to
44 * a binary stream with a well-defined endianness. */
45
46#ifndef AI_STREAMWRITER_H_INCLUDED
47#define AI_STREAMWRITER_H_INCLUDED
48
49#include "ByteSwapper.h"
50#include <assimp/IOStream.hpp>
51
52#include <memory>
53#include <vector>
54
55namespace Assimp {
56
57// --------------------------------------------------------------------------------------------
58/** Wrapper class around IOStream to allow for consistent writing of binary data in both
59 * little and big endian format. Don't attempt to instance the template directly. Use
60 * StreamWriterLE to read from a little-endian stream and StreamWriterBE to read from a
61 * BE stream. Alternatively, there is StreamWriterAny if the endianness of the output
62 * stream is to be determined at runtime.
63 */
64// --------------------------------------------------------------------------------------------
65template <bool SwapEndianess = false, bool RuntimeSwitch = false>
66class StreamWriter
67{
68 enum {
69 INITIAL_CAPACITY = 1024
70 };
71
72public:
73
74 // ---------------------------------------------------------------------
75 /** Construction from a given stream with a well-defined endianness.
76 *
77 * The StreamReader holds a permanent strong reference to the
78 * stream, which is released upon destruction.
79 * @param stream Input stream. The stream is not re-seeked and writing
80 continues at the current position of the stream cursor.
81 * @param le If @c RuntimeSwitch is true: specifies whether the
82 * stream is in little endian byte order. Otherwise the
83 * endianness information is defined by the @c SwapEndianess
84 * template parameter and this parameter is meaningless. */
85 StreamWriter(std::shared_ptr<IOStream> stream, bool le = false)
86 : stream(stream)
87 , le(le)
88 , cursor()
89 {
90 ai_assert(stream);
91 buffer.reserve(INITIAL_CAPACITY);
92 }
93
94 // ---------------------------------------------------------------------
95 StreamWriter(IOStream* stream, bool le = false)
96 : stream(std::shared_ptr<IOStream>(stream))
97 , le(le)
98 , cursor()
99 {
100 ai_assert(stream);
101 buffer.reserve(INITIAL_CAPACITY);
102 }
103
104 // ---------------------------------------------------------------------
105 ~StreamWriter() {
106 stream->Write(&buffer[0], 1, buffer.size());
107 stream->Flush();
108 }
109
110public:
111
112 // ---------------------------------------------------------------------
113 /** Write a float to the stream */
114 void PutF4(float f)
115 {
116 Put(f);
117 }
118
119 // ---------------------------------------------------------------------
120 /** Write a double to the stream */
121 void PutF8(double d) {
122 Put(d);
123 }
124
125 // ---------------------------------------------------------------------
126 /** Write a signed 16 bit integer to the stream */
127 void PutI2(int16_t n) {
128 Put(n);
129 }
130
131 // ---------------------------------------------------------------------
132 /** Write a signed 8 bit integer to the stream */
133 void PutI1(int8_t n) {
134 Put(n);
135 }
136
137 // ---------------------------------------------------------------------
138 /** Write an signed 32 bit integer to the stream */
139 void PutI4(int32_t n) {
140 Put(n);
141 }
142
143 // ---------------------------------------------------------------------
144 /** Write a signed 64 bit integer to the stream */
145 void PutI8(int64_t n) {
146 Put(n);
147 }
148
149 // ---------------------------------------------------------------------
150 /** Write a unsigned 16 bit integer to the stream */
151 void PutU2(uint16_t n) {
152 Put(n);
153 }
154
155 // ---------------------------------------------------------------------
156 /** Write a unsigned 8 bit integer to the stream */
157 void PutU1(uint8_t n) {
158 Put(n);
159 }
160
161 // ---------------------------------------------------------------------
162 /** Write an unsigned 32 bit integer to the stream */
163 void PutU4(uint32_t n) {
164 Put(n);
165 }
166
167 // ---------------------------------------------------------------------
168 /** Write a unsigned 64 bit integer to the stream */
169 void PutU8(uint64_t n) {
170 Put(n);
171 }
172
173public:
174
175 // ---------------------------------------------------------------------
176 /** overload operator<< and allow chaining of MM ops. */
177 template <typename T>
178 StreamWriter& operator << (T f) {
179 Put(f);
180 return *this;
181 }
182
183 // ---------------------------------------------------------------------
184 std::size_t GetCurrentPos() const {
185 return cursor;
186 }
187
188 // ---------------------------------------------------------------------
189 void SetCurrentPos(std::size_t new_cursor) {
190 cursor = new_cursor;
191 }
192
193private:
194
195 // ---------------------------------------------------------------------
196 /** Generic write method. ByteSwap::Swap(T*) *must* be defined */
197 template <typename T>
198 void Put(T f) {
199 Intern :: Getter<SwapEndianess,T,RuntimeSwitch>() (&f, le);
200
201 if (cursor + sizeof(T) >= buffer.size()) {
202 buffer.resize(cursor + sizeof(T));
203 }
204
205 void* dest = &buffer[cursor];
206
207 // reinterpret_cast + assignment breaks strict aliasing rules
208 // and generally causes trouble on platforms such as ARM that
209 // do not silently ignore alignment faults.
210 ::memcpy(dest, &f, sizeof(T));
211 cursor += sizeof(T);
212 }
213
214private:
215
216 std::shared_ptr<IOStream> stream;
217 bool le;
218
219 std::vector<uint8_t> buffer;
220 std::size_t cursor;
221};
222
223
224// --------------------------------------------------------------------------------------------
225// `static` StreamWriter. Their byte order is fixed and they might be a little bit faster.
226#ifdef AI_BUILD_BIG_ENDIAN
227 typedef StreamWriter<true> StreamWriterLE;
228 typedef StreamWriter<false> StreamWriterBE;
229#else
230 typedef StreamWriter<true> StreamWriterBE;
231 typedef StreamWriter<false> StreamWriterLE;
232#endif
233
234// `dynamic` StreamWriter. The byte order of the input data is specified in the
235// c'tor. This involves runtime branching and might be a little bit slower.
236typedef StreamWriter<true,true> StreamWriterAny;
237
238} // end namespace Assimp
239
240#endif // !! AI_STREAMWriter_H_INCLUDED
241