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