This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Zip File Loader Submitted by

It is a simple ZIP file class for reading. It only decompresses whole files inside the archive, so it's not useful for streaming from a Zip file, but it may serve as a good starting point. It also assumes that there is no extra comment at the end of the ZIP file.
It requires the zlib package for the deflate code. Link with adler32.c, crc32.c, infcodes.c, inffast.c, inflate.c, inftrees.c, infutil.c and zutil.c.
The header file should be self-explanatory, but I have included a test example.

Currently browsing [zipload.zip] (3,941 bytes) - [ZipFile.h] - (1,404 bytes)

    // --------------------------------------------------------------------------
    // File:        ZipFile.h
    //
    // Purpose:     The declaration of a quick'n dirty ZIP file reader class.
    //              (C) Copyright 2000 Javier Arevalo. Use and modify as you like
    //              Get zlib from http://www.cdrom.com/pub/infozip/zlib/
    // --------------------------------------------------------------------------

    #ifndef _ZIPFILE_H_
    #define _ZIPFILE_H_

    #include <stdio.h>

    enum TError
    {
      RET_OK,
      RET_FAIL,
    };

    class CZipFile
    {
      public:

        CZipFile    (): m_nEntries(0) { }
        ~CZipFile   ()                { End(); }

        TError  Init          (FILE *f);
        void    End           ();
        bool    IsOk          ()         const { return (m_nEntries != 0); }

        int     GetNumFiles   ()         const { return m_nEntries; }

        void    GetFilename   (int i, char *pszDest) const;
        int     GetFileLen    (int i) const;

        TError  ReadFile      (int i, void *pBuf);

      private:

        struct TZipDirHeader;
        struct TZipDirFileHeader;
        struct TZipLocalHeader;

        FILE                     *m_f;
        char                     *m_pDirData; // Raw data buffer.
        int                       m_nEntries; // Number of entries.

        // Pointers to the dir entries in pDirData.
        const TZipDirFileHeader **m_papDir;
    };

    #endif // _ZIPFILE_H_

