diff --git a/src/common/FSNodeZIP.cxx b/src/common/FSNodeZIP.cxx index 80cb6c0ac..4ee8b0ae7 100644 --- a/src/common/FSNodeZIP.cxx +++ b/src/common/FSNodeZIP.cxx @@ -21,6 +21,7 @@ //============================================================================ #include "bspf.hxx" +#include "OSystem.hxx" #include "FSNodeFactory.hxx" #include "FSNodeZIP.hxx" @@ -45,54 +46,70 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p) // Not a ZIP file _path = _shortPath = _virtualFile = ""; _isValid = _isDirectory = _isFile = _isVirtual = false; - cerr << "Not a ZIP file\n"; return; } _zipFile = p.substr(0, pos+4); + if(pos+5 < p.length()) + _virtualFile = p.substr(pos+5); - // A ZIP file is, behind the scenes, still a real file in the filesystem - // Hence, we need to create a real filesystem node for it - AbstractFSNode* tmp = FilesystemNodeFactory::create(_zipFile, - FilesystemNodeFactory::SYSTEM); + AbstractFSNode* tmp = FilesystemNodeFactory::create( + _zipFile, FilesystemNodeFactory::SYSTEM); _realNode = Common::SharedPtr(tmp); + + setFlags(_zipFile, _virtualFile, _realNode); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +FilesystemNodeZIP::FilesystemNodeZIP(const string& zipfile, const string& virtualfile, + Common::SharedPtr realnode) +{ + setFlags(zipfile, virtualfile, realnode); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FilesystemNodeZIP::setFlags(const string& zipfile, + const string& virtualfile, + Common::SharedPtr realnode) +{ + _zipFile = zipfile; + _virtualFile = virtualfile; + _realNode = realnode; + _path = _realNode->getPath(); _shortPath = _realNode->getShortPath(); // Is a file component present? - if(pos+5 < p.length()) + if(_virtualFile.size() != 0) { _isVirtual = true; - _virtualFile = p.substr(pos+5); _path += (BSPF_PATH_SEPARATOR + _virtualFile); _shortPath += (BSPF_PATH_SEPARATOR + _virtualFile); } else - { _isVirtual = false; - _virtualFile = ""; - } - -cerr << "FilesystemNodeZIP: " << p << endl - << "path: " << _path << endl - << "spath: " << getShortPath() << endl - << "zipFile: " << _zipFile << endl - << "virtualFile: " << _virtualFile << endl - << endl; + _isDirectory = !_isVirtual; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode, bool hidden) const { -cerr << "getChildren: " << _path << endl; + assert(_isDirectory); // Files within ZIP archives don't contain children if(_isVirtual) return false; - return false; + ZipHandler& zip = OSystem::zip(_path); + while(zip.hasNext()) + { + FilesystemNodeZIP entry(_path, zip.next(), _realNode); + myList.push_back(new FilesystemNodeZIP(entry)); + } + + return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/FSNodeZIP.hxx b/src/common/FSNodeZIP.hxx index 0c8195418..6086e46e7 100644 --- a/src/common/FSNodeZIP.hxx +++ b/src/common/FSNodeZIP.hxx @@ -42,9 +42,8 @@ class FilesystemNodeZIP : public AbstractFSNode /** * Creates a FilesystemNodeZIP for a given path. * - * @param path String with the path the new node should point to. - * @param verify true if the isValid and isDirectory/isFile flags should - * be verified during the construction. + * @param path String with the path the new node should point to. + * @param node Raw pointer to use for the internal FSNode */ FilesystemNodeZIP(const string& path); @@ -67,6 +66,13 @@ class FilesystemNodeZIP : public AbstractFSNode bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const; AbstractFSNode* getParent() const; + private: + FilesystemNodeZIP(const string& zipfile, const string& virtualfile, + Common::SharedPtr realnode); + + void setFlags(const string& zipfile, const string& virtualfile, + Common::SharedPtr realnode); + protected: Common::SharedPtr _realNode; string _zipFile, _virtualFile; diff --git a/src/common/ZipHandler.cxx b/src/common/ZipHandler.cxx new file mode 100644 index 000000000..c8cdc3036 --- /dev/null +++ b/src/common/ZipHandler.cxx @@ -0,0 +1,605 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2013 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id$ +//============================================================================ + +#include "ZipHandler.hxx" + +#include +#include +#include + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +ZipHandler::ZipHandler() + : myZip(NULL) +{ + for (int cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++) + myZipCache[cachenum] = NULL; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +ZipHandler::~ZipHandler() +{ + zip_file_cache_clear(); + free_zip_file(myZip); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void ZipHandler::open(const string& filename) +{ + // Close already open file + if(myZip) + zip_file_close(myZip); + + // And open a new one + zip_file_open(filename.c_str(), &myZip); + reset(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void ZipHandler::reset() +{ + /* reset the position and go from there */ + if(myZip) + myZip->cd_pos = 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool ZipHandler::hasNext() +{ + return myZip && (myZip->cd_pos < myZip->ecd.cd_size); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string ZipHandler::next() +{ + if(myZip) + { + const zip_file_header* header = NULL; + do { + header = zip_file_next_file(myZip); + } + while(header && header->uncompressed_length == 0); + + return header ? header->filename : EmptyString; + } + else + return EmptyString; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool ZipHandler::decompress(uInt8* buffer, uInt32 length) +{ + return myZip && (zip_file_decompress(myZip, buffer, length) == ZIPERR_NONE); +} + +/*------------------------------------------------- + replaces functionality of various osd_xxx + file access functions +-------------------------------------------------*/ +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool ZipHandler::stream_open(const char* filename, fstream** stream, + uInt64& length) +{ + fstream* in = new fstream(filename, fstream::in | fstream::binary); + if(!in || !in->is_open()) + { + *stream = NULL; + length = 0; + return false; + } + else + { + in->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); + *stream = in; + in->seekg(0, ios::end); + length = in->tellg(); + in->seekg(0, ios::beg); + return true; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void ZipHandler::stream_close(fstream** stream) +{ + if(*stream) + { + if((*stream)->is_open()) + (*stream)->close(); + delete *stream; + *stream = NULL; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool ZipHandler::stream_read(fstream* stream, void* buffer, uInt64 offset, + uInt32 length, uInt32& actual) +{ + try + { + stream->seekg(offset); + stream->read((char*)buffer, length); + + actual = stream->gcount(); + return true; + } + catch(...) + { + return false; + } + return false; +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +/*------------------------------------------------- + zip_file_open - opens a ZIP file for reading +-------------------------------------------------*/ +ZipHandler::zip_error ZipHandler::zip_file_open(const char *filename, zip_file **zip) +{ + zip_error ziperr = ZIPERR_NONE; + uInt32 read_length; + zip_file *newzip; + char *string; + int cachenum; + bool success; + + /* ensure we start with a NULL result */ + *zip = NULL; + + /* see if we are in the cache, and reopen if so */ + for (cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++) + { + zip_file *cached = myZipCache[cachenum]; + + /* if we have a valid entry and it matches our filename, use it and remove from the cache */ + if (cached != NULL && cached->filename != NULL && strcmp(filename, cached->filename) == 0) + { + *zip = cached; + myZipCache[cachenum] = NULL; + return ZIPERR_NONE; + } + } + + /* allocate memory for the zip_file structure */ + newzip = (zip_file *)malloc(sizeof(*newzip)); + if (newzip == NULL) + return ZIPERR_OUT_OF_MEMORY; + memset(newzip, 0, sizeof(*newzip)); + + /* open the file */ + if(!stream_open(filename, &newzip->file, newzip->length)) + { + ziperr = ZIPERR_FILE_ERROR; + goto error; + } + + /* read ecd data */ + ziperr = read_ecd(newzip); + if (ziperr != ZIPERR_NONE) + goto error; + + /* verify that we can work with this zipfile (no disk spanning allowed) */ + if (newzip->ecd.disk_number != newzip->ecd.cd_start_disk_number || newzip->ecd.cd_disk_entries != newzip->ecd.cd_total_entries) + { + ziperr = ZIPERR_UNSUPPORTED; + goto error; + } + + /* allocate memory for the central directory */ + newzip->cd = (uInt8 *)malloc(newzip->ecd.cd_size + 1); + if (newzip->cd == NULL) + { + ziperr = ZIPERR_OUT_OF_MEMORY; + goto error; + } + + /* read the central directory */ + success = stream_read(newzip->file, newzip->cd, newzip->ecd.cd_start_disk_offset, newzip->ecd.cd_size, read_length); + if (!success || read_length != newzip->ecd.cd_size) + { + ziperr = success ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR; + goto error; + } + + /* make a copy of the filename for caching purposes */ + string = (char *)malloc(strlen(filename) + 1); + if (string == NULL) + { + ziperr = ZIPERR_OUT_OF_MEMORY; + goto error; + } + + strcpy(string, filename); + newzip->filename = string; + *zip = newzip; + + return ZIPERR_NONE; + +error: + free_zip_file(newzip); + return ziperr; +} + + +/*------------------------------------------------- + zip_file_close - close a ZIP file and add it + to the cache +-------------------------------------------------*/ +void ZipHandler::zip_file_close(zip_file *zip) +{ + int cachenum; + + /* close the open files */ + if (zip->file) + stream_close(&zip->file); + + /* find the first NULL entry in the cache */ + for (cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++) + if (myZipCache[cachenum] == NULL) + break; + + /* if no room left in the cache, free the bottommost entry */ + if (cachenum == ZIP_CACHE_SIZE) + free_zip_file(myZipCache[--cachenum]); + + /* move everyone else down and place us at the top */ + if (cachenum != 0) + memmove(&myZipCache[1], &myZipCache[0], cachenum * sizeof(myZipCache[0])); + myZipCache[0] = zip; +} + + +/*------------------------------------------------- + zip_file_cache_clear - clear the ZIP file + cache and free all memory +-------------------------------------------------*/ +void ZipHandler::zip_file_cache_clear(void) +{ + /* clear call cache entries */ + for (int cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++) + if (myZipCache[cachenum] != NULL) + { +cerr << "free cache: " << myZipCache[cachenum]->filename << endl; + free_zip_file(myZipCache[cachenum]); + myZipCache[cachenum] = NULL; + } +} + + +/*************************************************************************** + CONTAINED FILE ACCESS +***************************************************************************/ + +/*------------------------------------------------- + zip_file_next_entry - return the next entry + in the ZIP +-------------------------------------------------*/ +const ZipHandler::zip_file_header* ZipHandler::zip_file_next_file(zip_file *zip) +{ + /* fix up any modified data */ + if (zip->header.raw != NULL) + { + zip->header.raw[ZIPCFN + zip->header.filename_length] = zip->header.saved; + zip->header.raw = NULL; + } + + /* if we're at or past the end, we're done */ + if (zip->cd_pos >= zip->ecd.cd_size) + return NULL; + + /* extract file header info */ + zip->header.raw = zip->cd + zip->cd_pos; + zip->header.rawlength = ZIPCFN; + zip->header.signature = read_dword(zip->header.raw + ZIPCENSIG); + zip->header.version_created = read_word (zip->header.raw + ZIPCVER); + zip->header.version_needed = read_word (zip->header.raw + ZIPCVXT); + zip->header.bit_flag = read_word (zip->header.raw + ZIPCFLG); + zip->header.compression = read_word (zip->header.raw + ZIPCMTHD); + zip->header.file_time = read_word (zip->header.raw + ZIPCTIM); + zip->header.file_date = read_word (zip->header.raw + ZIPCDAT); + zip->header.crc = read_dword(zip->header.raw + ZIPCCRC); + zip->header.compressed_length = read_dword(zip->header.raw + ZIPCSIZ); + zip->header.uncompressed_length = read_dword(zip->header.raw + ZIPCUNC); + zip->header.filename_length = read_word (zip->header.raw + ZIPCFNL); + zip->header.extra_field_length = read_word (zip->header.raw + ZIPCXTL); + zip->header.file_comment_length = read_word (zip->header.raw + ZIPCCML); + zip->header.start_disk_number = read_word (zip->header.raw + ZIPDSK); + zip->header.internal_attributes = read_word (zip->header.raw + ZIPINT); + zip->header.external_attributes = read_dword(zip->header.raw + ZIPEXT); + zip->header.local_header_offset = read_dword(zip->header.raw + ZIPOFST); + zip->header.filename = (char *)zip->header.raw + ZIPCFN; + + /* make sure we have enough data */ + zip->header.rawlength += zip->header.filename_length; + zip->header.rawlength += zip->header.extra_field_length; + zip->header.rawlength += zip->header.file_comment_length; + if (zip->cd_pos + zip->header.rawlength > zip->ecd.cd_size) + return NULL; + + /* NULL terminate the filename */ + zip->header.saved = zip->header.raw[ZIPCFN + zip->header.filename_length]; + zip->header.raw[ZIPCFN + zip->header.filename_length] = 0; + + /* advance the position */ + zip->cd_pos += zip->header.rawlength; + return &zip->header; +} + +/*------------------------------------------------- + zip_file_decompress - decompress a file + from a ZIP into the target buffer +-------------------------------------------------*/ +ZipHandler::zip_error ZipHandler::zip_file_decompress(zip_file *zip, void *buffer, uInt32 length) +{ + zip_error ziperr; + uInt64 offset; + + /* if we don't have enough buffer, error */ + if (length < zip->header.uncompressed_length) + return ZIPERR_BUFFER_TOO_SMALL; + + /* make sure the info in the header aligns with what we know */ + if (zip->header.start_disk_number != zip->ecd.disk_number) + return ZIPERR_UNSUPPORTED; + + /* get the compressed data offset */ + ziperr = get_compressed_data_offset(zip, &offset); + if (ziperr != ZIPERR_NONE) + return ziperr; + + /* handle compression types */ + switch (zip->header.compression) + { + case 0: + ziperr = decompress_data_type_0(zip, offset, buffer, length); + break; + + case 8: + ziperr = decompress_data_type_8(zip, offset, buffer, length); + break; + + default: + ziperr = ZIPERR_UNSUPPORTED; + break; + } + return ziperr; +} + +/*************************************************************************** + CACHE MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + free_zip_file - free all the data for a + zip_file +-------------------------------------------------*/ +void ZipHandler::free_zip_file(zip_file *zip) +{ + if (zip != NULL) + { +if (zip->file) cerr << "free: " << zip->filename << endl; + if (zip->file) + stream_close(&zip->file); + if (zip->filename != NULL) + free((void *)zip->filename); + if (zip->ecd.raw != NULL) + free(zip->ecd.raw); + if (zip->cd != NULL) + free(zip->cd); + free(zip); + } +} + +/*************************************************************************** + ZIP FILE PARSING +***************************************************************************/ + +/*------------------------------------------------- + read_ecd - read the ECD data +-------------------------------------------------*/ + +ZipHandler::zip_error ZipHandler::read_ecd(zip_file *zip) +{ + uInt32 buflen = 1024; + uInt8 *buffer; + + /* we may need multiple tries */ + while (buflen < 65536) + { + uInt32 read_length; + Int32 offset; + + /* max out the buffer length at the size of the file */ + if (buflen > zip->length) + buflen = zip->length; + + /* allocate buffer */ + buffer = (uInt8 *)malloc(buflen + 1); + if (buffer == NULL) + return ZIPERR_OUT_OF_MEMORY; + + /* read in one buffers' worth of data */ + bool success = stream_read(zip->file, buffer, zip->length - buflen, buflen, read_length); + if (!success || read_length != buflen) + { + free(buffer); + return ZIPERR_FILE_ERROR; + } + + /* find the ECD signature */ + for (offset = buflen - 22; offset >= 0; offset--) + if (buffer[offset + 0] == 'P' && buffer[offset + 1] == 'K' && buffer[offset + 2] == 0x05 && buffer[offset + 3] == 0x06) + break; + + /* if we found it, fill out the data */ + if (offset >= 0) + { + /* reuse the buffer as our ECD buffer */ + zip->ecd.raw = buffer; + zip->ecd.rawlength = buflen - offset; + + /* append a NULL terminator to the comment */ + memmove(&buffer[0], &buffer[offset], zip->ecd.rawlength); + zip->ecd.raw[zip->ecd.rawlength] = 0; + + /* extract ecd info */ + zip->ecd.signature = read_dword(zip->ecd.raw + ZIPESIG); + zip->ecd.disk_number = read_word (zip->ecd.raw + ZIPEDSK); + zip->ecd.cd_start_disk_number = read_word (zip->ecd.raw + ZIPECEN); + zip->ecd.cd_disk_entries = read_word (zip->ecd.raw + ZIPENUM); + zip->ecd.cd_total_entries = read_word (zip->ecd.raw + ZIPECENN); + zip->ecd.cd_size = read_dword(zip->ecd.raw + ZIPECSZ); + zip->ecd.cd_start_disk_offset = read_dword(zip->ecd.raw + ZIPEOFST); + zip->ecd.comment_length = read_word (zip->ecd.raw + ZIPECOML); + zip->ecd.comment = (const char *)(zip->ecd.raw + ZIPECOM); + return ZIPERR_NONE; + } + + /* didn't find it; free this buffer and expand our search */ + free(buffer); + if (buflen < zip->length) + buflen *= 2; + else + return ZIPERR_BAD_SIGNATURE; + } + return ZIPERR_OUT_OF_MEMORY; +} + +/*------------------------------------------------- + get_compressed_data_offset - return the + offset of the compressed data +-------------------------------------------------*/ +ZipHandler::zip_error ZipHandler::get_compressed_data_offset(zip_file *zip, uInt64 *offset) +{ + uInt32 read_length; + + /* make sure the file handle is open */ + if (zip->file == NULL && !stream_open(zip->filename, &zip->file, zip->length)) + return ZIPERR_FILE_ERROR; + + /* now go read the fixed-sized part of the local file header */ + bool success = stream_read(zip->file, zip->buffer, zip->header.local_header_offset, ZIPNAME, read_length); + if (!success || read_length != ZIPNAME) + return success ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR; + + /* compute the final offset */ + *offset = zip->header.local_header_offset + ZIPNAME; + *offset += read_word(zip->buffer + ZIPFNLN); + *offset += read_word(zip->buffer + ZIPXTRALN); + + return ZIPERR_NONE; +} + +/*************************************************************************** + DECOMPRESSION INTERFACES +***************************************************************************/ + +/*------------------------------------------------- + decompress_data_type_0 - "decompress" + type 0 data (which is uncompressed) +-------------------------------------------------*/ +ZipHandler::zip_error ZipHandler::decompress_data_type_0(zip_file *zip, uInt64 offset, void *buffer, uInt32 length) +{ + uInt32 read_length; + + /* the data is uncompressed; just read it */ + bool success = stream_read(zip->file, buffer, offset, zip->header.compressed_length, read_length); + if (!success) + return ZIPERR_FILE_ERROR; + else if (read_length != zip->header.compressed_length) + return ZIPERR_FILE_TRUNCATED; + else + return ZIPERR_NONE; +} + +/*------------------------------------------------- + decompress_data_type_8 - decompress + type 8 data (which is deflated) +-------------------------------------------------*/ +ZipHandler::zip_error ZipHandler::decompress_data_type_8(zip_file *zip, uInt64 offset, void *buffer, uInt32 length) +{ + uInt32 input_remaining = zip->header.compressed_length; + uInt32 read_length; + z_stream stream; + int zerr; + + /* make sure we don't need a newer mechanism */ + if (zip->header.version_needed > 0x14) + return ZIPERR_UNSUPPORTED; + + /* reset the stream */ + memset(&stream, 0, sizeof(stream)); + stream.next_out = (Bytef *)buffer; + stream.avail_out = length; + + /* initialize the decompressor */ + zerr = inflateInit2(&stream, -MAX_WBITS); + if (zerr != Z_OK) + return ZIPERR_DECOMPRESS_ERROR; + + /* loop until we're done */ + while (1) + { + /* read in the next chunk of data */ + bool success = stream_read(zip->file, zip->buffer, offset, BSPF_min(input_remaining, (uInt32)sizeof(zip->buffer)), read_length); + if (!success) + { + inflateEnd(&stream); + return ZIPERR_FILE_ERROR; + } + offset += read_length; + + /* if we read nothing, but still have data left, the file is truncated */ + if (read_length == 0 && input_remaining > 0) + { + inflateEnd(&stream); + return ZIPERR_FILE_TRUNCATED; + } + + /* fill out the input data */ + stream.next_in = zip->buffer; + stream.avail_in = read_length; + input_remaining -= read_length; + + /* add a dummy byte at end of compressed data */ + if (input_remaining == 0) + stream.avail_in++; + + /* now inflate */ + zerr = inflate(&stream, Z_NO_FLUSH); + if (zerr == Z_STREAM_END) + break; + if (zerr != Z_OK) + { + inflateEnd(&stream); + return ZIPERR_DECOMPRESS_ERROR; + } + } + + /* finish decompression */ + zerr = inflateEnd(&stream); + if (zerr != Z_OK) + return ZIPERR_DECOMPRESS_ERROR; + + /* if anything looks funny, report an error */ + if (stream.avail_out > 0 || input_remaining > 0) + return ZIPERR_DECOMPRESS_ERROR; + + return ZIPERR_NONE; +} diff --git a/src/common/ZipHandler.hxx b/src/common/ZipHandler.hxx new file mode 100644 index 000000000..c37560a06 --- /dev/null +++ b/src/common/ZipHandler.hxx @@ -0,0 +1,264 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2013 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id$ +//============================================================================ + +#ifndef ZIP_HANDLER_HXX +#define ZIP_HANDLER_HXX + +#include +#include "bspf.hxx" + +/*************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#define ZIP_DECOMPRESS_BUFSIZE 16384 + +/** + This class implements a thin wrapper around the zip file management code + from the MAME project. + + @author Wrapper class by Stephen Anthony, with main functionality + by Aaron Giles +*/ +class ZipHandler +{ + public: + ZipHandler(); + virtual ~ZipHandler(); + + // Open ZIP file for processing + void open(const string& filename); + + // The following form an iterator for processing the filenames in the ZIP file + void reset(); // Reset iterator to first file + bool hasNext(); // Answer whether there are more files present + string next(); // Get next file + + // Decompress the currently selected file, return false on any errors + bool decompress(uInt8* buffer, uInt32 length); + + private: + // Replaces functionaity of various osd_xxxx functions + static bool stream_open(const char* filename, fstream** stream, uInt64& length); + static void stream_close(fstream** stream); + static bool stream_read(fstream* stream, void* buffer, uInt64 offset, uInt32 length, uInt32& actual); + + /* Error types */ + enum zip_error + { + ZIPERR_NONE = 0, + ZIPERR_OUT_OF_MEMORY, + ZIPERR_FILE_ERROR, + ZIPERR_BAD_SIGNATURE, + ZIPERR_DECOMPRESS_ERROR, + ZIPERR_FILE_TRUNCATED, + ZIPERR_FILE_CORRUPT, + ZIPERR_UNSUPPORTED, + ZIPERR_BUFFER_TOO_SMALL + }; + + /* contains extracted file header information */ + struct zip_file_header + { + uInt32 signature; /* central file header signature */ + uInt16 version_created; /* version made by */ + uInt16 version_needed; /* version needed to extract */ + uInt16 bit_flag; /* general purpose bit flag */ + uInt16 compression; /* compression method */ + uInt16 file_time; /* last mod file time */ + uInt16 file_date; /* last mod file date */ + uInt32 crc; /* crc-32 */ + uInt32 compressed_length; /* compressed size */ + uInt32 uncompressed_length; /* uncompressed size */ + uInt16 filename_length; /* filename length */ + uInt16 extra_field_length; /* extra field length */ + uInt16 file_comment_length; /* file comment length */ + uInt16 start_disk_number; /* disk number start */ + uInt16 internal_attributes; /* internal file attributes */ + uInt32 external_attributes; /* external file attributes */ + uInt32 local_header_offset; /* relative offset of local header */ + const char* filename; /* filename */ + + uInt8* raw; /* pointer to the raw data */ + uInt32 rawlength; /* length of the raw data */ + uInt8 saved; /* saved byte from after filename */ + }; + + /* contains extracted end of central directory information */ + struct zip_ecd + { + uInt32 signature; /* end of central dir signature */ + uInt16 disk_number; /* number of this disk */ + uInt16 cd_start_disk_number; /* number of the disk with the start of the central directory */ + uInt16 cd_disk_entries; /* total number of entries in the central directory on this disk */ + uInt16 cd_total_entries; /* total number of entries in the central directory */ + uInt32 cd_size; /* size of the central directory */ + uInt32 cd_start_disk_offset; /* offset of start of central directory with respect to the starting disk number */ + uInt16 comment_length; /* .ZIP file comment length */ + const char* comment; /* .ZIP file comment */ + + uInt8* raw; /* pointer to the raw data */ + uInt32 rawlength; /* length of the raw data */ + }; + + /* describes an open ZIP file */ + struct zip_file + { + const char* filename; /* copy of ZIP filename (for caching) */ + fstream* file; /* C++ fstream file handle */ + uInt64 length; /* length of zip file */ + + zip_ecd ecd; /* end of central directory */ + + uInt8* cd; /* central directory raw data */ + uInt32 cd_pos; /* position in central directory */ + zip_file_header header; /* current file header */ + + uInt8 buffer[ZIP_DECOMPRESS_BUFSIZE]; /* buffer for decompression */ + }; + + enum { + /* number of open files to cache */ + ZIP_CACHE_SIZE = 8, + + /* offsets in end of central directory structure */ + ZIPESIG = 0x00, + ZIPEDSK = 0x04, + ZIPECEN = 0x06, + ZIPENUM = 0x08, + ZIPECENN = 0x0a, + ZIPECSZ = 0x0c, + ZIPEOFST = 0x10, + ZIPECOML = 0x14, + ZIPECOM = 0x16, + + /* offsets in central directory entry structure */ + ZIPCENSIG = 0x00, + ZIPCVER = 0x04, + ZIPCOS = 0x05, + ZIPCVXT = 0x06, + ZIPCEXOS = 0x07, + ZIPCFLG = 0x08, + ZIPCMTHD = 0x0a, + ZIPCTIM = 0x0c, + ZIPCDAT = 0x0e, + ZIPCCRC = 0x10, + ZIPCSIZ = 0x14, + ZIPCUNC = 0x18, + ZIPCFNL = 0x1c, + ZIPCXTL = 0x1e, + ZIPCCML = 0x20, + ZIPDSK = 0x22, + ZIPINT = 0x24, + ZIPEXT = 0x26, + ZIPOFST = 0x2a, + ZIPCFN = 0x2e, + + /* offsets in local file header structure */ + ZIPLOCSIG = 0x00, + ZIPVER = 0x04, + ZIPGENFLG = 0x06, + ZIPMTHD = 0x08, + ZIPTIME = 0x0a, + ZIPDATE = 0x0c, + ZIPCRC = 0x0e, + ZIPSIZE = 0x12, + ZIPUNCMP = 0x16, + ZIPFNLN = 0x1a, + ZIPXTRALN = 0x1c, + ZIPNAME = 0x1e + }; + + private: + /* ----- ZIP file access ----- */ + + /* open a ZIP file and parse its central directory */ + zip_error zip_file_open(const char *filename, zip_file **zip); + + /* close a ZIP file (may actually be left open due to caching) */ + void zip_file_close(zip_file *zip); + + /* clear out all open ZIP files from the cache */ + void zip_file_cache_clear(void); + + + /* ----- contained file access ----- */ + + /* find the next file in the ZIP */ + const zip_file_header *zip_file_next_file(zip_file *zip); + + /* decompress the most recently found file in the ZIP */ + zip_error zip_file_decompress(zip_file *zip, void *buffer, uInt32 length); + + inline static uInt16 read_word(uInt8* buf) + { + return (buf[1] << 8) | buf[0]; + } + + inline static uInt32 read_dword(uInt8* buf) + { + return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + } + + /* cache management */ + static void free_zip_file(zip_file *zip); + + /* ZIP file parsing */ + static zip_error read_ecd(zip_file *zip); + static zip_error get_compressed_data_offset(zip_file *zip, uInt64 *offset); + + /* decompression interfaces */ + static zip_error decompress_data_type_0(zip_file *zip, uInt64 offset, void *buffer, uInt32 length); + static zip_error decompress_data_type_8(zip_file *zip, uInt64 offset, void *buffer, uInt32 length); + + private: + zip_file* myZip; + zip_file* myZipCache[ZIP_CACHE_SIZE]; +}; + +#endif /* ZIP_HANDLER_HXX */ diff --git a/src/common/module.mk b/src/common/module.mk index ecd4758e1..5778312f0 100644 --- a/src/common/module.mk +++ b/src/common/module.mk @@ -10,7 +10,8 @@ MODULE_OBJS := \ src/common/FSNodeZIP.o \ src/common/PNGLibrary.o \ src/common/MouseControl.o \ - src/common/RectList.o + src/common/RectList.o \ + src/common/ZipHandler.o MODULE_DIRS += \ src/common diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index f3258f5f8..8931f889c 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -50,7 +50,6 @@ #endif #include "FSNode.hxx" -#include "unzip.h" #include "MD5.hxx" #include "Cart.hxx" #include "Settings.hxx" @@ -198,6 +197,7 @@ OSystem::~OSystem() delete mySerialPort; delete myPNGLib; + delete myZipHandler; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -309,6 +309,9 @@ bool OSystem::create() // Create PNG handler myPNGLib = new PNGLibrary(); + // Create ZIP handler + myZipHandler = new ZipHandler(); + return true; } @@ -829,6 +832,8 @@ uInt8* OSystem::openROM(string file, string& md5, uInt32& size) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool OSystem::loadFromZIP(const string& filename, uInt8** image, uInt32& size) { +return false; +#if 0 // FIXME // First determine if this actually is a ZIP file // by seeing if it contains the '.zip' extension size_t extpos = BSPF_findIgnoreCase(filename, ".zip"); @@ -913,6 +918,7 @@ bool OSystem::loadFromZIP(const string& filename, uInt8** image, uInt32& size) } } return false; +#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1247,3 +1253,6 @@ OSystem& OSystem::operator = (const OSystem&) assert(false); return *this; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +ZipHandler* OSystem::myZipHandler = 0; diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index 1c877d451..c4276d1d5 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -42,6 +42,7 @@ namespace GUI { #include "Array.hxx" #include "FrameBuffer.hxx" #include "PNGLibrary.hxx" +#include "ZipHandler.hxx" #include "bspf.hxx" struct Resolution { @@ -180,6 +181,17 @@ class OSystem */ PNGLibrary& png() const { return *myPNGLib; } + /** + Get the ZIP handler of the system. + + @return The ZIP object, using the given file + */ + static ZipHandler& zip(const string& file) + { + myZipHandler->open(file); + return *myZipHandler; + } + /** This method should be called to load the current settings from an rc file. It first loads the settings from the config file, then informs subsystems @@ -589,6 +601,9 @@ class OSystem // Indicates whether to stop the main loop bool myQuitLoop; + // ZIP static reference variable responsible for accessing ZIP files + static ZipHandler* myZipHandler; + private: enum { kNumUIPalettes = 2 }; string myBaseDir; diff --git a/src/emucore/module.mk b/src/emucore/module.mk index 2433be693..aa2d41e77 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -66,7 +66,6 @@ MODULE_OBJS := \ src/emucore/TIASnd.o \ src/emucore/TIATables.o \ src/emucore/TrackBall.o \ - src/emucore/unzip.o \ src/emucore/Thumbulator.o MODULE_DIRS += \ diff --git a/src/emucore/unzip.c b/src/emucore/unzip.c deleted file mode 100644 index 405191d43..000000000 --- a/src/emucore/unzip.c +++ /dev/null @@ -1,1273 +0,0 @@ -/* unzip.c -- IO on .zip files using zlib - Version 0.15 beta, Mar 19th, 1998, - - Read unzip.h for more info -*/ - - -#include -#include -#include -#include - -#include "unzip.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - - - -#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ - !defined(CASESENSITIVITYDEFAULT_NO) -#define CASESENSITIVITYDEFAULT_NO -#endif - - -#ifndef UNZ_BUFSIZE -#define UNZ_BUFSIZE (16384) -#endif - -#ifndef UNZ_MAXFILENAMEINZIP -#define UNZ_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) - - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -const char unz_copyright[] = - " unzip 0.15 Copyright 1998 Gilles Vollant "; - -/* unz_file_info_interntal contain internal info about a file in zipfile*/ -typedef struct unz_file_info_internal_s -{ - uLong offset_curfile;/* relative offset of local header 4 bytes */ -} unz_file_info_internal; - - -/* file_in_zip_read_info_s contain internal information about a file in zipfile, - when reading and decompress it */ -typedef struct -{ - char *read_buffer; /* internal buffer for compressed data */ - z_stream stream; /* zLib stream structure for inflate */ - - uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ - uLong stream_initialised; /* flag set if stream structure is initialised*/ - - uLong offset_local_extrafield;/* offset of the local extra field */ - uInt size_local_extrafield;/* size of the local extra field */ - uLong pos_local_extrafield; /* position in the local extra field in read*/ - - uLong crc32; /* crc32 of all data uncompressed */ - uLong crc32_wait; /* crc32 we must obtain after decompress all */ - uLong rest_read_compressed; /* number of byte to be decompressed */ - uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ - FILE* file; /* io structore of the zipfile */ - uLong compression_method; /* compression method (0==store) */ - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ -} file_in_zip_read_info_s; - - -/* unz_s contain internal information about the zipfile -*/ -typedef struct -{ - FILE* file; /* io structore of the zipfile */ - unz_global_info gi; /* public global information */ - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - uLong num_file; /* number of the current file in the zipfile*/ - uLong pos_in_central_dir; /* pos of the current file in the central dir*/ - uLong current_file_ok; /* flag about the usability of the current file*/ - uLong central_pos; /* position of the beginning of the central dir*/ - - uLong size_central_dir; /* size of the central directory */ - uLong offset_central_dir; /* offset of start of central directory with - respect to the starting disk number */ - - unz_file_info cur_file_info; /* public info about the current file in zip*/ - unz_file_info_internal cur_file_info_internal; /* private info about it*/ - file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current - file if we are decompressing it */ -} unz_s; - - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ - - -local int unzlocal_getByte(FILE* fin, int* pi) -{ - unsigned char c; - int err = fread(&c, 1, 1, fin); - if (err==1) - { - *pi = (int)c; - return UNZ_OK; - } - else - { - if (ferror(fin)) - return UNZ_ERRNO; - else - return UNZ_EOF; - } -} - - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int unzlocal_getShort (FILE* fin,uLong* pX) -{ - uLong x ; - int i = 0; - int err; - - err = unzlocal_getByte(fin,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int unzlocal_getLong (FILE* fin,uLong* pX) -{ - uLong x ; - int i = 0; - int err; - - err = unzlocal_getByte(fin,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<16; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<24; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - - -/* My own strcmpi / strcasecmp */ -local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) -{ - for (;;) - { - char c1=*(fileName1++); - char c2=*(fileName2++); - if ((c1>='a') && (c1<='z')) - c1 -= 0x20; - if ((c2>='a') && (c2<='z')) - c2 -= 0x20; - if (c1=='\0') - return ((c2=='\0') ? 0 : -1); - if (c2=='\0') - return 1; - if (c1c2) - return 1; - } -} - - -#ifdef CASESENSITIVITYDEFAULT_NO -#define CASESENSITIVITYDEFAULTVALUE 2 -#else -#define CASESENSITIVITYDEFAULTVALUE 1 -#endif - -#ifndef STRCMPCASENOSENTIVEFUNCTION -#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal -#endif - -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) - -*/ -extern int ZEXPORT unzStringFileNameCompare - (const char* fileName1, const char* fileName2, int iCaseSensitivity) -{ - if (iCaseSensitivity==0) - iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; - - if (iCaseSensitivity==1) - return strcmp(fileName1,fileName2); - - return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); -} - -#define BUFREADCOMMENT (0x400) - -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local uLong unzlocal_SearchCentralDir(FILE* fin) -{ - unsigned char* buf; - uLong uSizeFile; - uLong uBackRead; - uLong uMaxBack=0xffff; /* maximum size of global comment */ - uLong uPosFound=0; - - if (fseek(fin,0,SEEK_END) != 0) - return 0; - - - uSizeFile = ftell( fin ); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - if (fseek(fin,uReadPos,SEEK_SET)!=0) - break; - - if (fread(buf,(uInt)uReadSize,1,fin)!=1) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} - -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer - "zlib/zlib109.zip". - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ -extern unzFile ZEXPORT unzOpen(const char *path) -{ - unz_s us; - unz_s *s; - uLong central_pos,uL; - FILE * fin ; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - uLong number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - - int err=UNZ_OK; - - if (unz_copyright[0]!=' ') - return NULL; - - fin=fopen(path,"rb"); - if (fin==NULL) - return NULL; - - central_pos = unzlocal_SearchCentralDir(fin); - if (central_pos==0) - err=UNZ_ERRNO; - - if (fseek(fin,central_pos,SEEK_SET)!=0) - err=UNZ_ERRNO; - - /* the signature, already checked */ - if (unzlocal_getLong(fin,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of this disk */ - if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of the disk with the start of the central directory */ - if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir */ - if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((number_entry_CD!=us.gi.number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=UNZ_BADZIPFILE; - - /* size of the central directory */ - if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* zipfile comment length */ - if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((central_pospfile_in_zip_read!=NULL) - unzCloseCurrentFile(file); - - fclose(s->file); - TRYFREE(s); - return UNZ_OK; -} - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info) -{ - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - *pglobal_info=s->gi; - return UNZ_OK; -} - - -/* - Translate date/time from Dos format to tm_unz (readable more easilty) -*/ -local void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) -{ - uLong uDate; - uDate = (uLong)(ulDosDate>>16); - ptm->tm_mday = (uInt)(uDate&0x1f) ; - ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; - ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; - - ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); - ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; - ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; -} - -/* - Get Info about the current file in the zipfile, with internal only info -*/ -local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, - unz_file_info *pfile_info, - unz_file_info_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); - -local int unzlocal_GetCurrentFileInfoInternal - ( unzFile file, - unz_file_info *pfile_info, - unz_file_info_internal *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize) -{ - unz_s* s; - unz_file_info file_info; - unz_file_info_internal file_info_internal; - int err=UNZ_OK; - uLong uMagic; - long lSeek=0; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) - err=UNZ_ERRNO; - - - /* we check the magic */ - if (err==UNZ_OK) - { - if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x02014b50) - err=UNZ_BADZIPFILE; - } - - if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) - err=UNZ_ERRNO; - - unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); - - if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) - err=UNZ_ERRNO; - - lSeek+=file_info.size_filename; - if ((err==UNZ_OK) && (szFileName!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_filename0) && (fileNameBufferSize>0)) - if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek -= uSizeRead; - } - - - if ((err==UNZ_OK) && (extraField!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - } - if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) - if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek += file_info.size_file_extra - uSizeRead; - } - else - lSeek+=file_info.size_file_extra; - - - if ((err==UNZ_OK) && (szComment!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - } - if ((file_info.size_file_comment>0) && (commentBufferSize>0)) - if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek+=file_info.size_file_comment - uSizeRead; - } - else - lSeek+=file_info.size_file_comment; - - if ((err==UNZ_OK) && (pfile_info!=NULL)) - *pfile_info=file_info; - - if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) - *pfile_info_internal=file_info_internal; - - return err; -} - - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. -*/ -extern int ZEXPORT unzGetCurrentFileInfo - ( unzFile file, - unz_file_info *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize - ) -{ - return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize); -} - -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ -extern int ZEXPORT unzGoToFirstFile (unzFile file) -{ - int err=UNZ_OK; - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - s->pos_in_central_dir=s->offset_central_dir; - s->num_file=0; - err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ -extern int ZEXPORT unzGoToNextFile (unzFile file) -{ - unz_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - if (s->num_file+1==s->gi.number_entry) - return UNZ_END_OF_LIST_OF_FILE; - - s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + - s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; - s->num_file++; - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzipStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ -extern int ZEXPORT unzLocateFile - ( unzFile file, - const char *szFileName, - int iCaseSensitivity - ) -{ - unz_s* s; - int err; - - - uLong num_fileSaved; - uLong pos_in_central_dirSaved; - - - if (file==NULL) - return UNZ_PARAMERROR; - - if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) - return UNZ_PARAMERROR; - - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - num_fileSaved = s->num_file; - pos_in_central_dirSaved = s->pos_in_central_dir; - - err = unzGoToFirstFile(file); - - while (err == UNZ_OK) - { - char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; - unzGetCurrentFileInfo(file,NULL, - szCurrentFileName,sizeof(szCurrentFileName)-1, - NULL,0,NULL,0); - if (unzStringFileNameCompare(szCurrentFileName, - szFileName,iCaseSensitivity)==0) - return UNZ_OK; - err = unzGoToNextFile(file); - } - - s->num_file = num_fileSaved ; - s->pos_in_central_dir = pos_in_central_dirSaved ; - return err; -} - - -/* - Read the local header of the current zipfile - Check the coherency of the local header and info in the end of central - directory about this file - store in *piSizeVar the size of extra info in local header - (filename and size of extra field data) -*/ -local int unzlocal_CheckCurrentFileCoherencyHeader - ( unz_s* s, - uInt* piSizeVar, - uLong *poffset_local_extrafield, - uInt *psize_local_extrafield - ) -{ - uLong uMagic,uData,uFlags; - uLong size_filename; - uLong size_extra_field; - int err=UNZ_OK; - - *piSizeVar = 0; - *poffset_local_extrafield = 0; - *psize_local_extrafield = 0; - - if (fseek(s->file,s->cur_file_info_internal.offset_curfile + - s->byte_before_the_zipfile,SEEK_SET)!=0) - return UNZ_ERRNO; - - - if (err==UNZ_OK) - { - if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x04034b50) - err=UNZ_BADZIPFILE; - } - - if (unzlocal_getShort(s->file,&uData) != UNZ_OK) - err=UNZ_ERRNO; -/* - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) - err=UNZ_BADZIPFILE; -*/ - if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&uData) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) - err=UNZ_BADZIPFILE; - - if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - - if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) - err=UNZ_BADZIPFILE; - - *piSizeVar += (uInt)size_filename; - - if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) - err=UNZ_ERRNO; - *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + - SIZEZIPLOCALHEADER + size_filename; - *psize_local_extrafield = (uInt)size_extra_field; - - *piSizeVar += (uInt)size_extra_field; - - return err; -} - -/* - Open for reading data the current file in the zipfile. - If there is no error and the file is opened, the return value is UNZ_OK. -*/ -extern int ZEXPORT unzOpenCurrentFile (unzFile file) -{ - int err=UNZ_OK; - int Store; - uInt iSizeVar; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uLong offset_local_extrafield; /* offset of the local extra field */ - uInt size_local_extrafield; /* size of the local extra field */ - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_PARAMERROR; - - if (s->pfile_in_zip_read != NULL) - unzCloseCurrentFile(file); - - if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, - &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) - return UNZ_BADZIPFILE; - - pfile_in_zip_read_info = (file_in_zip_read_info_s*) - ALLOC(sizeof(file_in_zip_read_info_s)); - if (pfile_in_zip_read_info==NULL) - return UNZ_INTERNALERROR; - - pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); - pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; - pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; - pfile_in_zip_read_info->pos_local_extrafield=0; - - if (pfile_in_zip_read_info->read_buffer==NULL) - { - TRYFREE(pfile_in_zip_read_info); - return UNZ_INTERNALERROR; - } - - pfile_in_zip_read_info->stream_initialised=0; - - if ((s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - Store = s->cur_file_info.compression_method==0; - - pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; - pfile_in_zip_read_info->crc32=0; - pfile_in_zip_read_info->compression_method = - s->cur_file_info.compression_method; - pfile_in_zip_read_info->file=s->file; - pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; - - pfile_in_zip_read_info->stream.total_out = 0; - - if (!Store) - { - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidpf)0; - - err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised=1; - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. - * In unzip, i don't wait absolutely Z_STREAM_END because I known the - * size of both compressed and uncompressed data - */ - } - pfile_in_zip_read_info->rest_read_compressed = - s->cur_file_info.compressed_size ; - pfile_in_zip_read_info->rest_read_uncompressed = - s->cur_file_info.uncompressed_size ; - - - pfile_in_zip_read_info->pos_in_zipfile = - s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + - iSizeVar; - - pfile_in_zip_read_info->stream.avail_in = (uInt)0; - - - s->pfile_in_zip_read = pfile_in_zip_read_info; - return UNZ_OK; -} - - -/* - Read bytes from the current file. - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ -extern int ZEXPORT unzReadCurrentFile - ( unzFile file, - voidp buf, - unsigned len - ) -{ - int err=UNZ_OK; - uInt iRead = 0; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if (pfile_in_zip_read_info->read_buffer == NULL) - return UNZ_END_OF_LIST_OF_FILE; - if (len==0) - return 0; - - pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; - - pfile_in_zip_read_info->stream.avail_out = (uInt)len; - - if (len>pfile_in_zip_read_info->rest_read_uncompressed) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_uncompressed; - - while (pfile_in_zip_read_info->stream.avail_out>0) - { - if ((pfile_in_zip_read_info->stream.avail_in==0) && - (pfile_in_zip_read_info->rest_read_compressed>0)) - { - uInt uReadThis = UNZ_BUFSIZE; - if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; - if (uReadThis == 0) - return UNZ_EOF; - if (fseek(pfile_in_zip_read_info->file, - pfile_in_zip_read_info->pos_in_zipfile + - pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) - return UNZ_ERRNO; - if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, - pfile_in_zip_read_info->file)!=1) - return UNZ_ERRNO; - pfile_in_zip_read_info->pos_in_zipfile += uReadThis; - - pfile_in_zip_read_info->rest_read_compressed-=uReadThis; - - pfile_in_zip_read_info->stream.next_in = - (Bytef*)pfile_in_zip_read_info->read_buffer; - pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; - } - - if (pfile_in_zip_read_info->compression_method==0) - { - uInt uDoCopy,i ; - if (pfile_in_zip_read_info->stream.avail_out < - pfile_in_zip_read_info->stream.avail_in) - uDoCopy = pfile_in_zip_read_info->stream.avail_out ; - else - uDoCopy = pfile_in_zip_read_info->stream.avail_in ; - - for (i=0;istream.next_out+i) = - *(pfile_in_zip_read_info->stream.next_in+i); - - pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, - pfile_in_zip_read_info->stream.next_out, - uDoCopy); - pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; - pfile_in_zip_read_info->stream.avail_in -= uDoCopy; - pfile_in_zip_read_info->stream.avail_out -= uDoCopy; - pfile_in_zip_read_info->stream.next_out += uDoCopy; - pfile_in_zip_read_info->stream.next_in += uDoCopy; - pfile_in_zip_read_info->stream.total_out += uDoCopy; - iRead += uDoCopy; - } - else - { - uLong uTotalOutBefore,uTotalOutAfter; - const Bytef *bufBefore; - uLong uOutThis; - int flush=Z_SYNC_FLUSH; - - uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; - bufBefore = pfile_in_zip_read_info->stream.next_out; - - /* - if ((pfile_in_zip_read_info->rest_read_uncompressed == - pfile_in_zip_read_info->stream.avail_out) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - flush = Z_FINISH; - */ - err=inflate(&pfile_in_zip_read_info->stream,flush); - - uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; - uOutThis = uTotalOutAfter-uTotalOutBefore; - - pfile_in_zip_read_info->crc32 = - crc32(pfile_in_zip_read_info->crc32,bufBefore, - (uInt)(uOutThis)); - - pfile_in_zip_read_info->rest_read_uncompressed -= - uOutThis; - - iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); - - if (err==Z_STREAM_END) - return (iRead==0) ? UNZ_EOF : iRead; - if (err!=Z_OK) - break; - } - } - - if (err==Z_OK) - return iRead; - return err; -} - - -/* - Give the current position in uncompressed data -*/ -extern z_off_t ZEXPORT unztell (unzFile file) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - return (z_off_t)pfile_in_zip_read_info->stream.total_out; -} - - -/* - return 1 if the end of file was reached, 0 elsewhere -*/ -extern int ZEXPORT unzeof (unzFile file) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - return 1; - else - return 0; -} - - - -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field that can be read - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ -extern int ZEXPORT unzGetLocalExtrafield - ( unzFile file, - voidp buf, - unsigned len - ) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uInt read_now; - uLong size_to_read; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - size_to_read = (pfile_in_zip_read_info->size_local_extrafield - - pfile_in_zip_read_info->pos_local_extrafield); - - if (buf==NULL) - return (int)size_to_read; - - if (len>size_to_read) - read_now = (uInt)size_to_read; - else - read_now = (uInt)len ; - - if (read_now==0) - return 0; - - if (fseek(pfile_in_zip_read_info->file, - pfile_in_zip_read_info->offset_local_extrafield + - pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) - return UNZ_ERRNO; - - if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) - return UNZ_ERRNO; - - return (int)read_now; -} - -/* - Close the file in zip opened with unzipOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ -extern int ZEXPORT unzCloseCurrentFile (unzFile file) -{ - int err=UNZ_OK; - - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - { - if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) - err=UNZ_CRCERROR; - } - - - TRYFREE(pfile_in_zip_read_info->read_buffer); - pfile_in_zip_read_info->read_buffer = NULL; - if (pfile_in_zip_read_info->stream_initialised) - inflateEnd(&pfile_in_zip_read_info->stream); - - pfile_in_zip_read_info->stream_initialised = 0; - TRYFREE(pfile_in_zip_read_info); - - s->pfile_in_zip_read=NULL; - - return err; -} - - -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ -extern int ZEXPORT unzGetGlobalComment - ( unzFile file, - char *szComment, - uLong uSizeBuf - ) -{ - unz_s* s; - uLong uReadThis ; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - uReadThis = uSizeBuf; - if (uReadThis>s->gi.size_comment) - uReadThis = s->gi.size_comment; - - if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) - return UNZ_ERRNO; - - if (uReadThis>0) - { - *szComment='\0'; - if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) - return UNZ_ERRNO; - } - - if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) - *(szComment+s->gi.size_comment)='\0'; - return (int)uReadThis; -} diff --git a/src/emucore/unzip.h b/src/emucore/unzip.h deleted file mode 100644 index 766b0b5b9..000000000 --- a/src/emucore/unzip.h +++ /dev/null @@ -1,275 +0,0 @@ -/* unzip.h -- IO for uncompress .zip files using zlib - Version 0.15 beta, Mar 19th, 1998, - - Copyright (C) 1998 Gilles Vollant - - This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g - WinZip, InfoZip tools and compatible. - Encryption and multi volume ZipFile (span) are not supported. - Old compressions used by old PKZip 1.x are not supported - - THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE - CAN CHANGE IN FUTURE VERSION !! - I WAIT FEEDBACK at mail info@winimage.com - Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - -*/ -/* for more info about .ZIP format, see - ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip - PkWare has also a specification at : - ftp://ftp.pkware.com/probdesc.zip */ - -#ifndef _unz_H -#define _unz_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -#include -#endif - -#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagunzFile__ { int unused; } unzFile__; -typedef unzFile__ *unzFile; -#else -typedef voidp unzFile; -#endif - - -#define UNZ_OK (0) -#define UNZ_END_OF_LIST_OF_FILE (-100) -#define UNZ_ERRNO (Z_ERRNO) -#define UNZ_EOF (0) -#define UNZ_PARAMERROR (-102) -#define UNZ_BADZIPFILE (-103) -#define UNZ_INTERNALERROR (-104) -#define UNZ_CRCERROR (-105) - -/* tm_unz contain date/time info */ -typedef struct tm_unz_s -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ -} tm_unz; - -/* unz_global_info structure contain global data about the ZIPfile - These data comes from the end of central dir */ -typedef struct unz_global_info_s -{ - uLong number_entry; /* total number of entries in - the central dir on this disk */ - uLong size_comment; /* size of the global comment of the zipfile */ -} unz_global_info; - - -/* unz_file_info contain information about a file in the zipfile */ -typedef struct unz_file_info_s -{ - uLong version; /* version made by 2 bytes */ - uLong version_needed; /* version needed to extract 2 bytes */ - uLong flag; /* general purpose bit flag 2 bytes */ - uLong compression_method; /* compression method 2 bytes */ - uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ - uLong crc; /* crc-32 4 bytes */ - uLong compressed_size; /* compressed size 4 bytes */ - uLong uncompressed_size; /* uncompressed size 4 bytes */ - uLong size_filename; /* filename length 2 bytes */ - uLong size_file_extra; /* extra field length 2 bytes */ - uLong size_file_comment; /* file comment length 2 bytes */ - - uLong disk_num_start; /* disk number start 2 bytes */ - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ - - tm_unz tmu_date; -} unz_file_info; - -extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, - const char* fileName2, - int iCaseSensitivity)); -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) -*/ - - -extern unzFile ZEXPORT unzOpen OF((const char *path)); -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer - "zlib/zlib111.zip". - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ - -extern int ZEXPORT unzClose OF((unzFile file)); -/* - Close a ZipFile opened with unzipOpen. - If there is files inside the .Zip opened with unzOpenCurrentFile (see later), - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. - return UNZ_OK if there is no problem. */ - -extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, - unz_global_info *pglobal_info)); -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ - - -extern int ZEXPORT unzGetGlobalComment OF((unzFile file, - char *szComment, - uLong uSizeBuf)); -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ - - -/***************************************************************************/ -/* Unzip package allow you browse the directory of the zipfile */ - -extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ - -extern int ZEXPORT unzGoToNextFile OF((unzFile file)); -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ - -extern int ZEXPORT unzLocateFile OF((unzFile file, - const char *szFileName, - int iCaseSensitivity)); -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ - - -extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, - unz_file_info *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); -/* - Get Info about the current file - if pfile_info!=NULL, the *pfile_info structure will contain somes info about - the current file - if szFileName!=NULL, the filemane string will be copied in szFileName - (fileNameBufferSize is the size of the buffer) - if extraField!=NULL, the extra field information will be copied in extraField - (extraFieldBufferSize is the size of the buffer). - This is the Central-header version of the extra field - if szComment!=NULL, the comment string of the file will be copied in szComment - (commentBufferSize is the size of the buffer) -*/ - -/***************************************************************************/ -/* for reading the content of the current zipfile, you can open it, read data - from it, and close it (you can close it before reading all the file) - */ - -extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); -/* - Open for reading data the current file in the zipfile. - If there is no error, the return value is UNZ_OK. -*/ - -extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); -/* - Close the file in zip opened with unzOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ - - -extern int ZEXPORT unzReadCurrentFile OF((unzFile file, - voidp buf, - unsigned len)); -/* - Read bytes from the current file (opened by unzOpenCurrentFile) - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ - -extern z_off_t ZEXPORT unztell OF((unzFile file)); -/* - Give the current position in uncompressed data -*/ - -extern int ZEXPORT unzeof OF((unzFile file)); -/* - return 1 if the end of file was reached, 0 elsewhere -*/ - -extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, - voidp buf, - unsigned len)); -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ - -#ifdef __cplusplus -} -#endif - -#endif /* _unz_H */ diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 49fbb1cb2..5821039b4 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -44,7 +44,6 @@ #include "StringList.hxx" #include "StringListWidget.hxx" #include "Widget.hxx" -#include "unzip.h" #include "LauncherDialog.hxx" @@ -349,9 +348,9 @@ void LauncherDialog::loadDirListing() files.reserve(2048); if(myCurrentNode.isDirectory()) - { myCurrentNode.getChildren(files, FilesystemNode::kListAll); - } + +#if 0 else { unzFile tz; @@ -394,6 +393,7 @@ void LauncherDialog::loadDirListing() } } } +#endif // Add '[..]' to indicate previous folder if(myCurrentNode.hasParent()) @@ -528,6 +528,7 @@ bool LauncherDialog::matchPattern(const string& s, const string& pattern) const int LauncherDialog::filesInArchive(const string& archive) { int count = -1; +#if 0 unzFile tz; if((tz = unzOpen(archive.c_str())) != NULL) { @@ -562,6 +563,7 @@ int LauncherDialog::filesInArchive(const string& archive) } } } +#endif return count; } @@ -606,9 +608,10 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, const string& md5 = myGameList->md5(item); string extension; + const FilesystemNode romnode(rom); + int numFilesInArchive = filesInArchive(rom); - bool isArchive = !myGameList->isDir(item) && - BSPF_endsWithIgnoreCase(rom, ".zip"); + bool isArchive = false;//!myGameList->isDir(item) && BSPF_endsWithIgnoreCase(rom, ".zip"); // Directory's should be selected (ie, enter them and redisplay) // Archives should be entered if they contain more than 1 file @@ -617,7 +620,7 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, instance().frameBuffer().showMessage("Archive does not contain any valid ROM files", kMiddleCenter, true); } - else if((isArchive && numFilesInArchive > 1) || myGameList->isDir(item)) + else if(/*(isArchive && numFilesInArchive > 1) ||*/ romnode.isDirectory()) { string dirname = ""; if(myGameList->name(item) == " [..]") @@ -628,7 +631,7 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, } else { - myCurrentNode = FilesystemNode(rom); + myCurrentNode = romnode; myNodeNames.push(myGameList->name(item)); } updateListing(dirname); @@ -637,7 +640,7 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd, { if(LauncherFilterDialog::isValidRomName(rom, extension)) { - if(instance().createConsole(rom, md5)) + if(instance().createConsole(romnode.getPath(), md5)) instance().settings().setString("lastrom", myList->getSelectedString()); else instance().frameBuffer().showMessage(