multify -P

This commit is contained in:
David Rose 2009-09-04 21:38:43 +00:00
parent e7b00c6e92
commit d807610d32
4 changed files with 96 additions and 46 deletions

View File

@ -31,9 +31,9 @@ bool append = false; // -r
bool update = false; // -u bool update = false; // -u
bool tlist = false; // -t bool tlist = false; // -t
bool extract = false; // -x bool extract = false; // -x
bool kill_cmd = false; // -k bool kill_cmd = false; // -k
bool verbose = false; // -v bool verbose = false; // -v
bool compress_flag = false; // -z bool compress_flag = false; // -z
int default_compression_level = 6; int default_compression_level = 6;
Filename multifile_name; // -f Filename multifile_name; // -f
bool got_multifile_name = false; bool got_multifile_name = false;
@ -41,13 +41,15 @@ bool to_stdout = false; // -O
bool encryption_flag = false; // -e bool encryption_flag = false; // -e
string password; // -p string password; // -p
bool got_password = false; bool got_password = false;
string header_prefix; // -P
bool got_header_prefix = false;
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 pset<string> dont_compress; // -Z
// Default extensions not to compress. May be overridden with -Z. // Default extensions not to compress. May be overridden with -Z.
string dont_compress_str = "jpg,mp3"; string dont_compress_str = "jpg,png,mp3,ogg";
bool got_record_timestamp_flag = false; bool got_record_timestamp_flag = false;
bool record_timestamp_flag = true; bool record_timestamp_flag = true;
@ -178,6 +180,15 @@ help() {
" specified, and passwords are required, the user will be prompted from\n" " specified, and passwords are required, the user will be prompted from\n"
" standard input.\n\n" " standard input.\n\n"
" -P \"prefix\"\n"
" Specifies a header_prefix to write to the beginning of the multifile.\n"
" This is primarily useful for creating a multifile that can be invoked\n"
" directly as a program from the shell on Unix-like environments,\n"
" for instance, p3d files. The header_prefix must begin with a hash\n"
" mark and end with a newline; this will be enforced if it is not\n"
" already so. This only has effect in conjunction with with -c, -u,\n"
" or -k.\n\n"
" -F <scale_factor>\n" " -F <scale_factor>\n"
" Specify a Multifile scale factor. This is only necessary to support\n" " Specify a Multifile scale factor. This is only necessary to support\n"
" Multifiles that will exceed 4GB in size. The default scale factor is\n" " Multifiles that will exceed 4GB in size. The default scale factor is\n"
@ -330,6 +341,10 @@ add_files(int argc, char *argv[]) {
multifile->set_encryption_password(get_password()); multifile->set_encryption_password(get_password());
} }
if (got_header_prefix) {
multifile->set_header_prefix(header_prefix);
}
if (scale_factor != 0 && scale_factor != multifile->get_scale_factor()) { if (scale_factor != 0 && scale_factor != multifile->get_scale_factor()) {
cerr << "Setting scale factor to " << scale_factor << "\n"; cerr << "Setting scale factor to " << scale_factor << "\n";
multifile->set_scale_factor(scale_factor); multifile->set_scale_factor(scale_factor);
@ -451,6 +466,10 @@ kill_files(int argc, char *argv[]) {
return false; return false;
} }
if (got_header_prefix) {
multifile->set_header_prefix(header_prefix);
}
int i = 0; int i = 0;
while (i < multifile->get_num_subfiles()) { while (i < multifile->get_num_subfiles()) {
string subfile_name = multifile->get_subfile_name(i); string subfile_name = multifile->get_subfile_name(i);
@ -628,7 +647,7 @@ main(int argc, char *argv[]) {
extern char *optarg; extern char *optarg;
extern int optind; extern int optind;
static const char *optflags = "crutxkvz123456789Z:T:f:OC:ep:F:h"; static const char *optflags = "crutxkvz123456789Z:T:f:OC:ep:P: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) {
@ -727,6 +746,10 @@ main(int argc, char *argv[]) {
password = optarg; password = optarg;
got_password = true; got_password = true;
break; break;
case 'P':
header_prefix = optarg;
got_header_prefix = true;
break;
case 'F': case 'F':
{ {
char *endptr; char *endptr;

View File

@ -377,25 +377,6 @@ get_magic_number() {
return string(_header, _header_size); return string(_header, _header_size);
} }
////////////////////////////////////////////////////////////////////
// Function: Multifile::set_header_prefix
// Access: Published
// Description: Sets the string which is written to the Multifile
// before the Multifile header. This string must begin
// with a hash mark and end with a newline character,
// and include at least 6 characters; and if it includes
// embedded newline characters, each one must be
// followed by a hash mark.
//
// This is primarily useful as a simple hack to allow
// p3d applications to be run directly from the command
// line on Unix-like systems.
////////////////////////////////////////////////////////////////////
INLINE void Multifile::
set_header_prefix(const string &header_prefix) {
_header_prefix = header_prefix;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Multifile::get_header_prefix // Function: Multifile::get_header_prefix
// Access: Published // Access: Published

View File

@ -691,7 +691,7 @@ flush() {
// Also update the overall timestamp. // Also update the overall timestamp.
if (_timestamp_dirty) { if (_timestamp_dirty) {
nassertr(!_write->fail(), false); nassertr(!_write->fail(), false);
static const size_t timestamp_pos = _header_size + 2 + 2 + 4; static const size_t timestamp_pos = _header_prefix.size() + _header_size + 2 + 2 + 4;
_write->seekp(timestamp_pos); _write->seekp(timestamp_pos);
nassertr(!_write->fail(), false); nassertr(!_write->fail(), false);
@ -1336,6 +1336,56 @@ ls(ostream &out) const {
} }
} }
////////////////////////////////////////////////////////////////////
// Function: Multifile::set_header_prefix
// Access: Published
// Description: Sets the string which is written to the Multifile
// before the Multifile header. This string must begin
// with a hash mark and end with a newline character;
// and if it includes embedded newline characters, each
// one must be followed by a hash mark. If these
// conditions are not initially true, the string will be
// modified as necessary to make it so.
//
// This is primarily useful as a simple hack to allow
// p3d applications to be run directly from the command
// line on Unix-like systems.
//
// The return value is true if successful, or false on
// failure (for instance, because the header prefix
// violates the above rules).
////////////////////////////////////////////////////////////////////
void Multifile::
set_header_prefix(const string &header_prefix) {
string new_header_prefix = header_prefix;
if (!new_header_prefix.empty()) {
// It must begin with a hash mark.
if (new_header_prefix[0] != '#') {
new_header_prefix = string("#") + new_header_prefix;
}
// It must end with a newline.
if (new_header_prefix[new_header_prefix.size() - 1] != '\n') {
new_header_prefix += string("\n");
}
// Embedded newlines must be followed by a hash mark.
size_t newline = new_header_prefix.find('\n');
while (newline < new_header_prefix.size() - 1) {
if (new_header_prefix[newline + 1] != '#') {
new_header_prefix = new_header_prefix.substr(0, newline + 1) + string("#") + new_header_prefix.substr(newline + 1);
}
newline = new_header_prefix.find('#', newline);
}
}
if (_header_prefix != new_header_prefix) {
_header_prefix = new_header_prefix;
_needs_repack = true;
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Multifile::read_subfile // Function: Multifile::read_subfile
@ -1535,28 +1585,17 @@ read_index() {
char this_header[_header_size]; char this_header[_header_size];
read->seekg(0); read->seekg(0);
read->read(this_header, _header_size);
if (read->fail() || read->gcount() != (unsigned)_header_size) {
express_cat.info()
<< "Unable to read Multifile header " << _multifile_name << ".\n";
_read->release();
close();
return false;
}
// Here's a special case: if the multifile begins with a hash // Here's a special case: if the multifile begins with a hash
// character, then we skip at least 6 characters (the length of the // character, then we continue reading and discarding lines of ASCII
// original header string we already read), and continue reading and // text, until we come across a nonempty line that does not begin
// discarding lines of ASCII text, until we come across a nonempty // with a hash character. This allows a P3D application (which is a
// line that does not begin with a hash character. This allows a // multifile) to be run directly on the command line on Unix-based
// P3D application (which is a multifile) to be run directly on the // systems.
// command line on Unix-based systems.
_header_prefix = string(); _header_prefix = string();
int ch = read->get();
if (this_header[0] == '#') { if (ch == '#') {
_header_prefix = string(this_header, _header_size);
int ch = '#';
while (ch != EOF && ch == '#') { while (ch != EOF && ch == '#') {
// Skip to the end of the line. // Skip to the end of the line.
while (ch != EOF && ch != '\n') { while (ch != EOF && ch != '\n') {
@ -1569,10 +1608,17 @@ read_index() {
ch = read->get(); ch = read->get();
} }
} }
}
// Now fill up the header. // Now read the actual Multifile header.
this_header[0] = ch; this_header[0] = ch;
read->read(this_header + 1, _header_size - 1); read->read(this_header + 1, _header_size - 1);
if (read->fail() || read->gcount() != (unsigned)(_header_size - 1)) {
express_cat.info()
<< "Unable to read Multifile header " << _multifile_name << ".\n";
_read->release();
close();
return false;
} }
if (memcmp(this_header, _header, _header_size) != 0) { if (memcmp(this_header, _header, _header_size) != 0) {

View File

@ -114,7 +114,7 @@ PUBLISHED:
static INLINE string get_magic_number(); static INLINE string get_magic_number();
INLINE void set_header_prefix(const string &header_prefix); void set_header_prefix(const string &header_prefix);
INLINE const string &get_header_prefix() const; INLINE const string &get_header_prefix() const;
public: public: