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 }