File indexing completed on 2025-01-26 04:24:53
0001 /* ioapi.c -- IO base function header for compress/uncompress .zip 0002 files using zlib + zip or unzip API 0003 0004 Version 1.01e, February 12th, 2005 0005 0006 Copyright (C) 1998-2005 Gilles Vollant 0007 0008 Modified by Sergey A. Tachenov to integrate with Qt. 0009 */ 0010 0011 #include <stdio.h> 0012 #include <stdlib.h> 0013 #include <string.h> 0014 0015 #include "zlib.h" 0016 #include "ioapi.h" 0017 #include "quazip_global.h" 0018 #include <QIODevice> 0019 #if (QT_VERSION >= 0x050100) 0020 #define QUAZIP_QSAVEFILE_BUG_WORKAROUND 0021 #endif 0022 #ifdef QUAZIP_QSAVEFILE_BUG_WORKAROUND 0023 #include <QSaveFile> 0024 #endif 0025 0026 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ 0027 0028 #ifndef SEEK_CUR 0029 #define SEEK_CUR 1 0030 #endif 0031 0032 #ifndef SEEK_END 0033 #define SEEK_END 2 0034 #endif 0035 0036 #ifndef SEEK_SET 0037 #define SEEK_SET 0 0038 #endif 0039 0040 voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,voidpf file,int mode) 0041 { 0042 if (pfilefunc->zfile_func64.zopen64_file != NULL) 0043 return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,file,mode); 0044 else 0045 { 0046 return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,file,mode); 0047 } 0048 } 0049 0050 int call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) 0051 { 0052 if (pfilefunc->zfile_func64.zseek64_file != NULL) 0053 return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); 0054 else 0055 { 0056 uLong offsetTruncated = (uLong)offset; 0057 if (offsetTruncated != offset) 0058 return -1; 0059 else 0060 return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); 0061 } 0062 } 0063 0064 ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) 0065 { 0066 if (pfilefunc->zfile_func64.zseek64_file != NULL) 0067 return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); 0068 else 0069 { 0070 uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); 0071 if ((tell_uLong) == ((uLong)-1)) 0072 return (ZPOS64_T)-1; 0073 else 0074 return tell_uLong; 0075 } 0076 } 0077 0078 /// @cond internal 0079 struct QIODevice_descriptor { 0080 // Position only used for writing to sequential devices. 0081 qint64 pos; 0082 inline QIODevice_descriptor(): 0083 pos(0) 0084 {} 0085 }; 0086 /// @endcond 0087 0088 voidpf ZCALLBACK qiodevice_open_file_func ( 0089 voidpf opaque, 0090 voidpf file, 0091 int mode) 0092 { 0093 QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque); 0094 QIODevice *iodevice = reinterpret_cast<QIODevice*>(file); 0095 QIODevice::OpenMode desiredMode; 0096 if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) 0097 desiredMode = QIODevice::ReadOnly; 0098 else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) 0099 desiredMode = QIODevice::ReadWrite; 0100 else if (mode & ZLIB_FILEFUNC_MODE_CREATE) 0101 desiredMode = QIODevice::WriteOnly; 0102 if (iodevice->isOpen()) { 0103 if ((iodevice->openMode() & desiredMode) == desiredMode) { 0104 if (desiredMode != QIODevice::WriteOnly 0105 && iodevice->isSequential()) { 0106 // We can use sequential devices only for writing. 0107 delete d; 0108 return NULL; 0109 } else { 0110 if ((desiredMode & QIODevice::WriteOnly) != 0) { 0111 // open for writing, need to seek existing device 0112 if (!iodevice->isSequential()) { 0113 iodevice->seek(0); 0114 } else { 0115 d->pos = iodevice->pos(); 0116 } 0117 } 0118 } 0119 return iodevice; 0120 } else { 0121 delete d; 0122 return NULL; 0123 } 0124 } 0125 iodevice->open(desiredMode); 0126 if (iodevice->isOpen()) { 0127 if (desiredMode != QIODevice::WriteOnly && iodevice->isSequential()) { 0128 // We can use sequential devices only for writing. 0129 iodevice->close(); 0130 delete d; 0131 return NULL; 0132 } else { 0133 return iodevice; 0134 } 0135 } else { 0136 delete d; 0137 return NULL; 0138 } 0139 } 0140 0141 0142 uLong ZCALLBACK qiodevice_read_file_func ( 0143 voidpf opaque, 0144 voidpf stream, 0145 void* buf, 0146 uLong size) 0147 { 0148 QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque); 0149 QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream); 0150 qint64 ret64 = iodevice->read((char*)buf,size); 0151 uLong ret; 0152 ret = (uLong) ret64; 0153 if (ret64 != -1) { 0154 d->pos += ret64; 0155 } 0156 return ret; 0157 } 0158 0159 0160 uLong ZCALLBACK qiodevice_write_file_func ( 0161 voidpf opaque, 0162 voidpf stream, 0163 const void* buf, 0164 uLong size) 0165 { 0166 QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque); 0167 QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream); 0168 uLong ret; 0169 qint64 ret64 = iodevice->write((char*)buf,size); 0170 if (ret64 != -1) { 0171 d->pos += ret64; 0172 } 0173 ret = (uLong) ret64; 0174 return ret; 0175 } 0176 0177 uLong ZCALLBACK qiodevice_tell_file_func ( 0178 voidpf opaque, 0179 voidpf stream) 0180 { 0181 QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque); 0182 QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream); 0183 uLong ret; 0184 qint64 ret64; 0185 if (iodevice->isSequential()) { 0186 ret64 = d->pos; 0187 } else { 0188 ret64 = iodevice->pos(); 0189 } 0190 ret = static_cast<uLong>(ret64); 0191 return ret; 0192 } 0193 0194 ZPOS64_T ZCALLBACK qiodevice64_tell_file_func ( 0195 voidpf opaque, 0196 voidpf stream) 0197 { 0198 QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque); 0199 QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream); 0200 qint64 ret; 0201 if (iodevice->isSequential()) { 0202 ret = d->pos; 0203 } else { 0204 ret = iodevice->pos(); 0205 } 0206 return static_cast<ZPOS64_T>(ret); 0207 } 0208 0209 int ZCALLBACK qiodevice_seek_file_func ( 0210 voidpf /*opaque UNUSED*/, 0211 voidpf stream, 0212 uLong offset, 0213 int origin) 0214 { 0215 QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream); 0216 if (iodevice->isSequential()) { 0217 if (origin == ZLIB_FILEFUNC_SEEK_END 0218 && offset == 0) { 0219 // sequential devices are always at end (needed in mdAppend) 0220 return 0; 0221 } else { 0222 qWarning("qiodevice_seek_file_func() called for sequential device"); 0223 return -1; 0224 } 0225 } 0226 uLong qiodevice_seek_result=0; 0227 int ret; 0228 switch (origin) 0229 { 0230 case ZLIB_FILEFUNC_SEEK_CUR : 0231 qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset; 0232 break; 0233 case ZLIB_FILEFUNC_SEEK_END : 0234 qiodevice_seek_result = ((QIODevice*)stream)->size() - offset; 0235 break; 0236 case ZLIB_FILEFUNC_SEEK_SET : 0237 qiodevice_seek_result = offset; 0238 break; 0239 default: 0240 return -1; 0241 } 0242 ret = !iodevice->seek(qiodevice_seek_result); 0243 return ret; 0244 } 0245 0246 int ZCALLBACK qiodevice64_seek_file_func ( 0247 voidpf /*opaque UNUSED*/, 0248 voidpf stream, 0249 ZPOS64_T offset, 0250 int origin) 0251 { 0252 QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream); 0253 if (iodevice->isSequential()) { 0254 if (origin == ZLIB_FILEFUNC_SEEK_END 0255 && offset == 0) { 0256 // sequential devices are always at end (needed in mdAppend) 0257 return 0; 0258 } else { 0259 qWarning("qiodevice_seek_file_func() called for sequential device"); 0260 return -1; 0261 } 0262 } 0263 qint64 qiodevice_seek_result=0; 0264 int ret; 0265 switch (origin) 0266 { 0267 case ZLIB_FILEFUNC_SEEK_CUR : 0268 qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset; 0269 break; 0270 case ZLIB_FILEFUNC_SEEK_END : 0271 qiodevice_seek_result = ((QIODevice*)stream)->size() - offset; 0272 break; 0273 case ZLIB_FILEFUNC_SEEK_SET : 0274 qiodevice_seek_result = offset; 0275 break; 0276 default: 0277 return -1; 0278 } 0279 ret = !iodevice->seek(qiodevice_seek_result); 0280 return ret; 0281 } 0282 0283 int ZCALLBACK qiodevice_close_file_func ( 0284 voidpf opaque, 0285 voidpf stream) 0286 { 0287 QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque); 0288 delete d; 0289 QIODevice *device = reinterpret_cast<QIODevice*>(stream); 0290 #ifdef QUAZIP_QSAVEFILE_BUG_WORKAROUND 0291 // QSaveFile terribly breaks the is-a idiom: 0292 // it IS a QIODevice, but it is NOT compatible with it: close() is private 0293 QSaveFile *file = qobject_cast<QSaveFile*>(device); 0294 if (file != NULL) { 0295 // We have to call the ugly commit() instead: 0296 return file->commit() ? 0 : -1; 0297 } 0298 #endif 0299 device->close(); 0300 return 0; 0301 } 0302 0303 int ZCALLBACK qiodevice_fakeclose_file_func ( 0304 voidpf opaque, 0305 voidpf /*stream*/) 0306 { 0307 QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque); 0308 delete d; 0309 return 0; 0310 } 0311 0312 int ZCALLBACK qiodevice_error_file_func ( 0313 voidpf /*opaque UNUSED*/, 0314 voidpf /*stream UNUSED*/) 0315 { 0316 // can't check for error due to the QIODevice API limitation 0317 return 0; 0318 } 0319 0320 void fill_qiodevice_filefunc ( 0321 zlib_filefunc_def* pzlib_filefunc_def) 0322 { 0323 pzlib_filefunc_def->zopen_file = qiodevice_open_file_func; 0324 pzlib_filefunc_def->zread_file = qiodevice_read_file_func; 0325 pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; 0326 pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func; 0327 pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func; 0328 pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; 0329 pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; 0330 pzlib_filefunc_def->opaque = new QIODevice_descriptor; 0331 } 0332 0333 void fill_qiodevice64_filefunc ( 0334 zlib_filefunc64_def* pzlib_filefunc_def) 0335 { 0336 // Open functions are the same for Qt. 0337 pzlib_filefunc_def->zopen64_file = qiodevice_open_file_func; 0338 pzlib_filefunc_def->zread_file = qiodevice_read_file_func; 0339 pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; 0340 pzlib_filefunc_def->ztell64_file = qiodevice64_tell_file_func; 0341 pzlib_filefunc_def->zseek64_file = qiodevice64_seek_file_func; 0342 pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; 0343 pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; 0344 pzlib_filefunc_def->opaque = new QIODevice_descriptor; 0345 pzlib_filefunc_def->zfakeclose_file = qiodevice_fakeclose_file_func; 0346 } 0347 0348 void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) 0349 { 0350 p_filefunc64_32->zfile_func64.zopen64_file = NULL; 0351 p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; 0352 p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; 0353 p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; 0354 p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; 0355 p_filefunc64_32->zfile_func64.ztell64_file = NULL; 0356 p_filefunc64_32->zfile_func64.zseek64_file = NULL; 0357 p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; 0358 p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; 0359 p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; 0360 p_filefunc64_32->zfile_func64.zfakeclose_file = NULL; 0361 p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; 0362 p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; 0363 }