Patch 2793067: fix trunk with OGRE_THREAD_SUPPORT=1 on non-Windows platforms (don...
[ogre3d.git] / OgreMain / src / OgreZip.cpp
blobe38088ac239d9476d896c3257f86016b3f44079c
1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
7 Copyright (c) 2000-2006 Torus Knot Software Ltd
8 Also see acknowledgements in Readme.html
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22 http://www.gnu.org/copyleft/lesser.txt.
24 You may alternatively use this source under the terms of a specific version of
25 the OGRE Unrestricted License provided you have obtained such a license from
26 Torus Knot Software Ltd.
27 -----------------------------------------------------------------------------
29 #include "OgreStableHeaders.h"
31 #include "OgreZip.h"
33 #include "OgreLogManager.h"
34 #include "OgreException.h"
35 #include "OgreStringVector.h"
36 #include "OgreRoot.h"
38 #include <zzip/zzip.h>
41 namespace Ogre {
43 /// Utility method to format out zzip errors
44 String getZzipErrorDescription(zzip_error_t zzipError)
46 String errorMsg;
47 switch (zzipError)
49 case ZZIP_NO_ERROR:
50 break;
51 case ZZIP_OUTOFMEM:
52 errorMsg = "Out of memory.";
53 break;
54 case ZZIP_DIR_OPEN:
55 case ZZIP_DIR_STAT:
56 case ZZIP_DIR_SEEK:
57 case ZZIP_DIR_READ:
58 errorMsg = "Unable to read zip file.";
59 break;
60 case ZZIP_UNSUPP_COMPR:
61 errorMsg = "Unsupported compression format.";
62 break;
63 case ZZIP_CORRUPTED:
64 errorMsg = "Corrupted archive.";
65 break;
66 default:
67 errorMsg = "Unknown error.";
68 break;
71 return errorMsg;
73 //-----------------------------------------------------------------------
74 ZipArchive::ZipArchive(const String& name, const String& archType )
75 : Archive(name, archType), mZzipDir(0)
78 //-----------------------------------------------------------------------
79 ZipArchive::~ZipArchive()
81 unload();
83 //-----------------------------------------------------------------------
84 void ZipArchive::load()
86 if (!mZzipDir)
88 zzip_error_t zzipError;
89 mZzipDir = zzip_dir_open(mName.c_str(), &zzipError);
90 checkZzipError(zzipError, "opening archive");
92 // Cache names
93 ZZIP_DIRENT zzipEntry;
94 while (zzip_dir_read(mZzipDir, &zzipEntry))
96 FileInfo info;
97 info.archive = this;
98 // Get basename / path
99 StringUtil::splitFilename(zzipEntry.d_name, info.basename, info.path);
100 info.filename = zzipEntry.d_name;
101 // Get sizes
102 info.compressedSize = static_cast<size_t>(zzipEntry.d_csize);
103 info.uncompressedSize = static_cast<size_t>(zzipEntry.st_size);
104 // folder entries
105 if (info.basename.empty())
107 info.filename = info.filename.substr (0, info.filename.length () - 1);
108 StringUtil::splitFilename(info.filename, info.basename, info.path);
109 // Set compressed size to -1 for folders; anyway nobody will check
110 // the compressed size of a folder, and if he does, its useless anyway
111 info.compressedSize = size_t (-1);
114 mFileList.push_back(info);
120 //-----------------------------------------------------------------------
121 void ZipArchive::unload()
123 if (mZzipDir)
125 zzip_dir_close(mZzipDir);
126 mZzipDir = 0;
127 mFileList.clear();
131 //-----------------------------------------------------------------------
132 DataStreamPtr ZipArchive::open(const String& filename, bool readOnly) const
135 // Format not used here (always binary)
136 ZZIP_FILE* zzipFile =
137 zzip_file_open(mZzipDir, filename.c_str(), ZZIP_ONLYZIP | ZZIP_CASELESS);
138 if (!zzipFile)
140 int zerr = zzip_error(mZzipDir);
141 String zzDesc = getZzipErrorDescription((zzip_error_t)zerr);
142 LogManager::getSingleton().logMessage(
143 mName + " - Unable to open file " + filename + ", error was '" + zzDesc + "'");
145 // return null pointer
146 return DataStreamPtr();
149 // Get uncompressed size too
150 ZZIP_STAT zstat;
151 zzip_dir_stat(mZzipDir, filename.c_str(), &zstat, ZZIP_CASEINSENSITIVE);
153 // Construct & return stream
154 return DataStreamPtr(OGRE_NEW ZipDataStream(filename, zzipFile, static_cast<size_t>(zstat.st_size)));
157 //---------------------------------------------------------------------
158 DataStreamPtr ZipArchive::create(const String& filename) const
160 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
161 "Modification of zipped archives is not supported",
162 "ZipArchive::create");
165 //---------------------------------------------------------------------
166 void ZipArchive::remove(const String& filename) const
169 //-----------------------------------------------------------------------
170 StringVectorPtr ZipArchive::list(bool recursive, bool dirs)
172 StringVectorPtr ret = StringVectorPtr(OGRE_NEW_T(StringVector, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
174 FileInfoList::iterator i, iend;
175 iend = mFileList.end();
176 for (i = mFileList.begin(); i != iend; ++i)
177 if ((dirs == (i->compressedSize == size_t (-1))) &&
178 (recursive || i->path.empty()))
179 ret->push_back(i->filename);
181 return ret;
183 //-----------------------------------------------------------------------
184 FileInfoListPtr ZipArchive::listFileInfo(bool recursive, bool dirs)
186 FileInfoList* fil = OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)();
187 FileInfoList::const_iterator i, iend;
188 iend = mFileList.end();
189 for (i = mFileList.begin(); i != iend; ++i)
190 if ((dirs == (i->compressedSize == size_t (-1))) &&
191 (recursive || i->path.empty()))
192 fil->push_back(*i);
194 return FileInfoListPtr(fil, SPFM_DELETE_T);
196 //-----------------------------------------------------------------------
197 StringVectorPtr ZipArchive::find(const String& pattern, bool recursive, bool dirs)
199 StringVectorPtr ret = StringVectorPtr(OGRE_NEW_T(StringVector, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
200 // If pattern contains a directory name, do a full match
201 bool full_match = (pattern.find ('/') != String::npos) ||
202 (pattern.find ('\\') != String::npos);
204 FileInfoList::iterator i, iend;
205 iend = mFileList.end();
206 for (i = mFileList.begin(); i != iend; ++i)
207 if ((dirs == (i->compressedSize == size_t (-1))) &&
208 (recursive || full_match || i->path.empty()))
209 // Check basename matches pattern (zip is case insensitive)
210 if (StringUtil::match(full_match ? i->filename : i->basename, pattern, false))
211 ret->push_back(i->filename);
213 return ret;
215 //-----------------------------------------------------------------------
216 FileInfoListPtr ZipArchive::findFileInfo(const String& pattern,
217 bool recursive, bool dirs)
219 FileInfoListPtr ret = FileInfoListPtr(OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
220 // If pattern contains a directory name, do a full match
221 bool full_match = (pattern.find ('/') != String::npos) ||
222 (pattern.find ('\\') != String::npos);
224 FileInfoList::iterator i, iend;
225 iend = mFileList.end();
226 for (i = mFileList.begin(); i != iend; ++i)
227 if ((dirs == (i->compressedSize == size_t (-1))) &&
228 (recursive || full_match || i->path.empty()))
229 // Check name matches pattern (zip is case insensitive)
230 if (StringUtil::match(full_match ? i->filename : i->basename, pattern, false))
231 ret->push_back(*i);
233 return ret;
235 //-----------------------------------------------------------------------
236 bool ZipArchive::exists(const String& filename)
238 ZZIP_STAT zstat;
239 int res = zzip_dir_stat(mZzipDir, filename.c_str(), &zstat, ZZIP_CASEINSENSITIVE);
241 return (res == ZZIP_NO_ERROR);
244 //---------------------------------------------------------------------
245 time_t ZipArchive::getModifiedTime(const String& filename)
247 // Zziplib doesn't yet support getting the modification time of individual files
248 // so just check the mod time of the zip itself
249 struct stat tagStat;
250 bool ret = (stat(mName.c_str(), &tagStat) == 0);
252 if (ret)
254 return tagStat.st_mtime;
256 else
258 return 0;
262 //-----------------------------------------------------------------------
263 void ZipArchive::checkZzipError(int zzipError, const String& operation) const
265 if (zzipError != ZZIP_NO_ERROR)
267 String errorMsg = getZzipErrorDescription(static_cast<zzip_error_t>(zzipError));
269 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
270 mName + " - error whilst " + operation + ": " + errorMsg,
271 "ZipArchive::checkZzipError");
274 //-----------------------------------------------------------------------
275 //-----------------------------------------------------------------------
276 //-----------------------------------------------------------------------
277 ZipDataStream::ZipDataStream(ZZIP_FILE* zzipFile, size_t uncompressedSize)
278 : mZzipFile(zzipFile)
280 mSize = uncompressedSize;
282 //-----------------------------------------------------------------------
283 ZipDataStream::ZipDataStream(const String& name, ZZIP_FILE* zzipFile, size_t uncompressedSize)
284 :DataStream(name), mZzipFile(zzipFile)
286 mSize = uncompressedSize;
288 //-----------------------------------------------------------------------
289 ZipDataStream::~ZipDataStream()
291 close();
293 //-----------------------------------------------------------------------
294 size_t ZipDataStream::read(void* buf, size_t count)
296 zzip_ssize_t r = zzip_file_read(mZzipFile, (char*)buf, count);
297 if (r<0) {
298 ZZIP_DIR *dir = zzip_dirhandle(mZzipFile);
299 String msg = zzip_strerror_of(dir);
300 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
301 mName+" - error from zziplib: "+msg,
302 "ZipDataStream::read");
304 return (size_t) r;
306 //---------------------------------------------------------------------
307 size_t ZipDataStream::write(void* buf, size_t count)
309 // not supported
310 return 0;
312 //-----------------------------------------------------------------------
313 void ZipDataStream::skip(long count)
315 zzip_seek(mZzipFile, static_cast<zzip_off_t>(count), SEEK_CUR);
317 //-----------------------------------------------------------------------
318 void ZipDataStream::seek( size_t pos )
320 zzip_seek(mZzipFile, static_cast<zzip_off_t>(pos), SEEK_SET);
322 //-----------------------------------------------------------------------
323 size_t ZipDataStream::tell(void) const
325 return zzip_tell(mZzipFile);
327 //-----------------------------------------------------------------------
328 bool ZipDataStream::eof(void) const
330 return (zzip_tell(mZzipFile) >= static_cast<zzip_off_t>(mSize));
332 //-----------------------------------------------------------------------
333 void ZipDataStream::close(void)
335 zzip_file_close(mZzipFile);
337 //-----------------------------------------------------------------------
338 const String& ZipArchiveFactory::getType(void) const
340 static String name = "Zip";
341 return name;