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 Provides cheat implementations for IOSystem and IOStream to
44 * redirect exporter output to a blob chain.*/
45
46#ifndef AI_BLOBIOSYSTEM_H_INCLUDED
47#define AI_BLOBIOSYSTEM_H_INCLUDED
48
49#include <assimp/IOStream.hpp>
50#include <assimp/cexport.h>
51#include <assimp/IOSystem.hpp>
52#include <assimp/DefaultLogger.hpp>
53#include <stdint.h>
54#include <set>
55#include <vector>
56
57namespace Assimp {
58 class BlobIOSystem;
59
60// --------------------------------------------------------------------------------------------
61/** Redirect IOStream to a blob */
62// --------------------------------------------------------------------------------------------
63class BlobIOStream : public IOStream
64{
65public:
66
67 BlobIOStream(BlobIOSystem* creator, const std::string& file, size_t initial = 4096)
68 : buffer()
69 , cur_size()
70 , file_size()
71 , cursor()
72 , initial(initial)
73 , file(file)
74 , creator(creator)
75 {
76 }
77
78
79 virtual ~BlobIOStream();
80
81public:
82
83 // -------------------------------------------------------------------
84 aiExportDataBlob* GetBlob()
85 {
86 aiExportDataBlob* blob = new aiExportDataBlob();
87 blob->size = file_size;
88 blob->data = buffer;
89
90 buffer = NULL;
91
92 return blob;
93 }
94
95
96public:
97
98
99 // -------------------------------------------------------------------
100 virtual size_t Read( void *,
101 size_t,
102 size_t )
103 {
104 return 0;
105 }
106
107 // -------------------------------------------------------------------
108 virtual size_t Write(const void* pvBuffer,
109 size_t pSize,
110 size_t pCount)
111 {
112 pSize *= pCount;
113 if (cursor + pSize > cur_size) {
114 Grow(cursor + pSize);
115 }
116
117 memcpy(buffer+cursor, pvBuffer, pSize);
118 cursor += pSize;
119
120 file_size = std::max(file_size,cursor);
121 return pCount;
122 }
123
124 // -------------------------------------------------------------------
125 virtual aiReturn Seek(size_t pOffset,
126 aiOrigin pOrigin)
127 {
128 switch(pOrigin)
129 {
130 case aiOrigin_CUR:
131 cursor += pOffset;
132 break;
133
134 case aiOrigin_END:
135 cursor = file_size - pOffset;
136 break;
137
138 case aiOrigin_SET:
139 cursor = pOffset;
140 break;
141
142 default:
143 return AI_FAILURE;
144 }
145
146 if (cursor > file_size) {
147 Grow(cursor);
148 }
149
150 file_size = std::max(cursor,file_size);
151 return AI_SUCCESS;
152 }
153
154 // -------------------------------------------------------------------
155 virtual size_t Tell() const
156 {
157 return cursor;
158 }
159
160 // -------------------------------------------------------------------
161 virtual size_t FileSize() const
162 {
163 return file_size;
164 }
165
166 // -------------------------------------------------------------------
167 virtual void Flush()
168 {
169 // ignore
170 }
171
172
173
174private:
175
176 // -------------------------------------------------------------------
177 void Grow(size_t need = 0)
178 {
179 // 1.5 and phi are very heap-friendly growth factors (the first
180 // allows for frequent re-use of heap blocks, the second
181 // forms a fibonacci sequence with similar characteristics -
182 // since this heavily depends on the heap implementation
183 // and other factors as well, i'll just go with 1.5 since
184 // it is quicker to compute).
185 size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
186
187 const uint8_t* const old = buffer;
188 buffer = new uint8_t[new_size];
189
190 if (old) {
191 memcpy(buffer,old,cur_size);
192 delete[] old;
193 }
194
195 cur_size = new_size;
196 }
197
198private:
199
200 uint8_t* buffer;
201 size_t cur_size,file_size, cursor, initial;
202
203 const std::string file;
204 BlobIOSystem* const creator;
205};
206
207
208#define AI_BLOBIO_MAGIC "$blobfile"
209
210// --------------------------------------------------------------------------------------------
211/** Redirect IOSystem to a blob */
212// --------------------------------------------------------------------------------------------
213class BlobIOSystem : public IOSystem
214{
215
216 friend class BlobIOStream;
217 typedef std::pair<std::string, aiExportDataBlob*> BlobEntry;
218
219public:
220
221 BlobIOSystem()
222 {
223 }
224
225 virtual ~BlobIOSystem()
226 {
227 for(BlobEntry& blobby : blobs) {
228 delete blobby.second;
229 }
230 }
231
232public:
233
234 // -------------------------------------------------------------------
235 const char* GetMagicFileName() const
236 {
237 return AI_BLOBIO_MAGIC;
238 }
239
240
241 // -------------------------------------------------------------------
242 aiExportDataBlob* GetBlobChain()
243 {
244 // one must be the master
245 aiExportDataBlob* master = NULL, *cur;
246 for(const BlobEntry& blobby : blobs) {
247 if (blobby.first == AI_BLOBIO_MAGIC) {
248 master = blobby.second;
249 break;
250 }
251 }
252 if (!master) {
253 DefaultLogger::get()->error("BlobIOSystem: no data written or master file was not closed properly.");
254 return NULL;
255 }
256
257 master->name.Set("");
258
259 cur = master;
260 for(const BlobEntry& blobby : blobs) {
261 if (blobby.second == master) {
262 continue;
263 }
264
265 cur->next = blobby.second;
266 cur = cur->next;
267
268 // extract the file extension from the file written
269 const std::string::size_type s = blobby.first.find_first_of('.');
270 cur->name.Set(s == std::string::npos ? blobby.first : blobby.first.substr(s+1));
271 }
272
273 // give up blob ownership
274 blobs.clear();
275 return master;
276 }
277
278public:
279
280 // -------------------------------------------------------------------
281 virtual bool Exists( const char* pFile) const {
282 return created.find(std::string(pFile)) != created.end();
283 }
284
285
286 // -------------------------------------------------------------------
287 virtual char getOsSeparator() const {
288 return '/';
289 }
290
291
292 // -------------------------------------------------------------------
293 virtual IOStream* Open(const char* pFile,
294 const char* pMode)
295 {
296 if (pMode[0] != 'w') {
297 return NULL;
298 }
299
300 created.insert(std::string(pFile));
301 return new BlobIOStream(this,std::string(pFile));
302 }
303
304 // -------------------------------------------------------------------
305 virtual void Close( IOStream* pFile)
306 {
307 delete pFile;
308 }
309
310private:
311
312 // -------------------------------------------------------------------
313 void OnDestruct(const std::string& filename, BlobIOStream* child)
314 {
315 // we don't know in which the files are closed, so we
316 // can't reliably say that the first must be the master
317 // file ...
318 blobs.push_back( BlobEntry(filename,child->GetBlob()) );
319 }
320
321private:
322 std::set<std::string> created;
323 std::vector< BlobEntry > blobs;
324};
325
326
327// --------------------------------------------------------------------------------------------
328BlobIOStream :: ~BlobIOStream()
329{
330 creator->OnDestruct(file,this);
331 delete[] buffer;
332}
333
334
335} // end Assimp
336
337#endif
338