1 | /* |
2 | Open Asset Import Library (assimp) |
3 | ---------------------------------------------------------------------- |
4 | |
5 | Copyright (c) 2006-2017, assimp team |
6 | |
7 | All rights reserved. |
8 | |
9 | Redistribution and use of this software in source and binary forms, |
10 | with or without modification, are permitted provided that the |
11 | following conditions are met: |
12 | |
13 | * Redistributions of source code must retain the above |
14 | copyright notice, this list of conditions and the |
15 | following disclaimer. |
16 | |
17 | * Redistributions in binary form must reproduce the above |
18 | copyright notice, this list of conditions and the |
19 | following disclaimer in the documentation and/or other |
20 | materials provided with the distribution. |
21 | |
22 | * Neither the name of the assimp team, nor the names of its |
23 | contributors may be used to endorse or promote products |
24 | derived from this software without specific prior |
25 | written permission of the assimp team. |
26 | |
27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | |
39 | ---------------------------------------------------------------------- |
40 | */ |
41 | |
42 | #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER |
43 | |
44 | #include "Q3BSPZipArchive.h" |
45 | #include <cassert> |
46 | #include <assimp/ai_assert.h> |
47 | |
48 | namespace Assimp { |
49 | namespace Q3BSP { |
50 | |
51 | voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) { |
52 | IOSystem* io_system = (IOSystem*) opaque; |
53 | |
54 | const char* mode_fopen = NULL; |
55 | if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) { |
56 | mode_fopen = "rb" ; |
57 | } else { |
58 | if(mode & ZLIB_FILEFUNC_MODE_EXISTING) { |
59 | mode_fopen = "r+b" ; |
60 | } else { |
61 | if(mode & ZLIB_FILEFUNC_MODE_CREATE) { |
62 | mode_fopen = "wb" ; |
63 | } |
64 | } |
65 | } |
66 | |
67 | return (voidpf) io_system->Open(filename, mode_fopen); |
68 | } |
69 | |
70 | uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) { |
71 | IOStream* io_stream = (IOStream*) stream; |
72 | |
73 | return static_cast<uLong>(io_stream->Read(buf, 1, size)); |
74 | } |
75 | |
76 | uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) { |
77 | IOStream* io_stream = (IOStream*) stream; |
78 | |
79 | return static_cast<uLong>(io_stream->Write(buf, 1, size)); |
80 | } |
81 | |
82 | long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) { |
83 | IOStream* io_stream = (IOStream*) stream; |
84 | |
85 | return static_cast<long>(io_stream->Tell()); |
86 | } |
87 | |
88 | long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) { |
89 | IOStream* io_stream = (IOStream*) stream; |
90 | |
91 | aiOrigin assimp_origin; |
92 | switch (origin) { |
93 | default: |
94 | case ZLIB_FILEFUNC_SEEK_CUR: |
95 | assimp_origin = aiOrigin_CUR; |
96 | break; |
97 | case ZLIB_FILEFUNC_SEEK_END: |
98 | assimp_origin = aiOrigin_END; |
99 | break; |
100 | case ZLIB_FILEFUNC_SEEK_SET: |
101 | assimp_origin = aiOrigin_SET; |
102 | break; |
103 | } |
104 | |
105 | return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1); |
106 | } |
107 | |
108 | int IOSystem2Unzip::close(voidpf opaque, voidpf stream) { |
109 | IOSystem* io_system = (IOSystem*) opaque; |
110 | IOStream* io_stream = (IOStream*) stream; |
111 | |
112 | io_system->Close(io_stream); |
113 | |
114 | return 0; |
115 | } |
116 | |
117 | int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) { |
118 | return 0; |
119 | } |
120 | |
121 | zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) { |
122 | zlib_filefunc_def mapping; |
123 | |
124 | mapping.zopen_file = open; |
125 | mapping.zread_file = read; |
126 | mapping.zwrite_file = write; |
127 | mapping.ztell_file = tell; |
128 | mapping.zseek_file = seek; |
129 | mapping.zclose_file = close; |
130 | mapping.zerror_file = testerror; |
131 | mapping.opaque = (voidpf) pIOHandler; |
132 | |
133 | return mapping; |
134 | } |
135 | |
136 | ZipFile::ZipFile(size_t size) : m_Size(size) { |
137 | ai_assert(m_Size != 0); |
138 | |
139 | m_Buffer = malloc(m_Size); |
140 | } |
141 | |
142 | ZipFile::~ZipFile() { |
143 | free(m_Buffer); |
144 | m_Buffer = NULL; |
145 | } |
146 | |
147 | size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) { |
148 | const size_t size = pSize * pCount; |
149 | assert(size <= m_Size); |
150 | |
151 | std::memcpy(pvBuffer, m_Buffer, size); |
152 | |
153 | return size; |
154 | } |
155 | |
156 | size_t ZipFile::Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { |
157 | return 0; |
158 | } |
159 | |
160 | size_t ZipFile::FileSize() const { |
161 | return m_Size; |
162 | } |
163 | |
164 | aiReturn ZipFile::Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { |
165 | return aiReturn_FAILURE; |
166 | } |
167 | |
168 | size_t ZipFile::Tell() const { |
169 | return 0; |
170 | } |
171 | |
172 | void ZipFile::Flush() { |
173 | // empty |
174 | } |
175 | |
176 | // ------------------------------------------------------------------------------------------------ |
177 | // Constructor. |
178 | Q3BSPZipArchive::Q3BSPZipArchive(IOSystem* pIOHandler, const std::string& rFile) : m_ZipFileHandle(NULL), m_ArchiveMap() { |
179 | if (! rFile.empty()) { |
180 | zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler); |
181 | |
182 | m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping); |
183 | |
184 | if(m_ZipFileHandle != NULL) { |
185 | mapArchive(); |
186 | } |
187 | } |
188 | } |
189 | |
190 | // ------------------------------------------------------------------------------------------------ |
191 | // Destructor. |
192 | Q3BSPZipArchive::~Q3BSPZipArchive() { |
193 | for(auto &file : m_ArchiveMap) { |
194 | delete file.second; |
195 | } |
196 | m_ArchiveMap.clear(); |
197 | |
198 | if(m_ZipFileHandle != NULL) { |
199 | unzClose(m_ZipFileHandle); |
200 | m_ZipFileHandle = NULL; |
201 | } |
202 | } |
203 | |
204 | // ------------------------------------------------------------------------------------------------ |
205 | // Returns true, if the archive is already open. |
206 | bool Q3BSPZipArchive::isOpen() const { |
207 | return (m_ZipFileHandle != NULL); |
208 | } |
209 | |
210 | // ------------------------------------------------------------------------------------------------ |
211 | // Returns true, if the filename is part of the archive. |
212 | bool Q3BSPZipArchive::Exists(const char* pFile) const { |
213 | ai_assert(pFile != NULL); |
214 | |
215 | bool exist = false; |
216 | |
217 | if (pFile != NULL) { |
218 | std::string rFile(pFile); |
219 | std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile); |
220 | |
221 | if(it != m_ArchiveMap.end()) { |
222 | exist = true; |
223 | } |
224 | } |
225 | |
226 | return exist; |
227 | } |
228 | |
229 | // ------------------------------------------------------------------------------------------------ |
230 | // Returns the separator delimiter. |
231 | char Q3BSPZipArchive::getOsSeparator() const { |
232 | #ifndef _WIN32 |
233 | return '/'; |
234 | #else |
235 | return '\\'; |
236 | #endif |
237 | } |
238 | |
239 | // ------------------------------------------------------------------------------------------------ |
240 | // Opens a file, which is part of the archive. |
241 | IOStream *Q3BSPZipArchive::Open(const char* pFile, const char* /*pMode*/) { |
242 | ai_assert(pFile != NULL); |
243 | |
244 | IOStream* result = NULL; |
245 | |
246 | std::map<std::string, ZipFile*>::iterator it = m_ArchiveMap.find(pFile); |
247 | |
248 | if(it != m_ArchiveMap.end()) { |
249 | result = (IOStream*) it->second; |
250 | } |
251 | |
252 | return result; |
253 | } |
254 | |
255 | // ------------------------------------------------------------------------------------------------ |
256 | // Close a filestream. |
257 | void Q3BSPZipArchive::Close(IOStream *pFile) { |
258 | (void)(pFile); |
259 | ai_assert(pFile != NULL); |
260 | |
261 | // We don't do anything in case the file would be opened again in the future |
262 | } |
263 | // ------------------------------------------------------------------------------------------------ |
264 | // Returns the file-list of the archive. |
265 | void Q3BSPZipArchive::getFileList(std::vector<std::string> &rFileList) { |
266 | rFileList.clear(); |
267 | |
268 | for(auto &file : m_ArchiveMap) { |
269 | rFileList.push_back(file.first); |
270 | } |
271 | } |
272 | |
273 | // ------------------------------------------------------------------------------------------------ |
274 | // Maps the archive content. |
275 | bool Q3BSPZipArchive::mapArchive() { |
276 | bool success = false; |
277 | |
278 | if(m_ZipFileHandle != NULL) { |
279 | if(m_ArchiveMap.empty()) { |
280 | // At first ensure file is already open |
281 | if(unzGoToFirstFile(m_ZipFileHandle) == UNZ_OK) { |
282 | // Loop over all files |
283 | do { |
284 | char filename[FileNameSize]; |
285 | unz_file_info fileInfo; |
286 | |
287 | if(unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, NULL, 0, NULL, 0) == UNZ_OK) { |
288 | // The file has EXACTLY the size of uncompressed_size. In C |
289 | // you need to mark the last character with '\0', so add |
290 | // another character |
291 | if(fileInfo.uncompressed_size != 0 && unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) { |
292 | std::pair<std::map<std::string, ZipFile*>::iterator, bool> result = m_ArchiveMap.insert(std::make_pair(filename, new ZipFile(fileInfo.uncompressed_size))); |
293 | |
294 | if(unzReadCurrentFile(m_ZipFileHandle, result.first->second->m_Buffer, fileInfo.uncompressed_size) == (long int) fileInfo.uncompressed_size) { |
295 | if(unzCloseCurrentFile(m_ZipFileHandle) == UNZ_OK) { |
296 | // Nothing to do anymore... |
297 | } |
298 | } |
299 | } |
300 | } |
301 | } while(unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE); |
302 | } |
303 | } |
304 | |
305 | success = true; |
306 | } |
307 | |
308 | return success; |
309 | } |
310 | |
311 | // ------------------------------------------------------------------------------------------------ |
312 | |
313 | } // Namespace Q3BSP |
314 | } // Namespace Assimp |
315 | |
316 | #endif // ASSIMP_BUILD_NO_Q3BSP_IMPORTER |
317 | |