See what's going on with flipcode!




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.