Currently browsing [zipload.zip] (3,941 bytes) - [ZipFile.cpp] - (8,416 bytes)

    // --------------------------------------------------------------------------
    // File:        ZipFile.cpp
    //
    // Purpose:     The implementation of a quick'n dirty ZIP file reader class.
    //              (C) Copyright 2000 Javier Arevalo. Use and modify as you like
    //              Get zlib from http://www.cdrom.com/pub/infozip/zlib/
    // --------------------------------------------------------------------------

    #include "ZipFile.h"
    #include "zlib.h"
    #include <string.h>

    // --------------------------------------------------------------------------
    // Basic types.
    // --------------------------------------------------------------------------
    typedef unsigned long dword;
    typedef unsigned short word;
    typedef unsigned char byte;

    // --------------------------------------------------------------------------
    // ZIP file structures. Note these have to be packed.
    // --------------------------------------------------------------------------

    #pragma pack(2)
    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------
    struct CZipFile::TZipLocalHeader
    {
      enum
      {
        SIGNATURE = 0x04034b50,
        COMP_STORE  = 0,
        COMP_DEFLAT = 8,
      };
      dword   sig;
      word    version;
      word    flag;
      word    compression;      // COMP_xxxx
      word    modTime;
      word    modDate;
      dword   crc32;
      dword   cSize;
      dword   ucSize;
      word    fnameLen;         // Filename string follows header.
      word    xtraLen;          // Extra field follows filename.
    };

    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------
    struct CZipFile::TZipDirHeader
    {
      enum
      {
        SIGNATURE = 0x06054b50,
      };
      dword   sig;
      word    nDisk;
      word    nStartDisk;
      word    nDirEntries;
      word    totalDirEntries;
      dword   dirSize;
      dword   dirOffset;
      word    cmntLen;
    };

    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------
    struct CZipFile::TZipDirFileHeader
    {
      enum
      {
        SIGNATURE   = 0x02014b50,
        COMP_STORE  = 0,
        COMP_DEFLAT = 8,
      };
      dword   sig;
      word    verMade;
      word    verNeeded;
      word    flag;
      word    compression;      // COMP_xxxx
      word    modTime;
      word    modDate;
      dword   crc32;
      dword   cSize;            // Compressed size
      dword   ucSize;           // Uncompressed size
      word    fnameLen;         // Filename string follows header.
      word    xtraLen;          // Extra field follows filename.
      word    cmntLen;          // Comment field follows extra field.
      word    diskStart;
      word    intAttr;
      dword   extAttr;
      dword   hdrOffset;

      char *GetName   () const { return (char *)(this + 1);   }
      char *GetExtra  () const { return GetName() + fnameLen; }
      char *GetComment() const { return GetExtra() + xtraLen; }
    };

    #pragma pack()

    // --------------------------------------------------------------------------
    // Function:      Init
    // Purpose:       Initialize the object and read the zip file directory.
    // Parameters:    A stdio FILE* used for reading.
    // --------------------------------------------------------------------------
    TError CZipFile::Init(FILE *f)
    {
      End();
      if (f == NULL)
        return RET_FAIL;

      // Assuming no extra comment at the end, read the whole end record.
      TZipDirHeader dh;

      fseek(f, -(int)sizeof(dh), SEEK_END);
      long dhOffset = ftell(f);
      memset(&dh, 0, sizeof(dh));
      fread(&dh, sizeof(dh), 1, f);

      // Check
      if (dh.sig != TZipDirHeader::SIGNATURE)
        return RET_FAIL;

      // Go to the beginning of the directory.
      fseek(f, dhOffset - dh.dirSize, SEEK_SET);

      // Allocate the data buffer, and read the whole thing.
      m_pDirData = new char[dh.dirSize + dh.nDirEntries*sizeof(*m_papDir)];
      if (!m_pDirData)
        return RET_FAIL;
      memset(m_pDirData, 0, dh.dirSize + dh.nDirEntries*sizeof(*m_papDir));
      fread(m_pDirData, dh.dirSize, 1, f);

      // Now process each entry.
      char *pfh = m_pDirData;
      m_papDir = (const TZipDirFileHeader **)(m_pDirData + dh.dirSize);

      TError ret = RET_OK;

      for (int i = 0; i < dh.nDirEntries && ret == RET_OK; i++)
      {
        TZipDirFileHeader &fh = *(TZipDirFileHeader*)pfh;

        // Store the address of nth file for quicker access.
        m_papDir[i] = &fh;

        // Check the directory entry integrity.
        if (fh.sig != TZipDirFileHeader::SIGNATURE)
          ret = RET_FAIL;
        else
        {
          pfh += sizeof(fh);

          // Convert UNIX slashes to DOS backlashes.
          for (int j = 0; j < fh.fnameLen; j++)
            if (pfh[j] == '/')
              pfh[j] = '\\';

          // Skip name, extra and comment fields.
          pfh += fh.fnameLen + fh.xtraLen + fh.cmntLen;
        }
      }
      if (ret != RET_OK)
        delete[] m_pDirData;
      else
      {
        m_nEntries = dh.nDirEntries;
        m_f = f;
      }

      return ret;
    }

    // --------------------------------------------------------------------------
    // Function:      End
    // Purpose:       Finish the object
    // Parameters:
    // --------------------------------------------------------------------------
    void CZipFile::End()
    {
      if (IsOk())
      {
        delete[] m_pDirData;
        m_nEntries = 0;
      }
    }

    // --------------------------------------------------------------------------
    // Function:      GetFilename
    // Purpose:       Return the name of a file
    // Parameters:    The file index and the buffer where to store the filename
    // --------------------------------------------------------------------------
    void CZipFile::GetFilename(int i, char *pszDest)  const
    {
      if (pszDest != NULL)
      {
        if (i < 0 || i >= m_nEntries)
          *pszDest = '\0';
        else
        {
          memcpy(pszDest, m_papDir[i]->GetName(), m_papDir[i]->fnameLen);
          pszDest[m_papDir[i]->fnameLen] = '\0';
        }
      }
    }

    // --------------------------------------------------------------------------
    // Function:      GetFileLen
    // Purpose:       Return the length of a file so a buffer can be allocated
    // Parameters:    The file index.
    // --------------------------------------------------------------------------
    int CZipFile::GetFileLen(int i) const
    {
      if (i < 0 || i >= m_nEntries)
        return -1;
      else
        return m_papDir[i]->ucSize;
    }

    // --------------------------------------------------------------------------
    // Function:      ReadFile
    // Purpose:       Uncompress a complete file
    // Parameters:    The file index and the pre-allocated buffer
    // --------------------------------------------------------------------------
    TError CZipFile::ReadFile(int i, void *pBuf)
    {
      if (pBuf == NULL || i < 0 || i >= m_nEntries)
        return RET_FAIL;

      // Quick'n dirty read, the whole file at once.
      // Ungood if the ZIP has huge files inside

      // Go to the actual file and read the local header.
      fseek(m_f, m_papDir[i]->hdrOffset, SEEK_SET);
      TZipLocalHeader h;

      memset(&h, 0, sizeof(h));
      fread(&h, sizeof(h), 1, m_f);
      if (h.sig != TZipLocalHeader::SIGNATURE)
        return RET_FAIL;

      // Skip extra fields
      fseek(m_f, h.fnameLen + h.xtraLen, SEEK_CUR);

      if (h.compression == TZipLocalHeader::COMP_STORE)
      {
        // Simply read in raw stored data.
        fread(pBuf, h.cSize, 1, m_f);
        return RET_OK;
      }
      else if (h.compression != TZipLocalHeader::COMP_DEFLAT)
        return RET_FAIL;

      // Alloc compressed data buffer and read the whole stream
      char *pcData = new char[h.cSize];
      if (!pcData)
        return RET_FAIL;

      memset(pcData, 0, h.cSize);
      fread(pcData, h.cSize, 1, m_f);

      TError ret = RET_OK;

      // Setup the inflate stream.
      z_stream stream;
      int err;

      stream.next_in = (Bytef*)pcData;
      stream.avail_in = (uInt)h.cSize;
      stream.next_out = (Bytef*)pBuf;
      stream.avail_out = h.ucSize;
      stream.zalloc = (alloc_func)0;
      stream.zfree = (free_func)0;

      // Perform inflation. wbits < 0 indicates no zlib header inside the data.
      err = inflateInit2(&stream, -MAX_WBITS);
      if (err == Z_OK)
      {
        err = inflate(&stream, Z_FINISH);
        inflateEnd(&stream);
        if (err == Z_STREAM_END)
          err = Z_OK;
        inflateEnd(&stream);
      }
      if (err != Z_OK)
        ret = RET_FAIL;

      delete[] pcData;
      return ret;
    }

Currently browsing [zipload.zip] (3,941 bytes) - [ZipLoad.cpp] - (2,065 bytes)

    #include <stdio.h>
    #include <string.h>
    #include <direct.h>

    #include "ZipFile.h"

    void MakePath(const char *pszPath)
    {
      if (pszPath[0] == '\0')
        return;

      char buf[1000];
      const char *p = pszPath;

    //  printf("MakePath(\"%s\")\n", pszPath);

      // Skip machine name in network paths like \\MyMachine\blah...
      if (p[0] == '\\' && p[1] == '\\')
        p = strchr(p+2, '\\');

      while (p != NULL && *p != '\0')
      {
        p = strchr(p, '\\');

        if (p)
        {
          memcpy(buf, pszPath, p - pszPath);
          buf[p - pszPath] = 0;
          p++;
        }
        else
          strcpy(buf, pszPath);

        if (buf[0] != '\0' && strcmp(buf, ".") && strcmp(buf, ".."))
        {
    //      printf("  Making path: \"%s\"\n", buf);
          mkdir(buf);
        }
      }
    }

    void main(int argc, const char *argv[])
    {
      if (argc > 1)
      {
        FILE *f = fopen(argv[1], "rb");
        if (f)
        {
          CZipFile zip;

          if (RET_OK != zip.Init(f))
            printf("Bad Zip file: \"%s\"\n", argv[1]);
          else
          {
            for (int i = 0; i < zip.GetNumFiles(); i++)
            {
              int len = zip.GetFileLen(i);
              char fname[1000];

              zip.GetFilename(i, fname);

              printf("File \"%s\" (%d bytes): ", fname, len);

              char *pData = new char[len];
              if (!pData)
                printf("OUT OF MEMORY\n");
              else if (RET_OK == zip.ReadFile(i, pData))
              {
                printf("OK\n");
                char dpath[1000];

                sprintf(dpath, "Data\\%s", fname);
                char *p = strrchr(dpath, '\\');
                if (p)
                {
                  *p = '\0';
                  MakePath(dpath);
                  *p = '\\';
                }
                FILE *fo = fopen(dpath, "wb");
                if (fo)
                {
                  fwrite(pData, len, 1, fo);
                  fclose(fo);
                }
              }
              else
                printf("ERROR\n");
              delete[] pData;
            }
            zip.End();
          }

          fclose(f);
        }
      }
    }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.