1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following 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
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF 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
48namespace Assimp {
49namespace Q3BSP {
50
51voidpf 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
70uLong 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
76uLong 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
82long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
83 IOStream* io_stream = (IOStream*) stream;
84
85 return static_cast<long>(io_stream->Tell());
86}
87
88long 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
108int 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
117int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
118 return 0;
119}
120
121zlib_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
136ZipFile::ZipFile(size_t size) : m_Size(size) {
137 ai_assert(m_Size != 0);
138
139 m_Buffer = malloc(m_Size);
140}
141
142ZipFile::~ZipFile() {
143 free(m_Buffer);
144 m_Buffer = NULL;
145}
146
147size_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
156size_t ZipFile::Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
157 return 0;
158}
159
160size_t ZipFile::FileSize() const {
161 return m_Size;
162}
163
164aiReturn ZipFile::Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
165 return aiReturn_FAILURE;
166}
167
168size_t ZipFile::Tell() const {
169 return 0;
170}
171
172void ZipFile::Flush() {
173 // empty
174}
175
176// ------------------------------------------------------------------------------------------------
177// Constructor.
178Q3BSPZipArchive::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.
192Q3BSPZipArchive::~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.
206bool Q3BSPZipArchive::isOpen() const {
207 return (m_ZipFileHandle != NULL);
208}
209
210// ------------------------------------------------------------------------------------------------
211// Returns true, if the filename is part of the archive.
212bool 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.
231char 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.
241IOStream *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.
257void 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.
265void 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.
275bool 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