File indexing completed on 2024-05-12 16:29:20

0001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
0002 /* FemtoZip - superlightweight C++ module to create a compressed ZIP archive
0003    Copyright (C) 2005-2006 Ariya Hidayat <ariya@kde.org>
0004 
0005    Redistribution and use in source and binary forms, with or without
0006    modification, are permitted provided that the following conditions
0007    are met:
0008    * Redistributions of source code must retain the above copyright notice,
0009      this list of conditions and the following disclaimer.
0010    * Redistributions in binary form must reproduce the above copyright notice,
0011      this list of conditions and the following disclaimer in the documentation
0012      and/or other materials provided with the distribution.
0013    * Neither the name of the authors nor the names of its contributors may be
0014      used to endorse or promote products derived from this software without
0015      specific prior written permission.
0016 
0017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0018    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0019    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0020    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0021    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0022    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0023    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0024    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0025    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0026    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
0027    THE POSSIBILITY OF SUCH DAMAGE.
0028  */
0029 
0030 #ifndef USE_GSF_OUTPUT
0031 
0032 #include "FemtoZip.hxx"
0033 
0034 #include <stdlib.h>  // malloc, free, realoc
0035 #include <stdio.h>   // printf (debug mode)
0036 #include <string.h>  // memcpy, memset, strlen
0037 #include <time.h>    // time, localtime, time_t
0038 
0039 // uses small (16 entries) CRC table instead of the large (256 entries) one
0040 // very useful if memory requirement is critical
0041 #define FEMTOZIP_SMALLTABLE
0042 
0043 #ifdef DEBUG
0044 #define FEMTOZIP_DEBUG
0045 #endif
0046 
0047 #ifdef FEMTOZIP_DEBUG
0048 #define FZ_DEBUG(M) printf M
0049 #else
0050 #define FZ_DEBUG(M)
0051 #endif
0052 
0053 // see http://www.w3.org/TR/PNG-CRCAppendix.html on info regarding CRC-32
0054 
0055 #ifdef FEMTOZIP_SMALLTABLE
0056 static const unsigned long crc_table[16] =
0057 {
0058     0x00000000L, 0x1db71064L, 0x3b6e20c8L, 0x26d930acL,
0059     0x76dc4190L, 0x6b6b51f4L, 0x4db26158L, 0x5005713cL,
0060     0xedb88320L, 0xf00f9344L, 0xd6d6a3e8L, 0xcb61b38cL,
0061     0x9b64c2b0L, 0x86d3d2d4L, 0xa00ae278L, 0xbdbdf21cL
0062 };
0063 #else
0064 static const unsigned long crc_table[256] =
0065 {
0066     0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
0067     0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
0068     0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
0069     0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
0070     0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0071     0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
0072     0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
0073     0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
0074     0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
0075     0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0076     0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
0077     0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
0078     0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
0079     0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
0080     0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0081     0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
0082     0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
0083     0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
0084     0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
0085     0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0086     0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
0087     0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
0088     0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
0089     0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
0090     0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0091     0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
0092     0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
0093     0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
0094     0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
0095     0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0096     0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
0097     0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
0098     0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
0099     0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
0100     0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0101     0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
0102     0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
0103     0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
0104     0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
0105     0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0106     0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
0107     0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
0108     0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
0109     0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
0110     0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0111     0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
0112     0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
0113     0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
0114     0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
0115     0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0116     0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
0117     0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
0118     0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
0119     0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
0120     0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0121     0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
0122     0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
0123     0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
0124     0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
0125     0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0126     0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
0127     0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
0128     0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
0129     0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
0130 };
0131 #endif
0132 
0133 
0134 // entry record is stored as linked list
0135 
0136 class FemtoZipEntry
0137 {
0138 public:
0139     char *name;
0140     int compressionLevel;
0141     unsigned long uncompressedSize;
0142     unsigned long compressedSize;
0143     unsigned long headerPos;
0144     unsigned short timeStamp;
0145     unsigned short dateStamp;
0146     unsigned long crc32;
0147     FemtoZipEntry *next;
0148 
0149     FemtoZipEntry(const char *n, int cl):
0150         name(0), compressionLevel(cl), uncompressedSize(0),
0151         compressedSize(0), headerPos(0), timeStamp(0), dateStamp(0),
0152         crc32(0xffffffffL),   // pre-condition, all bits are '1'
0153         next(0)
0154     {
0155         name = strdup(n);
0156     }
0157 
0158     ~FemtoZipEntry()
0159     {
0160         free(name);
0161     }
0162 private:
0163     FemtoZipEntry(FemtoZipEntry const &);
0164     FemtoZipEntry &operator=(FemtoZipEntry const &);
0165 };
0166 
0167 class FemtoZipPrivate
0168 {
0169 public:
0170     int errorCode;
0171     FILE *fhandle;
0172     FemtoZipEntry *entryList;
0173     FemtoZipEntry *currentEntry;
0174     unsigned char buffer[46];
0175 
0176     FemtoZipPrivate(): errorCode(FemtoZip::NoError), fhandle(0),
0177         entryList(0), currentEntry(0)
0178     {
0179     }
0180 
0181     void createZip(const char *zipfile)
0182     {
0183         FZ_DEBUG(("Creating ZIP: %s\n", zipfile));
0184 
0185         fhandle = fopen(zipfile, "wb");
0186         if (!fhandle)
0187             errorCode = FemtoZip::ErrorCreateZip;
0188     }
0189 
0190     unsigned long updateCRC(unsigned long crc, const void *data, unsigned long len)
0191     {
0192         const unsigned char *buf = (const unsigned char *) data;
0193 
0194         for (unsigned long i = 0; i < len; i++)
0195 #ifdef FEMTOZIP_SMALLTABLE
0196         {
0197             crc ^= buf[i];
0198             crc = crc_table[crc & 0x0f] ^ (crc >> 4);
0199             crc = crc_table[crc & 0x0f] ^ (crc >> 4);
0200         }
0201 #else
0202             crc = crc_table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
0203 #endif
0204         return crc;
0205     }
0206 
0207     // write central directory, by walking the linked list
0208     // also: free the entry one by one
0209     void closeZip()
0210     {
0211         // last entry not closed
0212         if (currentEntry)
0213         {
0214             FZ_DEBUG(("automatically closing last entry %s", currentEntry->name));
0215             closeEntry();
0216         }
0217         if (!fhandle)
0218             return;
0219         unsigned long centralDirPos = (unsigned long) ftell(fhandle);
0220         unsigned short entryCount = 0;
0221         FemtoZipEntry *entry = entryList;
0222         while (entry && (errorCode == FemtoZip::NoError))
0223         {
0224             FZ_DEBUG(("central directory: entry for %s\n", entry->name));
0225             size_t namelen = strlen(entry->name);
0226 
0227             /*
0228             central directory record: total size >= 46 bytes
0229 
0230             offset  size   description
0231             ---------------------------------------
0232               0      4    signature: 'P','K',1,2
0233               4      2    version made by
0234               6      2    version needed to extract
0235               8      2    general purpose bit flag
0236              10      2    compression method 0=store 8=deflate
0237              12      2    last mod file time
0238              14      2    last mod file date
0239              16      4    crc-32
0240              20      4    compressed size
0241              24      4    uncompressed size
0242              28      2    file name length
0243              30      2    extra field length
0244              32      2    file comment length
0245              34      2    disk number start
0246              36      2    internal file attributes
0247              38      4    external file attributes
0248              42      4    relative offset of local header
0249             */
0250 
0251             buffer[0] = 0x50;
0252             buffer[1] = 0x4b;
0253             buffer[2] = 0x01;
0254             buffer[3] = 0x02;
0255             buffer[4] = 0x14;
0256             buffer[5] = 0;
0257             buffer[6] = 0x0a;
0258             buffer[7] = 0;
0259             buffer[8] = 0;
0260             buffer[9] = 0;
0261             buffer[10] = (entry->compressionLevel==0) ? 0 : 8;
0262             buffer[11] = 0x0;
0263             buffer[12] = (unsigned char)(entry->timeStamp & 0xff);
0264             buffer[13] = (unsigned char)((entry->timeStamp>>8) & 0xff);
0265             buffer[14] = (unsigned char)(entry->dateStamp & 0xff);
0266             buffer[15] = (unsigned char)((entry->dateStamp>>8) & 0xff);
0267             buffer[16] = entry->crc32 & 0xff;
0268             buffer[17] = (entry->crc32>>8) & 0xff;
0269             buffer[18] = (entry->crc32>>16) & 0xff;
0270             buffer[19] = (entry->crc32>>24) & 0xff;
0271             buffer[20] = entry->compressedSize & 0xff;
0272             buffer[21] = (entry->compressedSize>>8) & 0xff;
0273             buffer[22] = (entry->compressedSize>>16) & 0xff;
0274             buffer[23] = (entry->compressedSize>>24) & 0xff;
0275             buffer[24] = entry->uncompressedSize & 0xff;
0276             buffer[25] = (entry->uncompressedSize>>8) & 0xff;
0277             buffer[26] = (entry->uncompressedSize>>16) & 0xff;
0278             buffer[27] = (entry->uncompressedSize>>24) & 0xff;
0279             buffer[28] = namelen & 0xff;
0280             buffer[29] = (namelen>>8) & 0xff;
0281             buffer[30] = 0;
0282             buffer[31] = 0;
0283             buffer[32] = 0;
0284             buffer[33] = 0;
0285             buffer[34] = 0;
0286             buffer[35] = 0;
0287             buffer[36] = 0;
0288             buffer[37] = 0;
0289             buffer[38] = 0;
0290             buffer[39] = 0;
0291             buffer[40] = 0;
0292             buffer[41] = 0;
0293             buffer[42] = entry->headerPos & 0xff;
0294             buffer[43] = (entry->headerPos>>8) & 0xff;
0295             buffer[44] = (entry->headerPos>>16) & 0xff;
0296             buffer[45] = (entry->headerPos>>24) & 0xff;
0297 
0298             if (fwrite(buffer, 1, 46, fhandle) != 46)
0299                 errorCode = FemtoZip::ErrorWriteData;
0300             else
0301             {
0302                 if (fwrite(entry->name, 1, namelen, fhandle) != namelen)
0303                     errorCode = FemtoZip::ErrorWriteData;
0304             }
0305 
0306             FemtoZipEntry *next_entry = entry->next;
0307             delete entry;
0308             entry = next_entry;
0309             entryCount++;
0310         }
0311         unsigned long centralDirSize = (unsigned long)ftell(fhandle) - centralDirPos;
0312 
0313         /*
0314         end of central directory record: total size 22 bytes
0315 
0316         offset  size   description
0317         ---------------------------------------
0318           0      4    signature: 'P','K',5,6
0319           4      2    number of this disk
0320           6      2    number of this disk with the start of the central directory
0321           8      2    total number of entries in the central directory on this disk
0322          10      2    total number of entries in the central directory
0323          12      4    size of the central directory
0324          16      4    offset of start of central directory with respect to the starting disk number
0325          20      2    comment length
0326          22     var.  comment field
0327         */
0328 
0329         buffer[0] = 'P';
0330         buffer[1] = 'K';
0331         buffer[2] = 5;
0332         buffer[3] = 6;
0333         buffer[4] = 0x00;
0334         buffer[5] = 0x00;
0335         buffer[6] = 0x00;
0336         buffer[7] = 0x00;
0337         buffer[8] = (unsigned char)(entryCount & 0xff);
0338         buffer[9] = (unsigned char)((entryCount >> 8) & 0xff);
0339         buffer[10] = (unsigned char)(entryCount & 0xff);
0340         buffer[11] = (unsigned char)((entryCount >> 8) & 0xff);
0341         buffer[12] = centralDirSize & 0xff;
0342         buffer[13] = (centralDirSize>>8) & 0xff;
0343         buffer[14] = (centralDirSize>>16) & 0xff;
0344         buffer[15] = (centralDirSize>>24) & 0xff;
0345         buffer[16] = centralDirPos & 0xff;
0346         buffer[17] = (centralDirPos>>8) & 0xff;
0347         buffer[18] = (centralDirPos>>16) & 0xff;
0348         buffer[19] = (centralDirPos>>24) & 0xff;
0349         buffer[20] = 0x00;
0350         buffer[21] = 0x00;
0351         if (fwrite(buffer, 1, 22, fhandle) != 22)
0352             errorCode = FemtoZip::ErrorWriteData;
0353 
0354         // that's all, we're done !
0355         fclose(fhandle);
0356         fhandle = 0;
0357     }
0358 
0359     void writeLocalHeader(FemtoZipEntry *entry)
0360     {
0361         if (!entry) return;
0362 
0363         size_t namelen = strlen(entry->name);
0364 
0365         /*
0366         local file header: total size 22 bytes
0367 
0368         offset  size   description
0369         ---------------------------------------
0370           0      4    signature: 'P','K',3,4
0371           4      2    version needed to extract
0372           6      2    general purpose bit flag
0373           8      2    compression method 0=store 8=deflate
0374          10      2    last mod file time
0375          12      2    last mod file date
0376          14      4    crc-32
0377          18      4    compressed size
0378          22      4    uncompressed size
0379          26      2    file name length
0380          28      2    extra field length
0381          30     var.  file name (NOT null terminated)
0382         */
0383 
0384         buffer[0] = 'P';
0385         buffer[1] = 'K';
0386         buffer[2] = 3;
0387         buffer[3] = 4;
0388         buffer[4] = 0x0a;
0389         buffer[5] = 0;
0390         buffer[6] = 0;
0391         buffer[7] = 0;
0392         buffer[8] = (currentEntry->compressionLevel==0) ? 0 : 8;
0393         buffer[9] = 0;
0394         buffer[10] = (unsigned char)(currentEntry->timeStamp & 0xff);
0395         buffer[11] = (unsigned char)((currentEntry->timeStamp>>8) & 0xff);
0396         buffer[12] = (unsigned char)(currentEntry->dateStamp & 0xff);
0397         buffer[13] = (unsigned char)((currentEntry->dateStamp>>8) & 0xff);
0398         buffer[14] = currentEntry->crc32 & 0xff;
0399         buffer[15] = (currentEntry->crc32>>8) & 0xff;
0400         buffer[16] = (currentEntry->crc32>>16) & 0xff;
0401         buffer[17] = (currentEntry->crc32>>24) & 0xff;
0402         buffer[18] = currentEntry->compressedSize & 0xff;
0403         buffer[19] = (currentEntry->compressedSize>>8) & 0xff;
0404         buffer[20] = (currentEntry->compressedSize>>16) & 0xff;
0405         buffer[21] = (currentEntry->compressedSize>>24) & 0xff;
0406         buffer[22] = currentEntry->uncompressedSize & 0xff;
0407         buffer[23] = (currentEntry->uncompressedSize>>8) & 0xff;
0408         buffer[24] = (currentEntry->uncompressedSize>>16) & 0xff;
0409         buffer[25] = (currentEntry->uncompressedSize>>24) & 0xff;
0410         buffer[26] = namelen & 0xff;
0411         buffer[27] = (namelen>>8) & 0xff;
0412         buffer[28] = 0;
0413         buffer[29] = 0;
0414 
0415         if (fwrite(buffer, 1, 30, fhandle) != 30)
0416             errorCode = FemtoZip::ErrorWriteData;
0417         else
0418         {
0419             if (fwrite(entry->name, 1, namelen, fhandle) != namelen)
0420                 errorCode = FemtoZip::ErrorWriteData;
0421         }
0422     }
0423 
0424 
0425     void createEntry(const char *name, int compressionLevel)
0426     {
0427         if (errorCode != FemtoZip::NoError)
0428             return;
0429 
0430         if (fhandle == 0)
0431         {
0432             FZ_DEBUG(("createEntry error: file already closed"));
0433             return;
0434         }
0435 
0436         // somebody forget to close previous entry
0437         if (currentEntry != 0)
0438         {
0439             FZ_DEBUG(("createEntry warning: previous entry is not manually closed"));
0440             closeEntry();
0441         }
0442 
0443         // sanity check
0444         if (compressionLevel < 0)
0445             compressionLevel = 0;
0446 
0447         // create new entry and append it to the linked list
0448         currentEntry = new FemtoZipEntry(name, compressionLevel);
0449         if (entryList != 0)
0450         {
0451             FemtoZipEntry *e = entryList;
0452             while (e->next)
0453                 e = e->next;
0454             e->next = currentEntry;
0455         }
0456         else
0457             entryList = currentEntry;
0458 
0459         // anything to do with time stamp
0460         time_t currentEpoch;
0461         time(&currentEpoch);
0462         struct tm *currentTime = localtime(&currentEpoch);
0463 
0464         currentEntry->timeStamp = (unsigned short)
0465                                   (((currentTime->tm_hour & 31) << 11) | // 5-bit hours
0466                                    ((currentTime->tm_min & 63) << 5) |   // 6-bit minutes
0467                                    ((currentTime->tm_sec & 31)*2));       // 5-bit seconds*2
0468 
0469         if (currentTime->tm_year >= 80)
0470             // note: year is using 1980 as reference
0471             currentEntry->dateStamp = (unsigned short)
0472                                       ((((currentTime->tm_year-80) & 127) << 9) |  // 7-bit years
0473                                        (((currentTime->tm_mon+1) & 15) << 5) |     // 4-bit months
0474                                        (currentTime->tm_mday & 31));                // 5-bit days
0475         else
0476             // before 1980, can't be represented so set to Jan 1, 1980
0477             currentEntry->dateStamp = (1 << 5) | 1;
0478 
0479         // because we need to "fix" the header in closeEntry()
0480         currentEntry->headerPos = (unsigned long) ftell(fhandle);
0481 
0482         writeLocalHeader(currentEntry);
0483     }
0484 
0485     void closeEntry()
0486     {
0487         if (errorCode != FemtoZip::NoError)
0488             return;
0489 
0490         if (!fhandle)
0491         {
0492             FZ_DEBUG(("closeEntry error: file already closed"));
0493             return;
0494         }
0495 
0496         if (!currentEntry)
0497         {
0498             FZ_DEBUG(("closeEntry error: no entry is opened"));
0499             return;
0500         }
0501 
0502         currentEntry->compressedSize = currentEntry->uncompressedSize;
0503 
0504         // post-condition for the CRC-32, i.e. one's complement
0505         currentEntry->crc32 ^= 0xffffffffL;
0506 
0507         // we need to come back again here later on
0508         long filepos = ftell(fhandle);
0509 
0510         // "fix" the local header in the right position
0511         fseek(fhandle, (long) currentEntry->headerPos, SEEK_SET);
0512         writeLocalHeader(currentEntry);
0513 
0514         // back to where we left
0515         fseek(fhandle, filepos, SEEK_SET);
0516 
0517         // that's all for this one
0518         currentEntry = 0;
0519     }
0520 
0521     void writeData(unsigned long len, const void *data)
0522     {
0523         if (errorCode != FemtoZip::NoError)
0524             return;
0525 
0526         if (!fhandle)
0527         {
0528             FZ_DEBUG(("writeData error: file already closed"));
0529             return;
0530         }
0531 
0532         if (!currentEntry)
0533         {
0534             FZ_DEBUG(("writeData error: no entry is opened"));
0535             return;
0536         }
0537 
0538         currentEntry->crc32 = updateCRC(currentEntry->crc32, data, len);
0539         currentEntry->uncompressedSize += len;
0540 
0541         // method: Store
0542         if (fwrite(data, 1, len, fhandle) != len)
0543             errorCode = FemtoZip::ErrorWriteData;
0544     }
0545 };
0546 
0547 
0548 
0549 
0550 
0551 FemtoZip::FemtoZip(const char *zipfile) : d(0)
0552 {
0553     d = new FemtoZipPrivate;
0554     d->createZip(zipfile);
0555 }
0556 
0557 FemtoZip::~FemtoZip()
0558 {
0559     d->closeZip();
0560     delete d;
0561 }
0562 
0563 void FemtoZip::createEntry(const char *name, int compressionLevel)
0564 {
0565     d->createEntry(name, compressionLevel);
0566 }
0567 
0568 void FemtoZip::writeString(const char *str)
0569 {
0570     d->writeData(strlen(str), str);
0571 }
0572 
0573 void FemtoZip::closeEntry()
0574 {
0575     d->closeEntry();
0576 }
0577 
0578 int FemtoZip::errorCode() const
0579 {
0580     return d->errorCode;
0581 }
0582 
0583 #endif
0584 
0585 /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */