RetroZilla/modules/libjar/nsZipArchive.h
2015-10-20 23:03:22 -04:00

424 lines
12 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Veditz <dveditz@netscape.com>
* Samir Gehani <sgehani@netscape.com>
* Mitch Stoltz <mstoltz@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsZipArchive_h_
#define nsZipArchive_h_
#define ZIP_MAGIC 0x5A49505FL /* "ZIP_" */
#define ZIPFIND_MAGIC 0x5A495046L /* "ZIPF" */
#define ZIP_TABSIZE 256
// Keep this odd. The -1 is significant.
#define ZIP_BUFLEN (4 * 1024 - 1)
#ifdef STANDALONE
#define nsZipArchive nsZipArchiveStandalone
#define ZIP_Seek(fd,p,m) (fseek((fd),(p),(m))==0)
#else
#define PL_ARENA_CONST_ALIGN_MASK 7
#include "plarena.h"
#define ZIP_Seek(fd,p,m) (PR_Seek((fd),((PROffset32)p),(m))==((PROffset32)p))
#endif
#include "zlib.h"
class nsZipFind;
class nsZipReadState;
class nsZipItemMetadata;
#ifndef STANDALONE
struct PRFileDesc;
#endif
/**
* This file defines some of the basic structures used by libjar to
* read Zip files. It makes use of zlib in order to do the decompression.
*
* A few notes on the classes:
* nsZipArchive represents a single Zip file, and maintains an index
* of all the items in the file.
* nsZipItem represents a single item (file) in the Zip archive.
* nsZipReadState represents a read-in-progress, and maintains all
* zlib state
* nsZipFind represents the metadata involved in doing a search,
* and current state of the iteration of found objects.
*
* There is a lot of #ifdef STANDALONE here, and that is so that these
* basic structures can be reused in a standalone static
* library. In order for the code to be reused, these structures
* should never use anything from XPCOM, including such obvious things
* as NS_ASSERTION(). Instead, use the basic NSPR equivalents.
*
* There is one key difference in the way that this code behaves in
* STANDALONE mode. In STANDALONE mode, the nsZipArchive owns the
* single file descriptor and that is used to read the ZIP file. Since
* there is only one nsZipArchive per file, you can only read one file
* at a time from the Zip file.
*
* In non-STANDALONE mode, nsZipReadState owns the file descriptor.
* Since there can be multiple nsZipReadStates in existence at the
* same time, there can be multiple reads from the same nsZipArchive
* happening at the same time.
*/
/**
* nsZipItem -- a helper class for nsZipArchive
*
* each nsZipItem represents one file in the archive and all the
* information needed to manipulate it.
*/
class nsZipItem
{
public:
char* name; /* '\0' terminated */
PRUint32 headerOffset;
PRUint32 dataOffset;
PRUint32 size; /* size in original file */
PRUint32 realsize; /* inflated size */
PRUint32 crc32;
nsZipItem* next;
/*
* Keep small items together, to avoid overhead.
*/
PRUint16 mode;
PRUint16 time;
PRUint16 date;
/*
* Keep small items together, to avoid overhead.
*/
PRUint8 compression;
PRPackedBool hasDataOffset : 1;
PRPackedBool isSymlink : 1;
#ifndef STANDALONE
/**
* GetModTime
*
* Utility to get an NSPR-friendly formatted string
* representing the last modified time of this item.
*
* @return nsprstr The modification time in PRTime
*/
PRTime GetModTime();
#endif
nsZipItem();
~nsZipItem();
private:
//-- prevent copies and assignments
nsZipItem& operator=(const nsZipItem& rhs);
nsZipItem(const nsZipItem& rhs);
};
/**
* nsZipArchive -- a class for reading the PKZIP file format.
*
*/
class nsZipArchive
{
public:
/** cookie used to validate supposed objects passed from C code */
const PRInt32 kMagic;
/** Block size by which Arena grows. Arena used by filelists */
const PRUint32 kArenaBlockSize;
/** constructing does not open the archive. See OpenArchive() */
nsZipArchive();
/** destructing the object closes the archive */
~nsZipArchive();
#ifdef STANDALONE
/** helper routine for passing around mFd
*/
PRFileDesc* GetFd() { return mFd; }
#endif
/**
* OpenArchive
*
* It's an error to call this more than once on the same nsZipArchive
* object. If we were allowed to use exceptions this would have been
* part of the constructor
*
* @param aArchiveName full pathname of archive
* @return status code
*/
#ifdef STANDALONE
PRInt32 OpenArchive(const char * aArchiveName);
#else
PRInt32 OpenArchiveWithFileDesc(PRFileDesc* fd);
#endif
/**
* Test the integrity of items in this archive by running
* a CRC check after extracting each item into a memory
* buffer. If an entry name is supplied only the
* specified item is tested. Else, if null is supplied
* then all the items in the archive are tested.
*
* @return status code
*/
PRInt32 Test(const char *aEntryName, PRFileDesc* aFd);
/**
* Closes an open archive.
*/
PRInt32 CloseArchive();
/**
* GetItem
*
* @param aFilename Name of file in the archive
* @return status code
*/
PRInt32 GetItem(const char * aFilename, nsZipItem** result);
/**
* ReadInit
*
* Prepare to read from an item in the archive. Takes ownership of
* the file descriptor, and will retain responsibility for closing
* it property upon destruction.
*
* @param zipEntry name of item in file
* @param aRead is filled with appropriate values
* @return status code
*/
PRInt32 ReadInit(const char* zipEntry, nsZipReadState* aRead, PRFileDesc* aFd);
/**
* ExtractFile
*
* @param zipEntry name of file in archive to extract
* @param aOutname where to extract on disk
* @return status code
*/
PRInt32 ExtractFile(const char * zipEntry, const char * aOutname,
PRFileDesc* aFd);
PRInt32 ExtractItemToFileDesc(nsZipItem* item, PRFileDesc* outFD,
PRFileDesc* aFd);
/**
* FindInit
*
* Initializes a search for files in the archive. FindNext() returns
* the actual matches. FindFree() must be called when you're done
*
* @param aPattern a string or RegExp pattern to search for
* (may be NULL to find all files in archive)
* @return a structure used in FindNext. NULL indicates error
*/
nsZipFind* FindInit(const char * aPattern);
/**
* FindNext
*
* @param aFind the Find structure returned by FindInit
* @param aResult the next item that matches the pattern
*/
PRInt32 FindNext(nsZipFind* aFind, nsZipItem** aResult);
PRInt32 FindFree(nsZipFind *aFind);
#ifdef XP_UNIX
/**
* ResolveSymLinks
* @param path where the file is located
* @param zipItem the zipItem related to "path"
*/
PRInt32 ResolveSymlink(const char *path, nsZipItem *zipItem);
#endif
private:
//--- private members ---
nsZipItem* mFiles[ZIP_TABSIZE];
#ifndef STANDALONE
PLArenaPool mArena;
#else
// in standalone, each nsZipArchive has its own mFd
PRFileDesc *mFd;
#endif
//--- private methods ---
nsZipArchive& operator=(const nsZipArchive& rhs); // prevent assignments
nsZipArchive(const nsZipArchive& rhs); // prevent copies
PRInt32 BuildFileList(PRFileDesc* aFd);
nsZipItem* GetFileItem(const char * zipEntry);
PRUint32 HashName(const char* aName);
PRInt32 SeekToItem(const nsZipItem* aItem,
PRFileDesc* aFd);
PRInt32 CopyItemToDisk(const nsZipItem* aItem, PRFileDesc* outFD,
PRFileDesc* aFd);
PRInt32 InflateItem(const nsZipItem* aItem, PRFileDesc* outFD,
PRFileDesc* aFd);
PRInt32 TestItem(const nsZipItem *aItem,
PRFileDesc* aFd);
};
/**
* nsZipReadState
*
* a helper class for nsZipArchive, representing a read in progress
*/
class nsZipReadState
{
public:
nsZipReadState() :
#ifndef STANDALONE
mFd(0),
#endif
mCurPos(0)
{ MOZ_COUNT_CTOR(nsZipReadState); }
~nsZipReadState()
{
#ifndef STANDALONE
if (mFd)
PR_Close(mFd);
#endif
MOZ_COUNT_DTOR(nsZipReadState);
}
void Init(nsZipItem* aZipItem, PRFileDesc* aFd);
#ifndef STANDALONE
/**
* Read
*
* Read from the item specified to ReadInit. ReadInit must be
* called first.
*
* @param aRead the structure returned by ReadInit
* @param buf buffer to write data into.
* @param count number of bytes to read
* @param actual (out) number of bytes read
* @return status code
*/
PRInt32 Read(char* buf, PRUint32 count, PRUint32* actual);
#endif
/**
* Available
*
* Returns the number of bytes left to be read from the
* item specified to ReadInit. ReadInit must be called first.
*
* @param aRead the structure returned by ReadInit
* @return the number of bytes still to be read
*/
PRUint32 Available();
#ifndef STANDALONE
PRFileDesc* mFd;
#endif
nsZipItem* mItem;
PRUint32 mCurPos;
unsigned char mReadBuf[ZIP_BUFLEN];
z_stream mZs;
PRUint32 mCrc;
private:
#ifndef STANDALONE
PRInt32 ContinueInflate(char* aBuf,
PRUint32 aCount,
PRUint32* aBytesRead);
PRInt32 ContinueCopy(char* aBuf,
PRUint32 aCount,
PRUint32* aBytesRead);
#endif
//-- prevent copies and assignments
nsZipReadState& operator=(const nsZipReadState& rhs);
nsZipReadState(const nsZipFind& rhs);
};
/**
* nsZipFind
*
* a helper class for nsZipArchive, representing a search
*/
class nsZipFind
{
friend class nsZipArchive;
public:
const PRInt32 kMagic;
nsZipFind(nsZipArchive* aZip, char* aPattern, PRBool regExp);
~nsZipFind();
nsZipArchive* GetArchive();
private:
nsZipArchive* mArchive;
char* mPattern;
PRUint16 mSlot;
nsZipItem* mItem;
PRBool mRegExp;
//-- prevent copies and assignments
nsZipFind& operator=(const nsZipFind& rhs);
nsZipFind(const nsZipFind& rhs);
};
#endif /* nsZipArchive_h_ */