ZipFile.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2005 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 
00021 #include "ZipFile.h"
00022 #include "IDataSource.h"
00023 #include "FileSystem.h"
00024 
00025 // unzip API
00026 #include "unzip.h"
00027 
00028 DEFINE_RUNTIME_CLASSTYPE_CODE(NamedArchiveFile,ArchiveFile)
00029 
00030 DEFINE_RUNTIME_CLASSTYPE_CODE(ZipFile,NamedArchiveFile);
00031 
00032 
00033 
00034 // ioapi IDataSource wrapper functions
00035 
00036 static voidpf ids_open(voidpf opaque, const char* filename, int mode);
00037 static uLong ids_read(voidpf opaque, voidpf stream, void* buf, uLong size);
00038 static uLong ids_write(voidpf opaque, voidpf stream,
00039                                            const void* buf, uLong size);
00040 static long ids_tell(voidpf opaque, voidpf stream);
00041 static long ids_seek(voidpf opaque, voidpf stream, uLong offset, int origin);
00042 static int ids_close(voidpf opaque, voidpf stream);
00043 static int ids_error(voidpf opaque, voidpf stream);
00044 
00045 PentZip::zlib_filefunc_def IDS_filefunc_templ = {
00046         ids_open, ids_read, ids_write, ids_tell, ids_seek, ids_close, ids_error, 0
00047 };
00048 
00049 
00050 ZipFile::ZipFile(IDataSource* ds_)
00051 {
00052         ds = ds_;
00053         PentZip::zlib_filefunc_def filefuncs = IDS_filefunc_templ;
00054         filefuncs.opaque = static_cast<void*>(ds);
00055 
00056         // filefuncs contains the datasource, so no need to actually use a path
00057         PentZip::unzFile unzfile = PentZip::unzOpen2("", &filefuncs);
00058 
00059         valid = (unzfile != 0);
00060 
00061         unzipfile = static_cast<void*>(unzfile);
00062 
00063         if (valid) {
00064                 valid = readMetadata();
00065                 if (!valid) PentZip::unzClose(unzfile);
00066         }
00067 }
00068 
00069 
00070 ZipFile::~ZipFile()
00071 {
00072         if (valid) {
00073                 PentZip::unzFile unzfile = static_cast<PentZip::unzFile>(unzipfile);
00074                 PentZip::unzClose(unzfile);             
00075         }
00076         delete ds;
00077 }
00078 
00079 //static
00080 bool ZipFile::isZipFile(IDataSource* ids)
00081 {
00082         PentZip::zlib_filefunc_def filefuncs = IDS_filefunc_templ;
00083         filefuncs.opaque = static_cast<void*>(ids);
00084 
00085         // filefuncs contains the datasource, so no need to actually use a path
00086         PentZip::unzFile unzfile = PentZip::unzOpen2("", &filefuncs);
00087 
00088         if (unzfile != 0) {
00089                 PentZip::unzClose(unzfile);
00090                 return true;
00091         }
00092 
00093         return false;
00094 }
00095 
00096 bool ZipFile::readMetadata()
00097 {
00098         PentZip::unzFile unzfile = static_cast<PentZip::unzFile>(unzipfile);
00099 
00100         PentZip::unz_global_info ginfo;
00101         if (PentZip::unzGetGlobalInfo(unzfile, &ginfo) != UNZ_OK) return false;
00102 
00103         count = ginfo.number_entry;
00104 
00105         globalComment = "";
00106         if (ginfo.size_comment > 0) {
00107                 char* commentbuf = new char[ginfo.size_comment+1];
00108                 int c = PentZip::unzGetGlobalComment(unzfile,
00109                                                                                          commentbuf, ginfo.size_comment+1);
00110                 if (c > 0) globalComment = commentbuf;
00111                 delete[] commentbuf;
00112         }
00113 
00114         PentZip::unz_file_info info;
00115         char name[256];
00116 
00117         bool done = (PentZip::unzGoToFirstFile(unzfile) != UNZ_OK);
00118 
00119         while (!done) {
00120                 int ret = PentZip::unzGetCurrentFileInfo(unzfile, &info, name, 256,
00121                                                                                                  0, 0, 0, 0);
00122                 if (ret != UNZ_OK) continue;
00123 
00124                 std::string filename = name;
00125                 storeIndexedName(filename);
00126                 sizes[filename] = info.uncompressed_size;
00127 
00128                 done = (PentZip::unzGoToNextFile(unzfile) != UNZ_OK);
00129         }
00130 
00131         return true;
00132 }
00133 
00134 bool ZipFile::exists(const std::string& name)
00135 {
00136         std::map<std::string, uint32>::iterator iter;
00137         iter = sizes.find(name);
00138         return (iter != sizes.end());
00139 }
00140 
00141 uint32 ZipFile::getSize(const std::string& name)
00142 {
00143         std::map<std::string, uint32>::iterator iter;
00144         iter = sizes.find(name);
00145         if (iter == sizes.end()) return 0;
00146         return (iter->second);
00147 }
00148 
00149 uint8* ZipFile::getObject(const std::string& name, uint32* sizep)
00150 {
00151         PentZip::unzFile unzfile = static_cast<PentZip::unzFile>(unzipfile);
00152         if (sizep) *sizep = 0;
00153 
00154         if (PentZip::unzLocateFile(unzfile, name.c_str(), 1) != UNZ_OK) return 0;
00155 
00156         PentZip::unz_file_info info;
00157         uint8* buf = 0;
00158 
00159         if (PentZip::unzGetCurrentFileInfo(unzfile, &info, 0, 0, 0, 0, 0, 0)
00160                 != UNZ_OK)
00161                 return 0;
00162 
00163         if (PentZip::unzOpenCurrentFile(unzfile) != UNZ_OK) return 0;
00164         uint32 size = info.uncompressed_size;
00165 
00166         buf = new uint8[size];
00167 
00168         if (PentZip::unzReadCurrentFile(unzfile, buf, size) < size) {
00169                 delete[] buf;
00170                 return 0;
00171         }
00172 
00173         if (PentZip::unzCloseCurrentFile(unzfile) != UNZ_OK) {
00174                 delete[] buf;
00175                 return 0;
00176         }
00177 
00178         if (sizep) *sizep = size;
00179 
00180         return buf;
00181 }
00182 
00183 
00184 
00185 // ------------
00186 
00187 static voidpf ids_open(voidpf opaque, const char* filename, int mode)
00188 {
00189         // read-only, for now
00190         if (mode != (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING))
00191                 return 0;
00192 
00193         // opaque is actually the IDataSource*
00194         return opaque;
00195 }
00196 
00197 static uLong ids_read(voidpf opaque, voidpf stream, void* buf, uLong size)
00198 {
00199         IDataSource* ids = static_cast<IDataSource*>(stream);
00200         return ids->read(buf, size);
00201 }
00202 
00203 static uLong ids_write(voidpf opaque, voidpf stream,
00204                                            const void* buf, uLong size)
00205 {
00206         return 0;
00207 }
00208 
00209 static long ids_tell(voidpf opaque, voidpf stream)
00210 {
00211         IDataSource* ids = static_cast<IDataSource*>(stream);
00212         return ids->getPos();
00213 }
00214 
00215 static long ids_seek(voidpf opaque, voidpf stream, uLong offset, int origin)
00216 {
00217         IDataSource* ids = static_cast<IDataSource*>(stream);
00218         switch (origin) {
00219         case ZLIB_FILEFUNC_SEEK_CUR:
00220                 ids->skip(offset);
00221                 break;
00222         case ZLIB_FILEFUNC_SEEK_END:
00223                 ids->seek(ids->getSize()+offset);
00224                 break;
00225         case ZLIB_FILEFUNC_SEEK_SET:
00226                 ids->seek(offset);
00227                 break;
00228         default:
00229                 return -1;
00230         }
00231         return 0;
00232 }
00233 
00234 static int ids_close(voidpf opaque, voidpf stream)
00235 {
00236         return 0;
00237 }
00238 
00239 static int ids_error(voidpf opaque, voidpf stream)
00240 {
00241         return 0;
00242 }
00243 

Generated on Fri Jul 27 22:27:56 2007 for pentagram by  doxygen 1.4.7