mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
support compression in multifiles
This commit is contained in:
parent
1d49310670
commit
8d55c759de
@ -24,6 +24,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "multifile.h"
|
#include "multifile.h"
|
||||||
#include "filename.h"
|
#include "filename.h"
|
||||||
|
#include "pset.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
@ -32,12 +33,15 @@ bool append = false; // -r
|
|||||||
bool list = false; // -t
|
bool list = false; // -t
|
||||||
bool extract = false; // -x
|
bool extract = false; // -x
|
||||||
bool verbose = false; // -v
|
bool verbose = false; // -v
|
||||||
|
bool compress = false; // -z
|
||||||
|
int default_compression_level = 6;
|
||||||
Filename multifile_name; // -f
|
Filename multifile_name; // -f
|
||||||
bool got_multifile_name = false;
|
bool got_multifile_name = false;
|
||||||
bool to_stdout = false; // -O
|
bool to_stdout = false; // -O
|
||||||
Filename chdir_to; // -C
|
Filename chdir_to; // -C
|
||||||
bool got_chdir_to = false;
|
bool got_chdir_to = false;
|
||||||
size_t scale_factor = 0; // -F
|
size_t scale_factor = 0; // -F
|
||||||
|
pset<string> dont_compress; // -Z
|
||||||
|
|
||||||
void
|
void
|
||||||
usage() {
|
usage() {
|
||||||
@ -73,6 +77,25 @@ is_named(const string &subfile_name, int argc, char *argv[]) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_compression_level(const Filename &subfile_name) {
|
||||||
|
// Returns the appropriate compression level for the named file.
|
||||||
|
if (!compress) {
|
||||||
|
// Don't compress anything.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string ext = subfile_name.get_extension();
|
||||||
|
if (dont_compress.find(ext) != dont_compress.end()) {
|
||||||
|
// This extension is listed on the -Z parameter list; don't
|
||||||
|
// compress it.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go ahead and compress this file.
|
||||||
|
return default_compression_level;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
add_directory(Multifile &multifile, const Filename &directory_name) {
|
add_directory(Multifile &multifile, const Filename &directory_name) {
|
||||||
vector_string files;
|
vector_string files;
|
||||||
@ -95,7 +118,8 @@ add_directory(Multifile &multifile, const Filename &directory_name) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
string new_subfile_name =
|
string new_subfile_name =
|
||||||
multifile.add_subfile(subfile_name, subfile_name);
|
multifile.add_subfile(subfile_name, subfile_name,
|
||||||
|
get_compression_level(subfile_name));
|
||||||
if (new_subfile_name.empty()) {
|
if (new_subfile_name.empty()) {
|
||||||
cerr << "Unable to add " << subfile_name << ".\n";
|
cerr << "Unable to add " << subfile_name << ".\n";
|
||||||
okflag = false;
|
okflag = false;
|
||||||
@ -144,7 +168,8 @@ add_files(int argc, char *argv[]) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
string new_subfile_name =
|
string new_subfile_name =
|
||||||
multifile.add_subfile(subfile_name, subfile_name);
|
multifile.add_subfile(subfile_name, subfile_name,
|
||||||
|
get_compression_level(subfile_name));
|
||||||
if (new_subfile_name.empty()) {
|
if (new_subfile_name.empty()) {
|
||||||
cerr << "Unable to add " << subfile_name << ".\n";
|
cerr << "Unable to add " << subfile_name << ".\n";
|
||||||
okflag = false;
|
okflag = false;
|
||||||
@ -228,9 +253,19 @@ list_files(int argc, char *argv[]) {
|
|||||||
for (int i = 0; i < num_subfiles; i++) {
|
for (int i = 0; i < num_subfiles; i++) {
|
||||||
string subfile_name = multifile.get_subfile_name(i);
|
string subfile_name = multifile.get_subfile_name(i);
|
||||||
if (is_named(subfile_name, argc, argv)) {
|
if (is_named(subfile_name, argc, argv)) {
|
||||||
printf("%12d %s\n",
|
if (multifile.is_subfile_compressed(i)) {
|
||||||
multifile.get_subfile_length(i),
|
double ratio =
|
||||||
subfile_name.c_str());
|
(double)multifile.get_subfile_compressed_length(i) /
|
||||||
|
(double)multifile.get_subfile_length(i);
|
||||||
|
printf("%12d %3.0f%% %s\n",
|
||||||
|
multifile.get_subfile_length(i),
|
||||||
|
100.0 - ratio * 100.0,
|
||||||
|
subfile_name.c_str());
|
||||||
|
} else {
|
||||||
|
printf("%12d %s\n",
|
||||||
|
multifile.get_subfile_length(i),
|
||||||
|
subfile_name.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@ -252,6 +287,21 @@ list_files(int argc, char *argv[]) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tokenize_extensions(const string &str, pset<string> &extensions) {
|
||||||
|
size_t p = 0;
|
||||||
|
while (p < str.length()) {
|
||||||
|
size_t q = str.find_first_of(",", p);
|
||||||
|
if (q == string::npos) {
|
||||||
|
extensions.insert(str.substr(p));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extensions.insert(str.substr(p, q - p));
|
||||||
|
p = q + 1;
|
||||||
|
}
|
||||||
|
extensions.insert(string());
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[]) {
|
main(int argc, char *argv[]) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
@ -270,9 +320,12 @@ main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default extensions not to compress. May be overridden with -Z.
|
||||||
|
string dont_compress_str = "jpg,mp3";
|
||||||
|
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
extern int optind;
|
extern int optind;
|
||||||
static const char *optflags = "crtxvf:OC:F:h";
|
static const char *optflags = "crtxvz123456789Z:f:OC:F:h";
|
||||||
int flag = getopt(argc, argv, optflags);
|
int flag = getopt(argc, argv, optflags);
|
||||||
Filename rel_path;
|
Filename rel_path;
|
||||||
while (flag != EOF) {
|
while (flag != EOF) {
|
||||||
@ -292,6 +345,48 @@ main(int argc, char *argv[]) {
|
|||||||
case 'v':
|
case 'v':
|
||||||
verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
|
case 'z':
|
||||||
|
compress = true;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
default_compression_level = 1;
|
||||||
|
compress = true;
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
default_compression_level = 2;
|
||||||
|
compress = true;
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
default_compression_level = 3;
|
||||||
|
compress = true;
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
default_compression_level = 4;
|
||||||
|
compress = true;
|
||||||
|
break;
|
||||||
|
case '5':
|
||||||
|
default_compression_level = 5;
|
||||||
|
compress = true;
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
default_compression_level = 6;
|
||||||
|
compress = true;
|
||||||
|
break;
|
||||||
|
case '7':
|
||||||
|
default_compression_level = 7;
|
||||||
|
compress = true;
|
||||||
|
break;
|
||||||
|
case '8':
|
||||||
|
default_compression_level = 8;
|
||||||
|
compress = true;
|
||||||
|
break;
|
||||||
|
case '9':
|
||||||
|
default_compression_level = 9;
|
||||||
|
compress = true;
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
dont_compress_str = optarg;
|
||||||
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
multifile_name = Filename::from_os_specific(optarg);
|
multifile_name = Filename::from_os_specific(optarg);
|
||||||
got_multifile_name = true;
|
got_multifile_name = true;
|
||||||
@ -343,21 +438,14 @@ main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!got_multifile_name) {
|
if (!got_multifile_name) {
|
||||||
if (argc <= 1) {
|
cerr << "Multifile name not specified.\n";
|
||||||
usage();
|
usage();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
// For now, we allow -f to be omitted, and use the first argument
|
|
||||||
// as the archive name, for backward compatibility. Later we will
|
|
||||||
// remove this.
|
|
||||||
multifile_name = Filename::from_os_specific(argv[1]);
|
|
||||||
cerr << "Warning: using " << multifile_name
|
|
||||||
<< " as archive name. Use -f in the future to specify this.\n";
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split out the extensions named by -Z into different words.
|
||||||
|
tokenize_extensions(dont_compress_str, dont_compress);
|
||||||
|
|
||||||
bool okflag = true;
|
bool okflag = true;
|
||||||
if (create || append) {
|
if (create || append) {
|
||||||
okflag = add_files(argc, argv);
|
okflag = add_files(argc, argv);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#begin lib_target
|
#begin lib_target
|
||||||
#define TARGET express
|
#define TARGET express
|
||||||
#define USE_PACKAGES nspr crypto net
|
#define USE_PACKAGES nspr crypto net zlib
|
||||||
|
|
||||||
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
|
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
|
||||||
|
|
||||||
@ -44,6 +44,7 @@
|
|||||||
typeRegistry.I typeRegistry.h \
|
typeRegistry.I typeRegistry.h \
|
||||||
typeRegistryNode.I typeRegistryNode.h \
|
typeRegistryNode.I typeRegistryNode.h \
|
||||||
vector_uchar.h \
|
vector_uchar.h \
|
||||||
|
zStream.I zStream.h zStreamBuf.h \
|
||||||
$[if $[HAVE_CRYPTO], \
|
$[if $[HAVE_CRYPTO], \
|
||||||
crypto_utils.cxx crypto_utils.h patchfile.I \
|
crypto_utils.cxx crypto_utils.h patchfile.I \
|
||||||
patchfile.cxx patchfile.h ]
|
patchfile.cxx patchfile.h ]
|
||||||
@ -66,7 +67,8 @@
|
|||||||
subStream.cxx subStreamBuf.cxx \
|
subStream.cxx subStreamBuf.cxx \
|
||||||
trueClock.cxx typeHandle.cxx \
|
trueClock.cxx typeHandle.cxx \
|
||||||
typedObject.cxx typedReferenceCount.cxx \
|
typedObject.cxx typedReferenceCount.cxx \
|
||||||
typeRegistry.cxx typeRegistryNode.cxx vector_uchar.cxx
|
typeRegistry.cxx typeRegistryNode.cxx vector_uchar.cxx \
|
||||||
|
zStream.cxx zStreamBuf.cxx
|
||||||
|
|
||||||
#define INSTALL_HEADERS \
|
#define INSTALL_HEADERS \
|
||||||
bigEndian.h buffer.I buffer.h checksumHashGenerator.I \
|
bigEndian.h buffer.I buffer.h checksumHashGenerator.I \
|
||||||
@ -98,7 +100,8 @@
|
|||||||
typedReferenceCount.h typedef.h \
|
typedReferenceCount.h typedef.h \
|
||||||
typeRegistry.I typeRegistry.h \
|
typeRegistry.I typeRegistry.h \
|
||||||
typeRegistryNode.I typeRegistryNode.h \
|
typeRegistryNode.I typeRegistryNode.h \
|
||||||
vector_uchar.h
|
vector_uchar.h \
|
||||||
|
zStream.I zStream.h zStreamBuf.h
|
||||||
|
|
||||||
#define IGATESCAN all
|
#define IGATESCAN all
|
||||||
|
|
||||||
@ -125,3 +128,17 @@
|
|||||||
#define OTHER_LIBS $[OTHER_LIBS] pystub
|
#define OTHER_LIBS $[OTHER_LIBS] pystub
|
||||||
|
|
||||||
#end test_bin_target
|
#end test_bin_target
|
||||||
|
|
||||||
|
|
||||||
|
#if $[HAVE_ZLIB]
|
||||||
|
#begin test_bin_target
|
||||||
|
#define TARGET test_zstream
|
||||||
|
#define USE_PACKAGES zlib
|
||||||
|
#define LOCAL_LIBS $[LOCAL_LIBS] express
|
||||||
|
#define OTHER_LIBS pystub
|
||||||
|
|
||||||
|
#define SOURCES \
|
||||||
|
test_zstream.cxx
|
||||||
|
|
||||||
|
#end test_bin_target
|
||||||
|
#endif
|
||||||
|
@ -19,4 +19,6 @@
|
|||||||
#include "typeRegistry.cxx"
|
#include "typeRegistry.cxx"
|
||||||
#include "typeRegistryNode.cxx"
|
#include "typeRegistryNode.cxx"
|
||||||
#include "vector_uchar.cxx"
|
#include "vector_uchar.cxx"
|
||||||
|
#include "zStream.cxx"
|
||||||
|
#include "zStreamBuf.cxx"
|
||||||
|
|
||||||
|
@ -120,6 +120,7 @@ Subfile() {
|
|||||||
_data_length = 0;
|
_data_length = 0;
|
||||||
_source = (istream *)NULL;
|
_source = (istream *)NULL;
|
||||||
_flags = 0;
|
_flags = 0;
|
||||||
|
_compression_level = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "config_express.h"
|
#include "config_express.h"
|
||||||
#include "streamWriter.h"
|
#include "streamWriter.h"
|
||||||
#include "streamReader.h"
|
#include "streamReader.h"
|
||||||
|
#include "zStream.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@ -63,6 +64,9 @@ const int Multifile::_current_minor_ver = 0;
|
|||||||
// uint32 The address of this subfile's data record.
|
// uint32 The address of this subfile's data record.
|
||||||
// uint32 The length in bytes of this subfile's data record.
|
// uint32 The length in bytes of this subfile's data record.
|
||||||
// uint16 The Subfile::_flags member.
|
// uint16 The Subfile::_flags member.
|
||||||
|
// [uint32] The original, uncompressed length of the subfile, if it
|
||||||
|
// is compressed. This field is only present if the
|
||||||
|
// SF_compressed bit is set in _flags.
|
||||||
// uint16 The length in bytes of the subfile's name.
|
// uint16 The length in bytes of the subfile's name.
|
||||||
// char[n] The subfile's name.
|
// char[n] The subfile's name.
|
||||||
//
|
//
|
||||||
@ -295,7 +299,8 @@ set_scale_factor(size_t scale_factor) {
|
|||||||
// been modified slightly), or empty string on failure.
|
// been modified slightly), or empty string on failure.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
string Multifile::
|
string Multifile::
|
||||||
add_subfile(const string &subfile_name, const Filename &filename) {
|
add_subfile(const string &subfile_name, const Filename &filename,
|
||||||
|
int compression_level) {
|
||||||
nassertr(is_write_valid(), string());
|
nassertr(is_write_valid(), string());
|
||||||
|
|
||||||
if (!filename.exists()) {
|
if (!filename.exists()) {
|
||||||
@ -305,7 +310,7 @@ add_subfile(const string &subfile_name, const Filename &filename) {
|
|||||||
subfile->_source_filename = filename;
|
subfile->_source_filename = filename;
|
||||||
subfile->_source_filename.set_binary();
|
subfile->_source_filename.set_binary();
|
||||||
|
|
||||||
return add_new_subfile(subfile_name, subfile);
|
return add_new_subfile(subfile_name, subfile, compression_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -670,12 +675,41 @@ get_subfile_name(int index) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: Multifile::get_subfile_length
|
// Function: Multifile::get_subfile_length
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Returns the data length of the nth subfile. This
|
// Description: Returns the uncompressed data length of the nth
|
||||||
// might return 0 if the subfile has recently been added
|
// subfile. This might return 0 if the subfile has
|
||||||
// and flush() has not yet been called.
|
// recently been added and flush() has not yet been
|
||||||
|
// called.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
size_t Multifile::
|
size_t Multifile::
|
||||||
get_subfile_length(int index) const {
|
get_subfile_length(int index) const {
|
||||||
|
nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
|
||||||
|
return _subfiles[index]->_uncompressed_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: Multifile::is_subfile_compressed
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns true if the indicated subfile has been
|
||||||
|
// compressed when stored within the archive, false
|
||||||
|
// otherwise.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool Multifile::
|
||||||
|
is_subfile_compressed(int index) const {
|
||||||
|
nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
|
||||||
|
return (_subfiles[index]->_flags & SF_compressed) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: Multifile::get_subfile_compressed_length
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the number of bytes the indicated subfile
|
||||||
|
// consumes within the archive. For compressed
|
||||||
|
// subfiles, this will generally be smaller than
|
||||||
|
// get_subfile_length(); for noncompressed subfiles, it
|
||||||
|
// will be equal.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
size_t Multifile::
|
||||||
|
get_subfile_compressed_length(int index) const {
|
||||||
nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
|
nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
|
||||||
return _subfiles[index]->_data_length;
|
return _subfiles[index]->_data_length;
|
||||||
}
|
}
|
||||||
@ -818,7 +852,7 @@ open_read_write(iostream *multifile_stream) {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: Multifile::add_subfile
|
// Function: Multifile::add_subfile
|
||||||
// Access: Published
|
// Access: Public
|
||||||
// Description: Adds a file on disk as a subfile to the Multifile.
|
// Description: Adds a file on disk as a subfile to the Multifile.
|
||||||
// The indicated istream will be read and its contents
|
// The indicated istream will be read and its contents
|
||||||
// added to the Multifile at the next call to flush().
|
// added to the Multifile at the next call to flush().
|
||||||
@ -827,13 +861,14 @@ open_read_write(iostream *multifile_stream) {
|
|||||||
// been modified slightly), or empty string on failure.
|
// been modified slightly), or empty string on failure.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
string Multifile::
|
string Multifile::
|
||||||
add_subfile(const string &subfile_name, istream *subfile_data) {
|
add_subfile(const string &subfile_name, istream *subfile_data,
|
||||||
|
int compression_level) {
|
||||||
nassertr(is_write_valid(), string());
|
nassertr(is_write_valid(), string());
|
||||||
|
|
||||||
Subfile *subfile = new Subfile;
|
Subfile *subfile = new Subfile;
|
||||||
subfile->_source = subfile_data;
|
subfile->_source = subfile_data;
|
||||||
|
|
||||||
return add_new_subfile(subfile_name, subfile);
|
return add_new_subfile(subfile_name, subfile, compression_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -903,9 +938,17 @@ open_read_subfile(int index) {
|
|||||||
// Return an ISubStream object that references into the open
|
// Return an ISubStream object that references into the open
|
||||||
// Multifile istream.
|
// Multifile istream.
|
||||||
nassertr(subfile->_data_start != (streampos)0, new fstream);
|
nassertr(subfile->_data_start != (streampos)0, new fstream);
|
||||||
ISubStream *stream = new ISubStream;
|
istream *stream =
|
||||||
stream->open(_read, subfile->_data_start,
|
new ISubStream(_read, subfile->_data_start,
|
||||||
subfile->_data_start + (streampos)subfile->_data_length);
|
subfile->_data_start + (streampos)subfile->_data_length);
|
||||||
|
|
||||||
|
if ((subfile->_flags & SF_compressed) != 0) {
|
||||||
|
// Oops, the subfile is compressed. So actually, return an
|
||||||
|
// IDecompressStream that wraps around the ISubStream.
|
||||||
|
IDecompressStream *wrapper = new IDecompressStream(stream, true);
|
||||||
|
stream = wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -937,7 +980,13 @@ pad_to_streampos(streampos fpos) {
|
|||||||
// Multifile.
|
// Multifile.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
string Multifile::
|
string Multifile::
|
||||||
add_new_subfile(const string &subfile_name, Subfile *subfile) {
|
add_new_subfile(const string &subfile_name, Subfile *subfile,
|
||||||
|
int compression_level) {
|
||||||
|
if (compression_level != 0) {
|
||||||
|
subfile->_flags |= SF_compressed;
|
||||||
|
subfile->_compression_level = compression_level;
|
||||||
|
}
|
||||||
|
|
||||||
if (_next_index != (streampos)0) {
|
if (_next_index != (streampos)0) {
|
||||||
// If we're adding a Subfile to an already-existing Multifile, we
|
// If we're adding a Subfile to an already-existing Multifile, we
|
||||||
// will eventually need to repack the file.
|
// will eventually need to repack the file.
|
||||||
@ -1160,6 +1209,11 @@ read_index(istream &read, streampos fpos, Multifile *multifile) {
|
|||||||
_data_start = multifile->word_to_streampos(reader.get_uint32());
|
_data_start = multifile->word_to_streampos(reader.get_uint32());
|
||||||
_data_length = reader.get_uint32();
|
_data_length = reader.get_uint32();
|
||||||
_flags = reader.get_uint16();
|
_flags = reader.get_uint16();
|
||||||
|
if ((_flags & SF_compressed) != 0) {
|
||||||
|
_uncompressed_length = reader.get_uint32();
|
||||||
|
} else {
|
||||||
|
_uncompressed_length = _data_length;
|
||||||
|
}
|
||||||
size_t name_length = reader.get_uint16();
|
size_t name_length = reader.get_uint16();
|
||||||
if (read.eof() || read.fail()) {
|
if (read.eof() || read.fail()) {
|
||||||
_flags |= SF_index_invalid;
|
_flags |= SF_index_invalid;
|
||||||
@ -1207,6 +1261,9 @@ write_index(ostream &write, streampos fpos, Multifile *multifile) {
|
|||||||
dg.add_uint32(multifile->streampos_to_word(_data_start));
|
dg.add_uint32(multifile->streampos_to_word(_data_start));
|
||||||
dg.add_uint32(_data_length);
|
dg.add_uint32(_data_length);
|
||||||
dg.add_uint16(_flags);
|
dg.add_uint16(_flags);
|
||||||
|
if ((_flags & SF_compressed) != 0) {
|
||||||
|
dg.add_uint32(_uncompressed_length);
|
||||||
|
}
|
||||||
dg.add_uint16(_name.length());
|
dg.add_uint16(_name.length());
|
||||||
|
|
||||||
// For no real good reason, we'll invert all the bits in the name.
|
// For no real good reason, we'll invert all the bits in the name.
|
||||||
@ -1243,8 +1300,9 @@ write_index(ostream &write, streampos fpos, Multifile *multifile) {
|
|||||||
// effective end of the file. Returns the position
|
// effective end of the file. Returns the position
|
||||||
// within the file of the next data record.
|
// within the file of the next data record.
|
||||||
//
|
//
|
||||||
// The _data_start and _data_length members are updated
|
// The _data_start, _data_length, and
|
||||||
// by this operation.
|
// _uncompressed_length members are updated by this
|
||||||
|
// operation.
|
||||||
//
|
//
|
||||||
// If the "read" pointer is non-NULL, it is the readable
|
// If the "read" pointer is non-NULL, it is the readable
|
||||||
// istream of a Multifile in which the Subfile might
|
// istream of a Multifile in which the Subfile might
|
||||||
@ -1265,6 +1323,7 @@ write_data(ostream &write, istream *read, streampos fpos) {
|
|||||||
<< "Unable to read " << _source_filename << ".\n";
|
<< "Unable to read " << _source_filename << ".\n";
|
||||||
_flags |= SF_data_invalid;
|
_flags |= SF_data_invalid;
|
||||||
_data_length = 0;
|
_data_length = 0;
|
||||||
|
_uncompressed_length = 0;
|
||||||
} else {
|
} else {
|
||||||
source = &source_file;
|
source = &source_file;
|
||||||
}
|
}
|
||||||
@ -1295,12 +1354,30 @@ write_data(ostream &write, istream *read, streampos fpos) {
|
|||||||
} else {
|
} else {
|
||||||
// We do have source data. Copy it in, and also measure its
|
// We do have source data. Copy it in, and also measure its
|
||||||
// length.
|
// length.
|
||||||
_data_length = 0;
|
if ((_flags & SF_compressed) != 0) {
|
||||||
int byte = source->get();
|
// Write it compressed.
|
||||||
while (!source->eof() && !source->fail()) {
|
streampos write_start = write.tellp();
|
||||||
_data_length++;
|
_uncompressed_length = 0;
|
||||||
write.put(byte);
|
OCompressStream zstream(&write, false, _compression_level);
|
||||||
byte = source->get();
|
int byte = source->get();
|
||||||
|
while (!source->eof() && !source->fail()) {
|
||||||
|
_uncompressed_length++;
|
||||||
|
zstream.put(byte);
|
||||||
|
byte = source->get();
|
||||||
|
}
|
||||||
|
zstream.close();
|
||||||
|
streampos write_end = write.tellp();
|
||||||
|
_data_length = (size_t)(write_end - write_start);
|
||||||
|
} else {
|
||||||
|
// Write it uncompressed.
|
||||||
|
_uncompressed_length = 0;
|
||||||
|
int byte = source->get();
|
||||||
|
while (!source->eof() && !source->fail()) {
|
||||||
|
_uncompressed_length++;
|
||||||
|
write.put(byte);
|
||||||
|
byte = source->get();
|
||||||
|
}
|
||||||
|
_data_length = _uncompressed_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1334,6 +1411,10 @@ rewrite_index_data_start(ostream &write, Multifile *multifile) {
|
|||||||
StreamWriter writer(write);
|
StreamWriter writer(write);
|
||||||
writer.add_uint32(multifile->streampos_to_word(_data_start));
|
writer.add_uint32(multifile->streampos_to_word(_data_start));
|
||||||
writer.add_uint32(_data_length);
|
writer.add_uint32(_data_length);
|
||||||
|
writer.add_uint16(_flags);
|
||||||
|
if ((_flags & SF_compressed) != 0) {
|
||||||
|
writer.add_uint32(_uncompressed_length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -57,7 +57,8 @@ PUBLISHED:
|
|||||||
void set_scale_factor(size_t scale_factor);
|
void set_scale_factor(size_t scale_factor);
|
||||||
INLINE size_t get_scale_factor() const;
|
INLINE size_t get_scale_factor() const;
|
||||||
|
|
||||||
string add_subfile(const string &subfile_name, const Filename &filename);
|
string add_subfile(const string &subfile_name, const Filename &filename,
|
||||||
|
int compression_level);
|
||||||
bool flush();
|
bool flush();
|
||||||
bool repack();
|
bool repack();
|
||||||
|
|
||||||
@ -69,6 +70,8 @@ PUBLISHED:
|
|||||||
void remove_subfile(int index);
|
void remove_subfile(int index);
|
||||||
const string &get_subfile_name(int index) const;
|
const string &get_subfile_name(int index) const;
|
||||||
size_t get_subfile_length(int index) const;
|
size_t get_subfile_length(int index) const;
|
||||||
|
bool is_subfile_compressed(int index) const;
|
||||||
|
size_t get_subfile_compressed_length(int index) const;
|
||||||
|
|
||||||
void read_subfile(int index, Datagram &datagram);
|
void read_subfile(int index, Datagram &datagram);
|
||||||
bool extract_subfile(int index, const Filename &filename);
|
bool extract_subfile(int index, const Filename &filename);
|
||||||
@ -81,7 +84,8 @@ public:
|
|||||||
bool open_read(istream *multifile_stream);
|
bool open_read(istream *multifile_stream);
|
||||||
bool open_write(ostream *multifile_stream);
|
bool open_write(ostream *multifile_stream);
|
||||||
bool open_read_write(iostream *multifile_stream);
|
bool open_read_write(iostream *multifile_stream);
|
||||||
string add_subfile(const string &subfile_name, istream *subfile_data);
|
string add_subfile(const string &subfile_name, istream *subfile_data,
|
||||||
|
int compression_level);
|
||||||
|
|
||||||
bool extract_subfile_to(int index, ostream &out);
|
bool extract_subfile_to(int index, ostream &out);
|
||||||
istream *open_read_subfile(int index);
|
istream *open_read_subfile(int index);
|
||||||
@ -91,6 +95,7 @@ private:
|
|||||||
SF_deleted = 0x0001,
|
SF_deleted = 0x0001,
|
||||||
SF_index_invalid = 0x0002,
|
SF_index_invalid = 0x0002,
|
||||||
SF_data_invalid = 0x0004,
|
SF_data_invalid = 0x0004,
|
||||||
|
SF_compressed = 0x0008,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Subfile {
|
class Subfile {
|
||||||
@ -112,9 +117,11 @@ private:
|
|||||||
streampos _index_start;
|
streampos _index_start;
|
||||||
streampos _data_start;
|
streampos _data_start;
|
||||||
size_t _data_length;
|
size_t _data_length;
|
||||||
|
size_t _uncompressed_length;
|
||||||
istream *_source;
|
istream *_source;
|
||||||
Filename _source_filename;
|
Filename _source_filename;
|
||||||
int _flags;
|
int _flags;
|
||||||
|
int _compression_level; // Not preserved on disk.
|
||||||
};
|
};
|
||||||
|
|
||||||
INLINE streampos word_to_streampos(size_t word) const;
|
INLINE streampos word_to_streampos(size_t word) const;
|
||||||
@ -122,7 +129,8 @@ private:
|
|||||||
INLINE streampos normalize_streampos(streampos fpos) const;
|
INLINE streampos normalize_streampos(streampos fpos) const;
|
||||||
streampos pad_to_streampos(streampos fpos);
|
streampos pad_to_streampos(streampos fpos);
|
||||||
|
|
||||||
string add_new_subfile(const string &subfile_name, Subfile *subfile);
|
string add_new_subfile(const string &subfile_name, Subfile *subfile,
|
||||||
|
int compression_level);
|
||||||
void clear_subfiles();
|
void clear_subfiles();
|
||||||
bool read_index();
|
bool read_index();
|
||||||
bool write_header();
|
bool write_header();
|
||||||
|
@ -26,6 +26,16 @@ INLINE ISubStream::
|
|||||||
ISubStream() : istream(&_buf) {
|
ISubStream() : istream(&_buf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ISubStream::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE ISubStream::
|
||||||
|
ISubStream(istream *source, streampos start, streampos end) : istream(&_buf) {
|
||||||
|
open(source, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: ISubStream::open
|
// Function: ISubStream::open
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -39,10 +49,11 @@ ISubStream() : istream(&_buf) {
|
|||||||
// If end is zero, it indicates that the ISubStream will
|
// If end is zero, it indicates that the ISubStream will
|
||||||
// continue until the end of the source stream.
|
// continue until the end of the source stream.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE void ISubStream::
|
INLINE ISubStream &ISubStream::
|
||||||
open(istream *source, streampos start, streampos end) {
|
open(istream *source, streampos start, streampos end) {
|
||||||
clear(0);
|
clear(0);
|
||||||
_buf.open(source, start, end);
|
_buf.open(source, start, end);
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -51,8 +62,9 @@ open(istream *source, streampos start, streampos end) {
|
|||||||
// Description: Resets the SubStream to empty, but does not actually
|
// Description: Resets the SubStream to empty, but does not actually
|
||||||
// close the source istream.
|
// close the source istream.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE void ISubStream::
|
INLINE ISubStream &ISubStream::
|
||||||
close() {
|
close() {
|
||||||
_buf.close();
|
_buf.close();
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,9 +37,10 @@
|
|||||||
class EXPCL_PANDAEXPRESS ISubStream : public istream {
|
class EXPCL_PANDAEXPRESS ISubStream : public istream {
|
||||||
public:
|
public:
|
||||||
INLINE ISubStream();
|
INLINE ISubStream();
|
||||||
|
INLINE ISubStream(istream *source, streampos start, streampos end);
|
||||||
|
|
||||||
INLINE void open(istream *source, streampos start, streampos end);
|
INLINE ISubStream &open(istream *source, streampos start, streampos end);
|
||||||
INLINE void close();
|
INLINE ISubStream &close();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SubStreamBuf _buf;
|
SubStreamBuf _buf;
|
||||||
|
70
panda/src/express/test_zstream.cxx
Normal file
70
panda/src/express/test_zstream.cxx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Filename: test_zstream.cxx
|
||||||
|
// Created by: drose (05Aug02)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the Panda 3d
|
||||||
|
// Software license. You should have received a copy of this license
|
||||||
|
// along with this source code; you will also find a current copy of
|
||||||
|
// the license at http://www.panda3d.org/license.txt .
|
||||||
|
//
|
||||||
|
// To contact the maintainers of this program write to
|
||||||
|
// panda3d@yahoogroups.com .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "pandabase.h"
|
||||||
|
#include "zStream.h"
|
||||||
|
#include "filename.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
decompress(istream &source) {
|
||||||
|
IDecompressStream zstream(&source, false);
|
||||||
|
|
||||||
|
int ch = zstream.get();
|
||||||
|
while (!zstream.eof() && !zstream.fail()) {
|
||||||
|
cout.put(ch);
|
||||||
|
ch = zstream.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
compress(istream &source) {
|
||||||
|
OCompressStream zstream(&cout, false);
|
||||||
|
|
||||||
|
int ch = source.get();
|
||||||
|
while (!source.eof() && !source.fail()) {
|
||||||
|
zstream.put(ch);
|
||||||
|
ch = source.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
cerr << "test_zstream file\n"
|
||||||
|
<< "compresses file to standard output, or decompresses it if the\n"
|
||||||
|
<< "filename ends in .pz.\n";
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Filename source_filename = argv[1];
|
||||||
|
source_filename.set_binary();
|
||||||
|
|
||||||
|
ifstream source;
|
||||||
|
|
||||||
|
if (!source_filename.open_read(source)) {
|
||||||
|
cerr << "Unable to open source " << source_filename << ".\n";
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (source_filename.get_extension() == "pz") {
|
||||||
|
decompress(source);
|
||||||
|
} else {
|
||||||
|
compress(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
108
panda/src/express/zStream.I
Normal file
108
panda/src/express/zStream.I
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// Filename: zStream.I
|
||||||
|
// Created by: drose (05Aug02)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the Panda 3d
|
||||||
|
// Software license. You should have received a copy of this license
|
||||||
|
// along with this source code; you will also find a current copy of
|
||||||
|
// the license at http://www.panda3d.org/license.txt .
|
||||||
|
//
|
||||||
|
// To contact the maintainers of this program write to
|
||||||
|
// panda3d@yahoogroups.com .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: IDecompressStream::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE IDecompressStream::
|
||||||
|
IDecompressStream() : istream(&_buf) {
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: IDecompressStream::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE IDecompressStream::
|
||||||
|
IDecompressStream(istream *source, bool owns_source) : istream(&_buf) {
|
||||||
|
open(source, owns_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: IDecompressStream::open
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE IDecompressStream &IDecompressStream::
|
||||||
|
open(istream *source, bool owns_source) {
|
||||||
|
clear(0);
|
||||||
|
_buf.open_read(source, owns_source);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: IDecompressStream::close
|
||||||
|
// Access: Public
|
||||||
|
// Description: Resets the ZStream to empty, but does not actually
|
||||||
|
// close the source istream unless owns_source was true.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE IDecompressStream &IDecompressStream::
|
||||||
|
close() {
|
||||||
|
_buf.close_read();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OCompressStream::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE OCompressStream::
|
||||||
|
OCompressStream() : ostream(&_buf) {
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OCompressStream::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE OCompressStream::
|
||||||
|
OCompressStream(ostream *dest, bool owns_dest, int compression_level) :
|
||||||
|
ostream(&_buf)
|
||||||
|
{
|
||||||
|
open(dest, owns_dest, compression_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OCompressStream::open
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE OCompressStream &OCompressStream::
|
||||||
|
open(ostream *dest, bool owns_dest, int compression_level) {
|
||||||
|
clear(0);
|
||||||
|
_buf.open_write(dest, owns_dest, compression_level);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: OCompressStream::close
|
||||||
|
// Access: Public
|
||||||
|
// Description: Resets the ZStream to empty, but does not actually
|
||||||
|
// close the dest ostream unless owns_dest was true.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE OCompressStream &OCompressStream::
|
||||||
|
close() {
|
||||||
|
_buf.close_write();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
19
panda/src/express/zStream.cxx
Normal file
19
panda/src/express/zStream.cxx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Filename: zStream.cxx
|
||||||
|
// Created by: drose (05Aug02)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the Panda 3d
|
||||||
|
// Software license. You should have received a copy of this license
|
||||||
|
// along with this source code; you will also find a current copy of
|
||||||
|
// the license at http://www.panda3d.org/license.txt .
|
||||||
|
//
|
||||||
|
// To contact the maintainers of this program write to
|
||||||
|
// panda3d@yahoogroups.com .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "zStream.h"
|
86
panda/src/express/zStream.h
Normal file
86
panda/src/express/zStream.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// Filename: zStream.h
|
||||||
|
// Created by: drose (05Aug02)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the Panda 3d
|
||||||
|
// Software license. You should have received a copy of this license
|
||||||
|
// along with this source code; you will also find a current copy of
|
||||||
|
// the license at http://www.panda3d.org/license.txt .
|
||||||
|
//
|
||||||
|
// To contact the maintainers of this program write to
|
||||||
|
// panda3d@yahoogroups.com .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef ZSTREAM_H
|
||||||
|
#define ZSTREAM_H
|
||||||
|
|
||||||
|
#include "pandabase.h"
|
||||||
|
|
||||||
|
// This module is not compiled if zlib is not available.
|
||||||
|
#ifdef HAVE_ZLIB
|
||||||
|
|
||||||
|
#include "zStreamBuf.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Class : IDecompressStream
|
||||||
|
// Description : An input stream object that uses zlib to decompress
|
||||||
|
// (inflate) the input from another source stream
|
||||||
|
// on-the-fly.
|
||||||
|
//
|
||||||
|
// Attach an IDecompressStream to an existing istream that
|
||||||
|
// provides compressed data, and read the corresponding
|
||||||
|
// uncompressed data from the IDecompressStream.
|
||||||
|
//
|
||||||
|
// Seeking is not supported.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class EXPCL_PANDAEXPRESS IDecompressStream : public istream {
|
||||||
|
public:
|
||||||
|
INLINE IDecompressStream();
|
||||||
|
INLINE IDecompressStream(istream *source, bool owns_source);
|
||||||
|
|
||||||
|
INLINE IDecompressStream &open(istream *source, bool owns_source);
|
||||||
|
INLINE IDecompressStream &close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ZStreamBuf _buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Class : OCompressStream
|
||||||
|
// Description : An input stream object that uses zlib to compress
|
||||||
|
// (deflate) data to another destination stream
|
||||||
|
// on-the-fly.
|
||||||
|
//
|
||||||
|
// Attach an OCompressStream to an existing ostream that will
|
||||||
|
// accept compressed data, and write your uncompressed
|
||||||
|
// source data to the OCompressStream.
|
||||||
|
//
|
||||||
|
// Seeking is not supported.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class EXPCL_PANDAEXPRESS OCompressStream : public ostream {
|
||||||
|
public:
|
||||||
|
INLINE OCompressStream();
|
||||||
|
INLINE OCompressStream(ostream *dest, bool owns_dest,
|
||||||
|
int compression_level = 6);
|
||||||
|
|
||||||
|
INLINE OCompressStream &open(ostream *dest, bool owns_dest,
|
||||||
|
int compression_level = 6);
|
||||||
|
INLINE OCompressStream &close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ZStreamBuf _buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "zStream.I"
|
||||||
|
|
||||||
|
#endif // HAVE_ZLIB
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
333
panda/src/express/zStreamBuf.cxx
Normal file
333
panda/src/express/zStreamBuf.cxx
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
// Filename: zStreamBuf.cxx
|
||||||
|
// Created by: drose (05Aug02)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the Panda 3d
|
||||||
|
// Software license. You should have received a copy of this license
|
||||||
|
// along with this source code; you will also find a current copy of
|
||||||
|
// the license at http://www.panda3d.org/license.txt .
|
||||||
|
//
|
||||||
|
// To contact the maintainers of this program write to
|
||||||
|
// panda3d@yahoogroups.com .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "zStreamBuf.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_ZLIB
|
||||||
|
|
||||||
|
#ifndef HAVE_STREAMSIZE
|
||||||
|
// Some compilers (notably SGI) don't define this for us
|
||||||
|
typedef int streamsize;
|
||||||
|
#endif /* HAVE_STREAMSIZE */
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
ZStreamBuf::
|
||||||
|
ZStreamBuf() {
|
||||||
|
_source = (istream *)NULL;
|
||||||
|
_owns_source = false;
|
||||||
|
_dest = (ostream *)NULL;
|
||||||
|
_owns_dest = false;
|
||||||
|
|
||||||
|
#ifdef WIN32_VC
|
||||||
|
// In spite of the claims of the MSDN Library to the contrary,
|
||||||
|
// Windows doesn't seem to provide an allocate() function, so we'll
|
||||||
|
// do it by hand.
|
||||||
|
char *buf = new char[4096];
|
||||||
|
char *ebuf = buf + 4096;
|
||||||
|
setg(buf, ebuf, ebuf);
|
||||||
|
setp(buf, ebuf, ebuf);
|
||||||
|
|
||||||
|
#else
|
||||||
|
allocate();
|
||||||
|
setg(base(), ebuf(), ebuf());
|
||||||
|
setp(base(), ebuf());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::Destructor
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
ZStreamBuf::
|
||||||
|
~ZStreamBuf() {
|
||||||
|
close_read();
|
||||||
|
close_write();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::open_read
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void ZStreamBuf::
|
||||||
|
open_read(istream *source, bool owns_source) {
|
||||||
|
_source = source;
|
||||||
|
_owns_source = owns_source;
|
||||||
|
|
||||||
|
_z_source.next_in = Z_NULL;
|
||||||
|
_z_source.avail_in = 0;
|
||||||
|
_z_source.zalloc = Z_NULL;
|
||||||
|
_z_source.zfree = Z_NULL;
|
||||||
|
_z_source.opaque = Z_NULL;
|
||||||
|
|
||||||
|
int result = inflateInit(&_z_source);
|
||||||
|
if (result < 0) {
|
||||||
|
express_cat.warning()
|
||||||
|
<< "zlib error " << result << " = " << _z_source.msg << "\n";
|
||||||
|
close_read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::close_read
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void ZStreamBuf::
|
||||||
|
close_read() {
|
||||||
|
if (_source != (istream *)NULL) {
|
||||||
|
|
||||||
|
int result = inflateEnd(&_z_source);
|
||||||
|
if (result < 0) {
|
||||||
|
express_cat.warning()
|
||||||
|
<< "zlib error " << result << " = " << _z_source.msg << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_owns_source) {
|
||||||
|
delete _source;
|
||||||
|
_owns_source = false;
|
||||||
|
}
|
||||||
|
_source = (istream *)NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::open_write
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void ZStreamBuf::
|
||||||
|
open_write(ostream *dest, bool owns_dest, int compression_level) {
|
||||||
|
_dest = dest;
|
||||||
|
_owns_dest = owns_dest;
|
||||||
|
|
||||||
|
_z_dest.zalloc = Z_NULL;
|
||||||
|
_z_dest.zfree = Z_NULL;
|
||||||
|
_z_dest.opaque = Z_NULL;
|
||||||
|
|
||||||
|
int result = deflateInit(&_z_dest, compression_level);
|
||||||
|
if (result < 0) {
|
||||||
|
express_cat.warning()
|
||||||
|
<< "zlib error " << result << " = " << _z_dest.msg << "\n";
|
||||||
|
close_write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::close_write
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void ZStreamBuf::
|
||||||
|
close_write() {
|
||||||
|
if (_dest != (ostream *)NULL) {
|
||||||
|
size_t n = pptr() - pbase();
|
||||||
|
write_chars(pbase(), n, Z_FINISH);
|
||||||
|
pbump(-(int)n);
|
||||||
|
|
||||||
|
int result = deflateEnd(&_z_dest);
|
||||||
|
if (result < 0) {
|
||||||
|
express_cat.warning()
|
||||||
|
<< "zlib error " << result << " = " << _z_dest.msg << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_owns_dest) {
|
||||||
|
delete _dest;
|
||||||
|
_owns_dest = false;
|
||||||
|
}
|
||||||
|
_dest = (ostream *)NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::overflow
|
||||||
|
// Access: Protected, Virtual
|
||||||
|
// Description: Called by the system ostream implementation when its
|
||||||
|
// internal buffer is filled, plus one character.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int ZStreamBuf::
|
||||||
|
overflow(int ch) {
|
||||||
|
size_t n = pptr() - pbase();
|
||||||
|
if (n != 0) {
|
||||||
|
write_chars(pbase(), n, 0);
|
||||||
|
pbump(-(int)n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch != EOF) {
|
||||||
|
// Write one more character.
|
||||||
|
char c = ch;
|
||||||
|
write_chars(&c, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::sync
|
||||||
|
// Access: Protected, Virtual
|
||||||
|
// Description: Called by the system iostream implementation to
|
||||||
|
// implement a flush operation.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int ZStreamBuf::
|
||||||
|
sync() {
|
||||||
|
if (_source != (istream *)NULL) {
|
||||||
|
size_t n = egptr() - gptr();
|
||||||
|
gbump(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dest != (ostream *)NULL) {
|
||||||
|
size_t n = pptr() - pbase();
|
||||||
|
write_chars(pbase(), n, Z_SYNC_FLUSH);
|
||||||
|
pbump(-(int)n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::underflow
|
||||||
|
// Access: Protected, Virtual
|
||||||
|
// Description: Called by the system istream implementation when its
|
||||||
|
// internal buffer needs more characters.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int ZStreamBuf::
|
||||||
|
underflow() {
|
||||||
|
// Sometimes underflow() is called even if the buffer is not empty.
|
||||||
|
if (gptr() >= egptr()) {
|
||||||
|
size_t buffer_size = egptr() - eback();
|
||||||
|
gbump(-(int)buffer_size);
|
||||||
|
|
||||||
|
size_t num_bytes = buffer_size;
|
||||||
|
size_t read_count = read_chars(gptr(), buffer_size);
|
||||||
|
|
||||||
|
if (read_count != num_bytes) {
|
||||||
|
// Oops, we didn't read what we thought we would.
|
||||||
|
if (read_count == 0) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slide what we did read to the top of the buffer.
|
||||||
|
nassertr(read_count < num_bytes, EOF);
|
||||||
|
size_t delta = num_bytes - read_count;
|
||||||
|
memmove(gptr() + delta, gptr(), read_count);
|
||||||
|
gbump(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (unsigned char)*gptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::read_chars
|
||||||
|
// Access: Private
|
||||||
|
// Description: Gets some characters from the source stream.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
size_t ZStreamBuf::
|
||||||
|
read_chars(char *start, size_t length) {
|
||||||
|
static const size_t decompress_buffer_size = 4096;
|
||||||
|
char decompress_buffer[decompress_buffer_size];
|
||||||
|
|
||||||
|
_z_source.next_out = (Bytef *)start;
|
||||||
|
_z_source.avail_out = length;
|
||||||
|
|
||||||
|
int flush = (_source->eof() || _source->fail()) ? Z_FINISH : 0;
|
||||||
|
|
||||||
|
while (_z_source.avail_out > 0) {
|
||||||
|
if (_z_source.avail_in == 0 && flush == 0) {
|
||||||
|
_source->read(decompress_buffer, decompress_buffer_size);
|
||||||
|
size_t read_count = _source->gcount();
|
||||||
|
if (read_count == 0 || _source->eof() || _source->fail()) {
|
||||||
|
// End of input; tell zlib to expect to stop.
|
||||||
|
flush = Z_FINISH;
|
||||||
|
}
|
||||||
|
|
||||||
|
_z_source.next_in = (Bytef *)decompress_buffer;
|
||||||
|
_z_source.avail_in = read_count;
|
||||||
|
}
|
||||||
|
int result = inflate(&_z_source, flush);
|
||||||
|
size_t bytes_read = length - _z_source.avail_out;
|
||||||
|
|
||||||
|
if (result == Z_STREAM_END) {
|
||||||
|
// Here's the end of the file.
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
if (result < 0) {
|
||||||
|
express_cat.warning()
|
||||||
|
<< "zlib error " << result << " = " << _z_source.msg << "\n";
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: ZStreamBuf::write_chars
|
||||||
|
// Access: Private
|
||||||
|
// Description: Sends some characters to the dest stream. The flush
|
||||||
|
// parameter is passed to deflate().
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void ZStreamBuf::
|
||||||
|
write_chars(const char *start, size_t length, int flush) {
|
||||||
|
static const size_t compress_buffer_size = 4096;
|
||||||
|
char compress_buffer[compress_buffer_size];
|
||||||
|
|
||||||
|
_z_dest.next_in = (Bytef *)(char *)start;
|
||||||
|
_z_dest.avail_in = length;
|
||||||
|
|
||||||
|
_z_dest.next_out = (Bytef *)compress_buffer;
|
||||||
|
_z_dest.avail_out = compress_buffer_size;
|
||||||
|
|
||||||
|
int result = deflate(&_z_dest, flush);
|
||||||
|
if (result < 0 && result != Z_BUF_ERROR) {
|
||||||
|
express_cat.warning()
|
||||||
|
<< "zlib error " << result << " = " << _z_dest.msg << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
while (_z_dest.avail_in != 0) {
|
||||||
|
if (_z_dest.avail_out != compress_buffer_size) {
|
||||||
|
_dest->write(compress_buffer, compress_buffer_size - _z_dest.avail_out);
|
||||||
|
_z_dest.next_out = (Bytef *)compress_buffer;
|
||||||
|
_z_dest.avail_out = compress_buffer_size;
|
||||||
|
}
|
||||||
|
result = deflate(&_z_dest, flush);
|
||||||
|
if (result < 0) {
|
||||||
|
express_cat.warning()
|
||||||
|
<< "zlib error " << result << " = " << _z_dest.msg << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (_z_dest.avail_out != compress_buffer_size) {
|
||||||
|
_dest->write(compress_buffer, compress_buffer_size - _z_dest.avail_out);
|
||||||
|
_z_dest.next_out = (Bytef *)compress_buffer;
|
||||||
|
_z_dest.avail_out = compress_buffer_size;
|
||||||
|
result = deflate(&_z_dest, flush);
|
||||||
|
if (result < 0 && result != Z_BUF_ERROR) {
|
||||||
|
express_cat.warning()
|
||||||
|
<< "zlib error " << result << " = " << _z_dest.msg << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HAVE_ZLIB
|
67
panda/src/express/zStreamBuf.h
Normal file
67
panda/src/express/zStreamBuf.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Filename: zStreamBuf.h
|
||||||
|
// Created by: drose (05Aug02)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the Panda 3d
|
||||||
|
// Software license. You should have received a copy of this license
|
||||||
|
// along with this source code; you will also find a current copy of
|
||||||
|
// the license at http://www.panda3d.org/license.txt .
|
||||||
|
//
|
||||||
|
// To contact the maintainers of this program write to
|
||||||
|
// panda3d@yahoogroups.com .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef ZSTREAMBUF_H
|
||||||
|
#define ZSTREAMBUF_H
|
||||||
|
|
||||||
|
#include "pandabase.h"
|
||||||
|
|
||||||
|
// This module is not compiled if zlib is not available.
|
||||||
|
#ifdef HAVE_ZLIB
|
||||||
|
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Class : ZStreamBuf
|
||||||
|
// Description : The streambuf object that implements
|
||||||
|
// IDecompressStream and OCompressStream.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class EXPCL_PANDAEXPRESS ZStreamBuf : public streambuf {
|
||||||
|
public:
|
||||||
|
ZStreamBuf();
|
||||||
|
virtual ~ZStreamBuf();
|
||||||
|
|
||||||
|
void open_read(istream *source, bool owns_source);
|
||||||
|
void close_read();
|
||||||
|
|
||||||
|
void open_write(ostream *dest, bool owns_dest, int compression_level);
|
||||||
|
void close_write();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int overflow(int c);
|
||||||
|
virtual int sync(void);
|
||||||
|
virtual int underflow(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t read_chars(char *start, size_t length);
|
||||||
|
void write_chars(const char *start, size_t length, int flush);
|
||||||
|
|
||||||
|
private:
|
||||||
|
istream *_source;
|
||||||
|
bool _owns_source;
|
||||||
|
|
||||||
|
ostream *_dest;
|
||||||
|
bool _owns_dest;
|
||||||
|
|
||||||
|
z_stream _z_source;
|
||||||
|
z_stream _z_dest;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HAVE_ZLIB
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user