Insert directory entries into a SortedTree for searching.

This commit is contained in:
rth%cygnus.com 1998-12-12 05:23:36 +00:00
parent 4f1d3174f2
commit 5ca08c04d2
2 changed files with 114 additions and 92 deletions

View File

@ -150,7 +150,7 @@ static void import(Internal_EndCentralDirectoryHeader *,
/* Public functions */
ZipArchive::ZipArchive(const char *archiveName, Pool &pool, bool &status)
: pool(pool), dir(0)
: pool(pool)
{
status = true;
@ -166,17 +166,6 @@ ZipArchive::~ZipArchive()
PR_Close(fp);
}
const DirectoryEntry *ZipArchive::lookup(const char *fileName)
{
Uint32 i;
for (i = 0; i < nel; ++i)
if (PL_strcasecmp(dir[i].fn, fileName) == 0)
return &dir[i];
return NULL;
}
bool ZipArchive::get(const DirectoryEntry *dp, char *&buf, Int32 &len)
{
char *xbuf;
@ -201,36 +190,45 @@ bool ZipArchive::get(const DirectoryEntry *dp, char *&buf, Int32 &len)
Uint32 ZipArchive::getNumElements(const char *fn_suffix)
{
int suf_len = strlen(fn_suffix);
Uint32 nelems;
Uint32 i;
for (i=0, nelems=0; i < nel; i++) {
char *fn = dir[i].fn;
Uint32 nelems = 0;
DirectoryEntry *entry;
entry = dir.firstNode();
while (entry) {
const char *fn = entry->fn;
int fn_len = strlen(fn);
if (suf_len >= fn_len
&& PL_strncasecmp(&fn[fn_len - suf_len], fn_suffix, suf_len) == 0) {
nelems++;
}
entry = dir.next(entry);
}
return nelems;
}
Uint32 ZipArchive::listElements(const char *fn_suffix, char **&buf)
Uint32 ZipArchive::listElements(const char *fn_suffix, char **&rbuf)
{
int suf_len = strlen(fn_suffix);
Uint32 nelems;
Uint32 i;
buf = new (pool) char *[nel];
char **buf = new (pool) char *[nel];
DirectoryEntry *entry;
rbuf = buf;
entry = dir.firstNode();
for (i=0, nelems=0; i < nel; i++) {
char *fn = dir[i].fn;
const char *fn = entry->fn;
int fn_len = strlen(fn);
if (fn_len >= suf_len
&& PL_strncasecmp(&fn[fn_len - suf_len], fn_suffix, suf_len) == 0) {
buf[nelems] = dupString(fn, pool);
nelems++;
}
entry = dir.next(entry);
}
return nelems;
}
@ -244,6 +242,7 @@ bool ZipArchive::initReader()
External_EndCentralDirectoryHeader ext_ehdr;
Internal_EndCentralDirectoryHeader int_ehdr;
char *central_directory, *cd_ptr;
DirectoryEntry *edir;
PRInt32 pos;
if (! findEnd())
@ -271,35 +270,30 @@ bool ZipArchive::initReader()
// Import all of the individual directory entries.
nel = int_ehdr.total_entries_central_dir;
dir = new (pool) DirectoryEntry[nel];
edir = new (pool) DirectoryEntry[nel];
cd_ptr = central_directory;
for (int i = 0; i < nel; ++i) {
Internal_CentralDirectoryHeader int_chdr;
import(&int_chdr, *(External_CentralDirectoryHeader*)cd_ptr);
dir[i].len = int_chdr.uncompressed_size;
dir[i].size = int_chdr.compressed_size;
dir[i].method = int_chdr.compression_method;
dir[i].mod = 0; // FIXME
dir[i].off = (int_chdr.relative_offset_local_header
+ sizeof(External_LocalFileHeader)
+ int_chdr.filename_length
+ int_chdr.file_comment_length
+ int_chdr.extra_field_length);
edir[i].len = int_chdr.uncompressed_size;
edir[i].size = int_chdr.compressed_size;
edir[i].method = int_chdr.compression_method;
edir[i].mod = 0; // FIXME
edir[i].off = (int_chdr.relative_offset_local_header
+ sizeof(External_LocalFileHeader)
+ int_chdr.filename_length
+ int_chdr.file_comment_length
+ int_chdr.extra_field_length);
// ??? Why is this extra 4 needed? infozip source is less than readable.
if (int_chdr.extra_field_length)
dir[i].off += 4;
edir[i].off += 4;
cd_ptr += sizeof(External_CentralDirectoryHeader);
dir[i].fn = cd_ptr;
edir[i].fn = cd_ptr;
cd_ptr += int_chdr.filename_length;
cd_ptr += int_chdr.extra_field_length;
// Sanity check the entry.
if (cd_ptr - central_directory > int_ehdr.size_central_directory)
return false;
// Null terminate the filename at the expense of either the
// extra_field_length padding, or the signature on the next
@ -308,7 +302,16 @@ bool ZipArchive::initReader()
// FIXME -- do we care about transforming filenames as infozip
// would have us do in the general case?
dir[i].fn[int_chdr.filename_length] = '\0';
*cd_ptr = '\0';
cd_ptr += int_chdr.extra_field_length;
// Sanity check the entry.
if (cd_ptr - central_directory > int_ehdr.size_central_directory)
return false;
// Insert the entry into the tree.
dir.insert(edir[i]);
}
return true;

View File

@ -20,40 +20,67 @@
#include "Fundamentals.h"
#include "prio.h"
#include "plstr.h"
#include "Tree.h"
/*
* Central zip directory entry
*/
typedef struct {
char *fn; /* file name */
Uint32 len; /* file size */
Uint32 size; /* file compressed size */
Int32 method; /* Compression method */
Int32 mod; /* file modification time */
Int32 off; /* file contents offset */
} DirectoryEntry;
/* An object that represents a zip archive */
class DirectoryEntry_Key {
private:
const char * const str;
public:
explicit DirectoryEntry_Key(const char *s) : str(s) { }
DirectoryEntry_Key(const DirectoryEntry_Key &other) : str(other.str) { }
bool operator== (const DirectoryEntry_Key &other) const {
return PL_strcasecmp(str, other.str) == 0;
}
bool operator< (const DirectoryEntry_Key &other) const {
return PL_strcasecmp(str, other.str) < 0;
}
};
struct DirectoryEntry : public TreeNode<DirectoryEntry> {
const char *fn; // file name
Uint32 len; // file size
Uint32 size; // file compressed size
Int32 method; // compression method
Int32 mod; // file modification time
Int32 off; // file contents offset
// Bits to interface with the tree code.
DirectoryEntry_Key getKey() const {
return DirectoryEntry_Key(fn);
}
};
/*
* An object that represents a zip archive.
*/
class ZipArchive {
public:
/* Create a zip archive reader from a zip archive whose
* canonical pathname is archiveName. Pool is used to allocate
* memory for data structures. Sets status to true if it was
* able to successfully open the archive; returns false if
* it could not.
*/
// Create a zip archive reader from a zip archive whose
// canonical pathname is archiveName. Pool is used to allocate
// memory for data structures. Sets status to true if it was
// able to successfully open the archive; returns false if
// it could not.
ZipArchive(const char *archiveName, Pool &pool, bool &status);
~ZipArchive();
/* Read a file given by fileName from the zip archive into
* buf, allocating as much memory as necessary. This memory
* is allocated using the pool passed into the constructor
* and will go away when the pool is destroyed. On success,
* returns true and sets len to the length of the file read.
* Returns false if the file was not found in the archive, or
* if there was an error.
*/
// Read a file given by fileName from the zip archive into
// buf, allocating as much memory as necessary. This memory
// is allocated using the pool passed into the constructor
// and will go away when the pool is destroyed. On success,
// returns true and sets len to the length of the file read.
// Returns false if the file was not found in the archive, or
// if there was an error.
bool get(const char *fileName, char *&buf, Int32 &len) {
const DirectoryEntry *entry = lookup(fileName);
@ -63,47 +90,40 @@ public:
return get(entry, buf, len);
}
/* Exactly like get() above, but works with a directory entry
* obtained via lookup().
*/
// Exactly like get() above, but works with a directory entry
// obtained via lookup().
bool get(const DirectoryEntry *entry, char *&buf, Int32 &len);
/* returns true if the given file exists in the archive, false
* otherwise.
*/
// Returns true if the given file exists in the archive, false
// otherwise.
bool exists(const char *fileName) {
return (lookup(fileName) != 0);
}
/* lookup a file and return it's directory entry if it exists.
* If not, return false.
*/
const DirectoryEntry *lookup(const char *fileName);
// Lookup a file and return it's directory entry if it exists.
// If not, return false.
const DirectoryEntry *lookup(const char *fileName) {
return dir.find(DirectoryEntry_Key(fileName));
}
/* Return number of elements in the zip archive whose filenames
* have the suffix indicated by fileNameSuffix.
*/
// Return number of elements in the zip archive whose filenames
// have the suffix indicated by fileNameSuffix.
Uint32 getNumElements(const char *fileNameSuffix);
/* Gets the names of all elements in the zip archive whose filenames
* have the suffix indicated by fileNameSuffix. Returns the number
* of matching elements. Memory for buf is allocated using the
* pool passed into the constructor and is destroyed when the
* pool is destroyed.
*/
// Gets the names of all elements in the zip archive whose filenames
// have the suffix indicated by fileNameSuffix. Returns the number
// of matching elements. Memory for buf is allocated using the
// pool passed into the constructor and is destroyed when the
// pool is destroyed.
Uint32 listElements(const char *fileNameSuffix, char **&buf);
private:
Pool &pool; /* Pool used to allocate internal memory */
/* File descriptor */
PRFileDesc *fp;
DirectoryEntry *dir; /* zip file directory */
Uint32 nel; /* number of directory entries */
Uint32 cenoff; /* Offset of central directory (CEN) */
Uint32 endoff; /* Offset of end-of-central-directory record */
Pool &pool; // Pool used to allocate internal memory
PRFileDesc *fp; // File descriptor
SortedTree<DirectoryEntry,DirectoryEntry_Key> dir; // zip file directory
Uint32 nel; // number of directory entries
Uint32 cenoff; // Offset of central directory (CEN)
Uint32 endoff; // Offset of end-of-central-directory record
bool initReader();
bool findEnd();
@ -111,5 +131,4 @@ private:
bool inflateFully(Uint32 size, void *buf, Uint32 len);
};
#endif /* _ZIP_ARCHIVE_H_ */