1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4 
5 Copyright (c) 2006-2021, assimp team
6 
7 
8 All rights reserved.
9 
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the
12 following conditions are met:
13 
14 * Redistributions of source code must retain the above
15   copyright notice, this list of conditions and the
16   following disclaimer.
17 
18 * Redistributions in binary form must reproduce the above
19   copyright notice, this list of conditions and the
20   following disclaimer in the documentation and/or other
21   materials provided with the distribution.
22 
23 * Neither the name of the assimp team, nor the names of its
24   contributors may be used to endorse or promote products
25   derived from this software without specific prior
26   written permission of the assimp team.
27 
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 
40 ----------------------------------------------------------------------
41 */
42 
43 /** @file MemoryIOWrapper.h
44  *  Handy IOStream/IOSystem implementation to read directly from a memory buffer */
45 #pragma once
46 #ifndef AI_MEMORYIOSTREAM_H_INC
47 #define AI_MEMORYIOSTREAM_H_INC
48 
49 #ifdef __GNUC__
50 #   pragma GCC system_header
51 #endif
52 
53 #include <assimp/IOStream.hpp>
54 #include <assimp/IOSystem.hpp>
55 #include <assimp/ai_assert.h>
56 
57 #include <stdint.h>
58 
59 namespace Assimp    {
60 
61 #define AI_MEMORYIO_MAGIC_FILENAME "$$$___magic___$$$"
62 #define AI_MEMORYIO_MAGIC_FILENAME_LENGTH 17
63 
64 // ----------------------------------------------------------------------------------
65 /** Implementation of IOStream to read directly from a memory buffer */
66 // ----------------------------------------------------------------------------------
67 class MemoryIOStream : public IOStream {
68 public:
69     MemoryIOStream (const uint8_t* buff, size_t len, bool own = false)
buffer(buff)70     : buffer (buff)
71     , length(len)
72     , pos((size_t)0)
73     , own(own) {
74         // empty
75     }
76 
~MemoryIOStream()77     ~MemoryIOStream ()  {
78         if(own) {
79             delete[] buffer;
80         }
81     }
82 
83     // -------------------------------------------------------------------
84     // Read from stream
Read(void * pvBuffer,size_t pSize,size_t pCount)85     size_t Read(void* pvBuffer, size_t pSize, size_t pCount)    {
86         ai_assert(nullptr != pvBuffer);
87         ai_assert(0 != pSize);
88 
89         const size_t cnt = std::min( pCount, (length-pos) / pSize);
90         const size_t ofs = pSize * cnt;
91 
92         ::memcpy(pvBuffer,buffer+pos,ofs);
93         pos += ofs;
94 
95         return cnt;
96     }
97 
98     // -------------------------------------------------------------------
99     // Write to stream
Write(const void *,size_t,size_t)100     size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/,size_t /*pCount*/)  {
101         ai_assert(false); // won't be needed
102         return 0;
103     }
104 
105     // -------------------------------------------------------------------
106     // Seek specific position
Seek(size_t pOffset,aiOrigin pOrigin)107     aiReturn Seek(size_t pOffset, aiOrigin pOrigin) {
108         if (aiOrigin_SET == pOrigin) {
109             if (pOffset > length) {
110                 return AI_FAILURE;
111             }
112             pos = pOffset;
113         } else if (aiOrigin_END == pOrigin) {
114             if (pOffset > length) {
115                 return AI_FAILURE;
116             }
117             pos = length-pOffset;
118         } else {
119             if (pOffset+pos > length) {
120                 return AI_FAILURE;
121             }
122             pos += pOffset;
123         }
124         return AI_SUCCESS;
125     }
126 
127     // -------------------------------------------------------------------
128     // Get current seek position
Tell()129     size_t Tell() const {
130         return pos;
131     }
132 
133     // -------------------------------------------------------------------
134     // Get size of file
FileSize()135     size_t FileSize() const {
136         return length;
137     }
138 
139     // -------------------------------------------------------------------
140     // Flush file contents
Flush()141     void Flush() {
142         ai_assert(false); // won't be needed
143     }
144 
145 private:
146     const uint8_t* buffer;
147     size_t length,pos;
148     bool own;
149 };
150 
151 // ---------------------------------------------------------------------------
152 /** Dummy IO system to read from a memory buffer */
153 class MemoryIOSystem : public IOSystem {
154 public:
155     /** Constructor. */
MemoryIOSystem(const uint8_t * buff,size_t len,IOSystem * io)156     MemoryIOSystem(const uint8_t* buff, size_t len, IOSystem* io)
157     : buffer(buff)
158     , length(len)
159     , existing_io(io)
160     , created_streams() {
161         // empty
162     }
163 
164     /** Destructor. */
~MemoryIOSystem()165     ~MemoryIOSystem() {
166     }
167 
168     // -------------------------------------------------------------------
169     /** Tests for the existence of a file at the given path. */
Exists(const char * pFile)170     bool Exists(const char* pFile) const override {
171         if (0 == strncmp( pFile, AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH ) ) {
172             return true;
173         }
174         return existing_io ? existing_io->Exists(pFile) : false;
175     }
176 
177     // -------------------------------------------------------------------
178     /** Returns the directory separator. */
getOsSeparator()179     char getOsSeparator() const override {
180         return existing_io ? existing_io->getOsSeparator()
181                            : '/';  // why not? it doesn't care
182     }
183 
184     // -------------------------------------------------------------------
185     /** Open a new file with a given path. */
186     IOStream* Open(const char* pFile, const char* pMode = "rb") override {
187         if ( 0 == strncmp( pFile, AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH ) ) {
188             created_streams.emplace_back(new MemoryIOStream(buffer, length));
189             return created_streams.back();
190         }
191         return existing_io ? existing_io->Open(pFile, pMode) : NULL;
192     }
193 
194     // -------------------------------------------------------------------
195     /** Closes the given file and releases all resources associated with it. */
Close(IOStream * pFile)196     void Close( IOStream* pFile) override {
197         auto it = std::find(created_streams.begin(), created_streams.end(), pFile);
198         if (it != created_streams.end()) {
199             delete pFile;
200             created_streams.erase(it);
201         } else if (existing_io) {
202             existing_io->Close(pFile);
203         }
204     }
205 
206     // -------------------------------------------------------------------
207     /** Compare two paths */
ComparePaths(const char * one,const char * second)208     bool ComparePaths(const char* one, const char* second) const override {
209         return existing_io ? existing_io->ComparePaths(one, second) : false;
210     }
211 
PushDirectory(const std::string & path)212     bool PushDirectory( const std::string &path ) override {
213         return existing_io ? existing_io->PushDirectory(path) : false;
214     }
215 
CurrentDirectory()216     const std::string &CurrentDirectory() const override {
217         static std::string empty;
218         return existing_io ? existing_io->CurrentDirectory() : empty;
219     }
220 
StackSize()221     size_t StackSize() const override {
222         return existing_io ? existing_io->StackSize() : 0;
223     }
224 
PopDirectory()225     bool PopDirectory() override {
226         return existing_io ? existing_io->PopDirectory() : false;
227     }
228 
CreateDirectory(const std::string & path)229     bool CreateDirectory( const std::string &path ) override {
230         return existing_io ? existing_io->CreateDirectory(path) : false;
231     }
232 
ChangeDirectory(const std::string & path)233     bool ChangeDirectory( const std::string &path ) override {
234         return existing_io ? existing_io->ChangeDirectory(path) : false;
235     }
236 
DeleteFile(const std::string & file)237     bool DeleteFile( const std::string &file ) override {
238         return existing_io ? existing_io->DeleteFile(file) : false;
239     }
240 
241 private:
242     const uint8_t* buffer;
243     size_t length;
244     IOSystem* existing_io;
245     std::vector<IOStream*> created_streams;
246 };
247 
248 } // end namespace Assimp
249 
250 #endif
251