mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
define update_subfile
This commit is contained in:
parent
f474d2a336
commit
fbdc3e52c7
@ -30,6 +30,7 @@
|
||||
|
||||
bool create = false; // -c
|
||||
bool append = false; // -r
|
||||
bool update = false; // -u
|
||||
bool list = false; // -t
|
||||
bool extract = false; // -x
|
||||
bool verbose = false; // -v
|
||||
@ -49,7 +50,7 @@ string dont_compress_str = "jpg,mp3";
|
||||
void
|
||||
usage() {
|
||||
cerr <<
|
||||
"Usage: multify -[c|r|t|x] -f <multifile_name> [options] <subfile_name> ...\n";
|
||||
"Usage: multify -[c|r|u|t|x] -f <multifile_name> [options] <subfile_name> ...\n";
|
||||
}
|
||||
|
||||
void
|
||||
@ -82,6 +83,12 @@ help() {
|
||||
" the Multifile with the same name. The Multifile will be repacked\n"
|
||||
" after completion, even if no Subfiles were added.\n\n"
|
||||
|
||||
" -u\n"
|
||||
" Update an existing Multifile archive. This is similar to -r, except\n"
|
||||
" that files are compared byte-for-byte with their corresponding files\n"
|
||||
" in the archive first. If they have not changed, the multifile is not\n"
|
||||
" modified (other than to repack it if necessary).\n\n"
|
||||
|
||||
" -t\n"
|
||||
" List the contents of an existing Multifile. With -v, this shows\n"
|
||||
" the size of each Subfile and its compression ratio, if compressed.\n\n"
|
||||
@ -127,7 +134,6 @@ help() {
|
||||
|
||||
" -O\n"
|
||||
" With -x, extract subfiles to standard output instead of to disk.\n\n"
|
||||
|
||||
" -Z <extension_list>\n"
|
||||
" Specify a comma-separated list of filename extensions that represent\n"
|
||||
" files that are not to be compressed. The default if this is omitted is\n"
|
||||
@ -191,16 +197,23 @@ add_directory(Multifile &multifile, const Filename &directory_name) {
|
||||
for (fi = files.begin(); fi != files.end(); ++fi) {
|
||||
Filename subfile_name(directory_name, (*fi));
|
||||
if (subfile_name.is_directory()) {
|
||||
okflag = add_directory(multifile, subfile_name);
|
||||
if (!add_directory(multifile, subfile_name)) {
|
||||
okflag = false;
|
||||
}
|
||||
|
||||
} else if (!subfile_name.exists()) {
|
||||
cerr << "Not found: " << subfile_name << "\n";
|
||||
okflag = false;
|
||||
|
||||
} else {
|
||||
string new_subfile_name =
|
||||
multifile.add_subfile(subfile_name, subfile_name,
|
||||
get_compression_level(subfile_name));
|
||||
string new_subfile_name;
|
||||
if (update) {
|
||||
new_subfile_name = multifile.update_subfile
|
||||
(subfile_name, subfile_name, get_compression_level(subfile_name));
|
||||
} else {
|
||||
new_subfile_name = multifile.add_subfile
|
||||
(subfile_name, subfile_name, get_compression_level(subfile_name));
|
||||
}
|
||||
if (new_subfile_name.empty()) {
|
||||
cerr << "Unable to add " << subfile_name << ".\n";
|
||||
okflag = false;
|
||||
@ -218,7 +231,7 @@ add_directory(Multifile &multifile, const Filename &directory_name) {
|
||||
bool
|
||||
add_files(int argc, char *argv[]) {
|
||||
Multifile multifile;
|
||||
if (append) {
|
||||
if (append || update) {
|
||||
if (!multifile.open_read_write(multifile_name)) {
|
||||
cerr << "Unable to open " << multifile_name << " for updating.\n";
|
||||
return false;
|
||||
@ -248,9 +261,14 @@ add_files(int argc, char *argv[]) {
|
||||
okflag = false;
|
||||
|
||||
} else {
|
||||
string new_subfile_name =
|
||||
multifile.add_subfile(subfile_name, subfile_name,
|
||||
get_compression_level(subfile_name));
|
||||
string new_subfile_name;
|
||||
if (update) {
|
||||
new_subfile_name = multifile.update_subfile
|
||||
(subfile_name, subfile_name, get_compression_level(subfile_name));
|
||||
} else {
|
||||
new_subfile_name = multifile.add_subfile
|
||||
(subfile_name, subfile_name, get_compression_level(subfile_name));
|
||||
}
|
||||
if (new_subfile_name.empty()) {
|
||||
cerr << "Unable to add " << subfile_name << ".\n";
|
||||
okflag = false;
|
||||
@ -406,7 +424,7 @@ main(int argc, char *argv[]) {
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
static const char *optflags = "crtxvz123456789Z:f:OC:F:h";
|
||||
static const char *optflags = "crutxvz123456789Z:f:OC:F:h";
|
||||
int flag = getopt(argc, argv, optflags);
|
||||
Filename rel_path;
|
||||
while (flag != EOF) {
|
||||
@ -417,6 +435,9 @@ main(int argc, char *argv[]) {
|
||||
case 'r':
|
||||
append = true;
|
||||
break;
|
||||
case 'u':
|
||||
update = true;
|
||||
break;
|
||||
case 't':
|
||||
list = true;
|
||||
break;
|
||||
@ -512,8 +533,8 @@ main(int argc, char *argv[]) {
|
||||
argv += (optind - 1);
|
||||
|
||||
// We should have exactly one of these options.
|
||||
if ((create?1:0) + (append?1:0) + (list?1:0) + (extract?1:0) != 1) {
|
||||
cerr << "Exactly one of -c, -r, -t, -x must be specified.\n";
|
||||
if ((create?1:0) + (append?1:0) + (update?1:0) + (list?1:0) + (extract?1:0) != 1) {
|
||||
cerr << "Exactly one of -c, -r, -u, -t, -x must be specified.\n";
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
@ -528,7 +549,7 @@ main(int argc, char *argv[]) {
|
||||
tokenize_extensions(dont_compress_str, dont_compress);
|
||||
|
||||
bool okflag = true;
|
||||
if (create || append) {
|
||||
if (create || append || update) {
|
||||
okflag = add_files(argc, argv);
|
||||
} else if (extract) {
|
||||
okflag = extract_files(argc, argv);
|
||||
|
@ -294,7 +294,10 @@ set_scale_factor(size_t scale_factor) {
|
||||
// Access: Published
|
||||
// Description: Adds a file on disk as a subfile to the Multifile.
|
||||
// The file named by filename will be read and added to
|
||||
// the Multifile at the next call to flush().
|
||||
// the Multifile at the next call to flush(). If there
|
||||
// already exists a subfile with the indicated name, it
|
||||
// is replaced without examining its contents (but see
|
||||
// also update_subfile).
|
||||
//
|
||||
// Returns the subfile name on success (it might have
|
||||
// been modified slightly), or empty string on failure.
|
||||
@ -307,11 +310,58 @@ add_subfile(const string &subfile_name, const Filename &filename,
|
||||
if (!filename.exists()) {
|
||||
return string();
|
||||
}
|
||||
Subfile *subfile = new Subfile;
|
||||
subfile->_source_filename = filename;
|
||||
subfile->_source_filename.set_binary();
|
||||
string name = standardize_subfile_name(subfile_name);
|
||||
if (!name.empty()) {
|
||||
Subfile *subfile = new Subfile;
|
||||
subfile->_name = name;
|
||||
subfile->_source_filename = filename;
|
||||
subfile->_source_filename.set_binary();
|
||||
|
||||
return add_new_subfile(subfile_name, subfile, compression_level);
|
||||
add_new_subfile(subfile, compression_level);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::update_subfile
|
||||
// Access: Published
|
||||
// Description: Adds a file on disk to the subfile. If a subfile
|
||||
// already exists with the same name, its contents are
|
||||
// compared to the disk file, and it is replaced only if
|
||||
// it is different; otherwise, the multifile is left
|
||||
// unchanged.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string Multifile::
|
||||
update_subfile(const string &subfile_name, const Filename &filename,
|
||||
int compression_level) {
|
||||
nassertr(is_write_valid(), string());
|
||||
|
||||
if (!filename.exists()) {
|
||||
return string();
|
||||
}
|
||||
string name = standardize_subfile_name(subfile_name);
|
||||
if (!name.empty()) {
|
||||
int index = find_subfile(name);
|
||||
if (index >= 0) {
|
||||
// The subfile already exists; compare it to the source file.
|
||||
if (compare_subfile(index, filename)) {
|
||||
// The files are identical; do nothing.
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// The subfile does not already exist or it is different from the
|
||||
// source file. Add the new source file.
|
||||
Subfile *subfile = new Subfile;
|
||||
subfile->_name = name;
|
||||
subfile->_source_filename = filename;
|
||||
subfile->_source_filename.set_binary();
|
||||
|
||||
add_new_subfile(subfile, compression_level);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -545,7 +595,7 @@ get_num_subfiles() const {
|
||||
int Multifile::
|
||||
find_subfile(const string &subfile_name) const {
|
||||
Subfile find_subfile;
|
||||
find_subfile._name = subfile_name;
|
||||
find_subfile._name = standardize_subfile_name(subfile_name);
|
||||
Subfiles::const_iterator fi;
|
||||
fi = _subfiles.find(&find_subfile);
|
||||
if (fi == _subfiles.end()) {
|
||||
@ -590,7 +640,7 @@ has_directory(const string &subfile_name) const {
|
||||
// Access: Published
|
||||
// Description: Considers subfile_name to be the name of a
|
||||
// subdirectory within the Multifile, but not a file
|
||||
// itself; ills the given vector up with the sorted list
|
||||
// itself; fills the given vector up with the sorted list
|
||||
// of subdirectories or files within the named
|
||||
// directory.
|
||||
//
|
||||
@ -808,6 +858,57 @@ extract_subfile(int index, const Filename &filename) {
|
||||
return extract_subfile_to(index, out);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::compare_subfile
|
||||
// Access: Published
|
||||
// Description: Performs a byte-for-byte comparison of the indicated
|
||||
// file on disk with the nth subfile. Returns true if
|
||||
// the files are equivalent, or false if they are
|
||||
// different (or the file is missing).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool Multifile::
|
||||
compare_subfile(int index, const Filename &filename) {
|
||||
nassertr(is_read_valid(), false);
|
||||
nassertr(index >= 0 && index < (int)_subfiles.size(), false);
|
||||
|
||||
if (!filename.exists()) {
|
||||
express_cat.info()
|
||||
<< "File is missing: " << filename << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
istream *in1 = open_read_subfile(index);
|
||||
if (in1 == (istream *)NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ifstream in2;
|
||||
Filename bin_filename = Filename::binary_filename(filename);
|
||||
if (!bin_filename.open_read(in2)) {
|
||||
express_cat.info()
|
||||
<< "Cannot read " << filename << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
int byte1 = in1->get();
|
||||
int byte2 = in2.get();
|
||||
while (!in1->fail() && !in1->eof() &&
|
||||
!in2.fail() && !in2.eof()) {
|
||||
if (byte1 != byte2) {
|
||||
delete in1;
|
||||
return false;
|
||||
}
|
||||
byte1 = in1->get();
|
||||
byte2 = in2.get();
|
||||
}
|
||||
|
||||
bool failed = (in1->fail() && !in1->eof()) || (in2.fail() && !in2.eof());
|
||||
delete in1;
|
||||
|
||||
nassertr(!failed, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::output
|
||||
// Access: Published
|
||||
@ -928,7 +1029,7 @@ open_read_write(iostream *multifile_stream) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::add_subfile
|
||||
// Access: Public
|
||||
// Description: Adds a file on disk as a subfile to the Multifile.
|
||||
// Description: Adds a file from a stream as a subfile to the Multifile.
|
||||
// The indicated istream will be read and its contents
|
||||
// added to the Multifile at the next call to flush().
|
||||
//
|
||||
@ -940,10 +1041,15 @@ add_subfile(const string &subfile_name, istream *subfile_data,
|
||||
int compression_level) {
|
||||
nassertr(is_write_valid(), string());
|
||||
|
||||
Subfile *subfile = new Subfile;
|
||||
subfile->_source = subfile_data;
|
||||
string name = standardize_subfile_name(subfile_name);
|
||||
if (!name.empty()) {
|
||||
Subfile *subfile = new Subfile;
|
||||
subfile->_name = name;
|
||||
subfile->_source = subfile_data;
|
||||
add_new_subfile(subfile, compression_level);
|
||||
}
|
||||
|
||||
return add_new_subfile(subfile_name, subfile, compression_level);
|
||||
return name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -1001,9 +1107,8 @@ pad_to_streampos(streampos fpos) {
|
||||
// Description: Adds a newly-allocated Subfile pointer to the
|
||||
// Multifile.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string Multifile::
|
||||
add_new_subfile(const string &subfile_name, Subfile *subfile,
|
||||
int compression_level) {
|
||||
void Multifile::
|
||||
add_new_subfile(Subfile *subfile, int compression_level) {
|
||||
if (compression_level != 0) {
|
||||
#ifndef HAVE_ZLIB
|
||||
express_cat.warning()
|
||||
@ -1021,20 +1126,6 @@ add_new_subfile(const string &subfile_name, Subfile *subfile,
|
||||
_needs_repack = true;
|
||||
}
|
||||
|
||||
// Normalize the Subfile name: eliminate ./, leading slash, etc.
|
||||
Filename name = subfile_name;
|
||||
name.standardize();
|
||||
if (name.empty() || name == "/") {
|
||||
// Invalid empty name.
|
||||
return string();
|
||||
}
|
||||
|
||||
if (name[0] == '/') {
|
||||
subfile->_name = name.get_fullpath().substr(1);
|
||||
} else {
|
||||
subfile->_name = name;
|
||||
}
|
||||
|
||||
pair<Subfiles::iterator, bool> insert_result = _subfiles.insert(subfile);
|
||||
if (!insert_result.second) {
|
||||
// Hmm, unable to insert. There must already be a subfile by that
|
||||
@ -1046,7 +1137,27 @@ add_new_subfile(const string &subfile_name, Subfile *subfile,
|
||||
}
|
||||
|
||||
_new_subfiles.push_back(subfile);
|
||||
return subfile->_name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::standardize_subfile_name
|
||||
// Access: Private
|
||||
// Description: Returns the standard form of the subfile name.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string Multifile::
|
||||
standardize_subfile_name(const string &subfile_name) const {
|
||||
Filename name = subfile_name;
|
||||
name.standardize();
|
||||
if (name.empty() || name == "/") {
|
||||
// Invalid empty name.
|
||||
return string();
|
||||
}
|
||||
|
||||
if (name[0] == '/') {
|
||||
return name.get_fullpath().substr(1);
|
||||
} else {
|
||||
return name.get_fullpath();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -57,6 +57,8 @@ PUBLISHED:
|
||||
|
||||
string add_subfile(const string &subfile_name, const Filename &filename,
|
||||
int compression_level);
|
||||
string update_subfile(const string &subfile_name, const Filename &filename,
|
||||
int compression_level);
|
||||
bool flush();
|
||||
bool repack();
|
||||
|
||||
@ -74,6 +76,7 @@ PUBLISHED:
|
||||
INLINE string read_subfile(int index);
|
||||
istream *open_read_subfile(int index);
|
||||
bool extract_subfile(int index, const Filename &filename);
|
||||
bool compare_subfile(int index, const Filename &filename);
|
||||
|
||||
void output(ostream &out) const;
|
||||
void ls(ostream &out = cout) const;
|
||||
@ -129,8 +132,9 @@ private:
|
||||
INLINE streampos normalize_streampos(streampos fpos) const;
|
||||
streampos pad_to_streampos(streampos fpos);
|
||||
|
||||
string add_new_subfile(const string &subfile_name, Subfile *subfile,
|
||||
int compression_level);
|
||||
void add_new_subfile(Subfile *subfile, int compression_level);
|
||||
string standardize_subfile_name(const string &subfile_name) const;
|
||||
|
||||
void clear_subfiles();
|
||||
bool read_index();
|
||||
bool write_header();
|
||||
|
Loading…
x
Reference in New Issue
Block a user