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
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"
33 #include "OgreLogManager.h"
34 #include "OgreException.h"
35 #include "OgreStringVector.h"
38 #include <zzip/zzip.h>
43 /// Utility method to format out zzip errors
44 String
getZzipErrorDescription(zzip_error_t zzipError
)
52 errorMsg
= "Out of memory.";
58 errorMsg
= "Unable to read zip file.";
60 case ZZIP_UNSUPP_COMPR
:
61 errorMsg
= "Unsupported compression format.";
64 errorMsg
= "Corrupted archive.";
67 errorMsg
= "Unknown error.";
73 //-----------------------------------------------------------------------
74 ZipArchive::ZipArchive(const String
& name
, const String
& archType
)
75 : Archive(name
, archType
), mZzipDir(0)
78 //-----------------------------------------------------------------------
79 ZipArchive::~ZipArchive()
83 //-----------------------------------------------------------------------
84 void ZipArchive::load()
88 zzip_error_t zzipError
;
89 mZzipDir
= zzip_dir_open(mName
.c_str(), &zzipError
);
90 checkZzipError(zzipError
, "opening archive");
93 ZZIP_DIRENT zzipEntry
;
94 while (zzip_dir_read(mZzipDir
, &zzipEntry
))
98 // Get basename / path
99 StringUtil::splitFilename(zzipEntry
.d_name
, info
.basename
, info
.path
);
100 info
.filename
= zzipEntry
.d_name
;
102 info
.compressedSize
= static_cast<size_t>(zzipEntry
.d_csize
);
103 info
.uncompressedSize
= static_cast<size_t>(zzipEntry
.st_size
);
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()
125 zzip_dir_close(mZzipDir
);
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
);
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
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
);
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()))
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
);
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))
235 //-----------------------------------------------------------------------
236 bool ZipArchive::exists(const String
& filename
)
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
250 bool ret
= (stat(mName
.c_str(), &tagStat
) == 0);
254 return tagStat
.st_mtime
;
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()
293 //-----------------------------------------------------------------------
294 size_t ZipDataStream::read(void* buf
, size_t count
)
296 zzip_ssize_t r
= zzip_file_read(mZzipFile
, (char*)buf
, count
);
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");
306 //---------------------------------------------------------------------
307 size_t ZipDataStream::write(void* buf
, size_t count
)
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";